diff options
29 files changed, 61 insertions, 518 deletions
@@ -1,4 +1 @@ -Machina NEWS file - -0.0.0: - * Um.. nothing +No news is good news. @@ -1,4 +1 @@ -A sequencer based on finite automata. - -This is in this repository right now for my convenience. -It is not intended to be used. +A MIDI sequencer based on probabilistic finite-state automata. diff --git a/src/engine/ActionFactory.cpp b/src/engine/ActionFactory.cpp index 4b63e92..2e87cbc 100644 --- a/src/engine/ActionFactory.cpp +++ b/src/engine/ActionFactory.cpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "machina/ActionFactory.hpp" diff --git a/src/engine/Engine.cpp b/src/engine/Engine.cpp index 69402a3..5af50b9 100644 --- a/src/engine/Engine.cpp +++ b/src/engine/Engine.cpp @@ -36,7 +36,6 @@ Engine::load_machine(const Glib::ustring& uri) if (m) { m->activate(); _driver->set_machine(m); - //_driver->machine()->nodes().append(m->nodes()); } // .. and drop it in this thread (to prevent deallocation in the RT thread) @@ -51,38 +50,32 @@ Engine::load_machine(const Glib::ustring& uri) SharedPtr<Machine> Engine::import_machine(const Glib::ustring& uri) { - SharedPtr<Machine> old_machine = _driver->machine(); // Hold a reference to current machine.. - SharedPtr<Machine> m = Loader().load(uri); if (m) { m->activate(); _driver->machine()->nodes().append(m->nodes()); } - // .. and drop it in this thread (to prevent deallocation in the RT thread) + // Discard m return _driver->machine(); } -/** Learn the SMF (MIDI) file at @a uri, and run the resulting machine - * (replacing current machine). +/** Learn the SMF (MIDI) file at @a uri, add it to the current machine. * Safe to call while engine is processing. */ SharedPtr<Machine> -Engine::learn_midi(const Glib::ustring& uri) +Engine::import_midi(const Glib::ustring& uri, Raul::BeatTime duration) { - SharedPtr<Machine> old_machine = _driver->machine(); // Hold a reference to current machine.. - SharedPtr<SMFDriver> file_driver(new SMFDriver()); - SharedPtr<Machine> m = file_driver->learn(uri, 32.0); // FIXME: hardcoded + SharedPtr<Machine> m = file_driver->learn(uri, duration); m->activate(); - //_driver->set_machine(m); _driver->machine()->nodes().append(m->nodes()); - // .. and drop it in this thread (to prevent deallocation in the RT thread) + // Discard m - return m; + return _driver->machine(); } diff --git a/src/engine/JackDriver.cpp b/src/engine/JackDriver.cpp index 25ff496..d2c131d 100644 --- a/src/engine/JackDriver.cpp +++ b/src/engine/JackDriver.cpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <iostream> @@ -118,6 +118,7 @@ JackDriver::process_input(SharedPtr<Machine> machine, const TimeSlice& time) using namespace std; if (_recording.get()) { + const jack_nframes_t nframes = time.length_ticks(); void* jack_buffer = jack_port_get_buffer(_input_port, nframes); const jack_nframes_t event_count = jack_midi_get_event_count(jack_buffer, nframes); @@ -133,6 +134,7 @@ JackDriver::process_input(SharedPtr<Machine> machine, const TimeSlice& time) _recorder->whip(); } else { + const jack_nframes_t nframes = time.length_ticks(); void* jack_buffer = jack_port_get_buffer(_input_port, nframes); const jack_nframes_t event_count = jack_midi_get_event_count(jack_buffer, nframes); @@ -146,10 +148,8 @@ JackDriver::process_input(SharedPtr<Machine> machine, const TimeSlice& time) const SharedPtr<LearnRequest> learn = machine->pending_learn(); if (learn) { learn->enter_action()->set_event(ev.size, ev.buffer); - cerr << "LEARN START\n"; learn->start(_quantization.get(), time.ticks_to_beats(jack_last_frame_time(_client) + ev.time)); - //LearnRecord learn = machine->pop_learn(); } } else if (ev.buffer[0] == 0x80) { @@ -162,14 +162,11 @@ JackDriver::process_input(SharedPtr<Machine> machine, const TimeSlice& time) learn->finish( time.ticks_to_beats(jack_last_frame_time(_client) + ev.time)); machine->clear_pending_learn(); - cerr << "LEARNED!\n"; } } } - - //std::cerr << "EVENT: " << std::hex << (int)ev.buffer[0] << "\n"; - } + } } @@ -179,9 +176,13 @@ JackDriver::write_event(Raul::BeatTime time, size_t size, const byte* event) throw (std::logic_error) { + if (!_output_port) + return; + if (_cycle_time.beats_to_ticks(time) + _cycle_time.offset_ticks() < _cycle_time.start_ticks()) { std::cerr << "ERROR: Missed event by " - << _cycle_time.start_ticks() - (_cycle_time.beats_to_ticks(time) + _cycle_time.offset_ticks()) + << _cycle_time.start_ticks() + - (_cycle_time.beats_to_ticks(time) + _cycle_time.offset_ticks()) << " ticks" << "\n\tbpm: " << _cycle_time.bpm() << "\n\tev time: " << _cycle_time.beats_to_ticks(time) @@ -195,8 +196,6 @@ JackDriver::write_event(Raul::BeatTime time, const TickCount offset = _cycle_time.beats_to_ticks(time) + _cycle_time.offset_ticks() - _cycle_time.start_ticks(); - assert(_output_port); - if ( ! (offset < _cycle_time.offset_ticks() + nframes)) { std::cerr << "ERROR: Event offset " << offset << " outside cycle " << "\n\tbpm: " << _cycle_time.bpm() @@ -297,7 +296,8 @@ JackDriver::on_process(jack_nframes_t nframes) void JackDriver::reset() { - // FIXME: Flag audio thread and end active notes, etc + /* FIXME: This should signal the audio thread and wait for it + * to exit all active states to resolve stuck notes, then reset. */ _machine->deactivate(); _machine->reset(); _cycle_time.set_start(0); @@ -307,9 +307,9 @@ JackDriver::reset() void JackDriver::start_record() { - std::cerr << "START RECORD" << std::endl; - // FIXME: hardcoded size - _recorder = SharedPtr<Recorder>(new Recorder(1024, (1.0/(double)sample_rate()) * (_bpm.get() / 60.0), _quantization.get())); + // FIXME: Choose an appropriate maximum ringbuffer size + _recorder = SharedPtr<Recorder>(new Recorder( + 1024, (1.0/(double)sample_rate()) * (_bpm.get() / 60.0), _quantization.get())); _recorder->start(); _record_time = 0; _recording = 1; @@ -321,10 +321,8 @@ JackDriver::finish_record() { _recording = 0; SharedPtr<Machine> machine = _recorder->finish(); - std::cout << "Learned machine! " << machine->nodes().size() << " nodes." << std::endl; _recorder.reset(); machine->activate(); - //set_machine(machine); _machine->nodes().append(machine->nodes()); } diff --git a/src/engine/LearnRequest.cpp b/src/engine/LearnRequest.cpp index 019f7a2..70420e2 100644 --- a/src/engine/LearnRequest.cpp +++ b/src/engine/LearnRequest.cpp @@ -31,9 +31,6 @@ LearnRequest::finish(BeatTime time) double duration = Raul::Quantizer::quantize(_quantization, time - _start_time); _node->set_duration(duration); - using namespace std; - cerr << "Q=" << _quantization << ", T=" << time << ", ST=" << _start_time << endl; - std::cerr << "LEARN DURATION: " << duration << std::endl; } diff --git a/src/engine/Loader.cpp b/src/engine/Loader.cpp index 57905ba..f9145c9 100644 --- a/src/engine/Loader.cpp +++ b/src/engine/Loader.cpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <iostream> @@ -77,8 +77,6 @@ Loader::load(const Glib::ustring& uri) const Glib::ustring machine_uri = "<>"; - cout << "USER URI: " << uri << endl; - cout << "[Loader] Loading " << machine_uri << " from " << document_uri << endl; machine = SharedPtr<Machine>(new Machine()); @@ -102,8 +100,6 @@ Loader::load(const Glib::ustring& uri) const Glib::ustring& node_id = (*i)["initialNode"]; const Glib::ustring& duration = (*i)["duration"]; - cout << "Initial: " << node_id << " - " << duration << endl; - SharedPtr<Node> node(new Node(strtod(duration.c_str(), NULL), true)); machine->add_node(node); created.insert(std::make_pair(node_id.collate_key(), node)); @@ -125,8 +121,6 @@ Loader::load(const Glib::ustring& uri) const Glib::ustring& node_id = (*i)["node"]; const Glib::ustring& duration = (*i)["duration"]; - //cout << "Node: " << node_id << " - " << duration << endl; - if (created.find(node_id.collate_key()) == created.end()) { SharedPtr<Node> node(new Node(strtod(duration.c_str(), NULL), false)); machine->add_node(node); @@ -137,11 +131,6 @@ Loader::load(const Glib::ustring& uri) } - /*for (Created::iterator n = created.begin(); n != created.end(); ++n) { - cout << "NODE: " << n->first << endl; - }*/ - - /* Get note actions */ query = Raul::RDFQuery(*_namespaces, Glib::ustring( @@ -157,8 +146,6 @@ Loader::load(const Glib::ustring& uri) const Glib::ustring& node_id = (*i)["node"]; const Glib::ustring& note = (*i)["note"]; - //cerr << "NOTE: " << node_id << " = " << note << endl; - Created::iterator node_i = created.find(node_id); if (node_i != created.end()) { SharedPtr<Node> node = node_i->second; diff --git a/src/engine/Machine.cpp b/src/engine/Machine.cpp index 38e6e11..5879243 100644 --- a/src/engine/Machine.cpp +++ b/src/engine/Machine.cpp @@ -55,7 +55,6 @@ Machine::set_sink(SharedPtr<Raul::MIDISink> sink) void Machine::add_node(SharedPtr<Node> node) { - //cerr << "ADDING NODE " << node.get() << endl; assert(_nodes.find(node) == _nodes.end()); _nodes.push_back(node); } @@ -113,13 +112,6 @@ Machine::earliest_node() const } } } - /*for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) { - const SharedPtr<Node> node = (*n); - - if (node->is_active()) - if (!earliest || node->exit_time() < earliest->exit_time()) - earliest = node; - }*/ return earliest; } @@ -294,13 +286,6 @@ Machine::run(const Raul::TimeSlice& time) void Machine::learn(SharedPtr<LearnRequest> learn) { - std::cerr << "Learn" << std::endl; - - /*LearnRequest request(node, - SharedPtr<MidiAction>(new MidiAction(4, NULL)), - SharedPtr<MidiAction>(new MidiAction(4, NULL)));*/ - - //_pending_learns.push_back(learn); _pending_learn = learn; } @@ -320,8 +305,6 @@ Machine::write_state(Raul::RDFWriter& writer) for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) { - //cerr << "Writing node " << count++ << " state." << endl; - (*n)->write_state(writer); if ((*n)->is_initial()) { @@ -339,13 +322,9 @@ Machine::write_state(Raul::RDFWriter& writer) for (Nodes::const_iterator n = _nodes.begin(); n != _nodes.end(); ++n) { - //cerr << "Writing node " << count++ << " edges: "; - for (Node::Edges::const_iterator e = (*n)->outgoing_edges().begin(); e != (*n)->outgoing_edges().end(); ++e) { - //cerr << "."; - (*e)->write_state(writer); writer.write(RdfId(RdfId::RESOURCE, ""), @@ -353,8 +332,6 @@ Machine::write_state(Raul::RDFWriter& writer) (*e)->id()); } - //cerr << endl; - } } diff --git a/src/engine/MachineBuilder.cpp b/src/engine/MachineBuilder.cpp index b62e90e..8be9148 100644 --- a/src/engine/MachineBuilder.cpp +++ b/src/engine/MachineBuilder.cpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <algorithm> @@ -91,22 +91,15 @@ MachineBuilder::connect_nodes(SharedPtr<Machine> m, SharedPtr<Node> delay_node; - /*cerr << "******" << endl; - cerr << "Connect nodes durations: " << tail->duration() << " .. " << head->duration() << endl; - cerr << "Connect nodes times: " << tail_end_time << " .. " << head_start_time << endl;*/ - if (is_delay_node(tail) && tail->outgoing_edges().size() == 0) { // Tail is a delay node, just accumulate the time difference into it - //cerr << "Accumulating delay " << tail_end_time << " .. " << head_start_time << endl; set_node_duration(tail, tail->duration() + head_start_time - tail_end_time); tail->add_outgoing_edge(SharedPtr<Edge>(new Edge(tail, head))); } else if (head_start_time == tail_end_time) { // Connect directly - //cerr << "Connnecting directly " << tail_end_time << " .. " << head_start_time << endl; tail->add_outgoing_edge(SharedPtr<Edge>(new Edge(tail, head))); } else { // Need to actually create a delay node - //cerr << "Adding delay node for " << tail_end_time << " .. " << head_start_time << endl; delay_node = SharedPtr<Node>(new Node()); set_node_duration(delay_node, head_start_time - tail_end_time); tail->add_outgoing_edge(SharedPtr<Edge>(new Edge(tail, delay_node))); @@ -114,8 +107,6 @@ MachineBuilder::connect_nodes(SharedPtr<Machine> m, m->add_node(delay_node); } - /*cerr << "******" << endl << endl;*/ - return delay_node; } @@ -130,10 +121,7 @@ MachineBuilder::event(Raul::BeatTime time_offset, if (ev_size == 0) return; - //cerr << "t = " << t << endl; - if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_ON) { - //cerr << "NOTE ON: " << (int)buf[1] << ", channel = " << (int)(buf[0] & 0x0F) << endl; SharedPtr<Node> node(new Node()); node->set_enter_action(SharedPtr<Action>(new MidiAction(ev_size, buf))); @@ -148,7 +136,6 @@ MachineBuilder::event(Raul::BeatTime time_offset, if (j->second->outgoing_edges().empty()) { this_connect_node = j->second; this_connect_node_end_time = j->first + j->second->duration(); - cerr << "POLY CONNECT!\n"; break; } } @@ -157,7 +144,6 @@ MachineBuilder::event(Raul::BeatTime time_offset, // Currently monophonic, or didn't find a poly node, so use _connect_node // which is maintained below on note off events. if ( ! this_connect_node) { - cerr << "NO POLY CONNECT\n"; this_connect_node = _connect_node; this_connect_node_end_time = _connect_node_end_time; } @@ -166,9 +152,6 @@ MachineBuilder::event(Raul::BeatTime time_offset, SharedPtr<Node> delay_node = connect_nodes(_machine, this_connect_node, this_connect_node_end_time, node, t); - if (delay_node) - cerr << "XXXXXXXXXXXXXX NOTE ON DELAY NODE\n"; - if (delay_node) { _connect_node = delay_node; _connect_node_end_time = t; @@ -178,7 +161,7 @@ MachineBuilder::event(Raul::BeatTime time_offset, _active_nodes.push_back(node); } else if ((buf[0] & 0xF0) == MIDI_CMD_NOTE_OFF) { - //cerr << "NOTE OFF: " << (int)buf[1] << endl; + for (ActiveList::iterator i = _active_nodes.begin(); i != _active_nodes.end(); ++i) { SharedPtr<MidiAction> action = PtrCast<MidiAction>((*i)->enter_action()); if (!action) @@ -191,8 +174,6 @@ MachineBuilder::event(Raul::BeatTime time_offset, && (ev[0] & 0x0F) == (buf[0] & 0x0F) // same channel && ev[1] == buf[1]) // same note { - //cerr << "FOUND MATCHING NOTE OFF!\n"; - SharedPtr<Node> resolved = *i; resolved->set_exit_action(SharedPtr<Action>(new MidiAction(ev_size, buf))); @@ -201,15 +182,11 @@ MachineBuilder::event(Raul::BeatTime time_offset, // Last active note if (_active_nodes.size() == 1) { - cerr << "{ RESOLVING, t= " << t << "\n"; - _connect_node_end_time = t; // Finish a polyphonic section if (_poly_nodes.size() > 0) { - cerr << "POLY\n"; - _connect_node = SharedPtr<Node>(new Node()); _machine->add_node(_connect_node); @@ -228,14 +205,11 @@ MachineBuilder::event(Raul::BeatTime time_offset, // Just monophonic } else { - cerr << "NO POLY\n"; - // Trim useless delay node if possible (these appear after poly sections) if (is_delay_node(_connect_node) && _connect_node->duration() == 0 && _connect_node->outgoing_edges().size() == 1 && (*_connect_node->outgoing_edges().begin())->head() == resolved) { - cerr << "TRIMMING\n"; _connect_node->outgoing_edges().clear(); assert(_connect_node->outgoing_edges().empty()); _connect_node->set_enter_action(resolved->enter_action()); @@ -248,18 +222,13 @@ MachineBuilder::event(Raul::BeatTime time_offset, _machine->add_node(_connect_node); } else { - - cerr << "RESOLVED\n"; _connect_node = resolved; _machine->add_node(resolved); } } - cerr << "}"; - // Polyphonic, add this state to poly list } else { - cerr << "ADDING POLY\n"; _poly_nodes.push_back(make_pair(resolved->enter_time(), resolved)); _connect_node = resolved; _connect_node_end_time = t; @@ -273,6 +242,7 @@ MachineBuilder::event(Raul::BeatTime time_offset, break; } } + } } @@ -309,43 +279,6 @@ MachineBuilder::resolve() && _machine->nodes().find(_initial_node) == _machine->nodes().end()) _machine->add_node(_initial_node); -#if 0 - // Quantize - if (_quantization > 0) { - for (Machine::Nodes::iterator i = _machine->nodes().begin(); - i != _machine->nodes().end(); ++i) { - Raul::BeatTime q_dur = Quantizer::quantize(_quantization, (*i)->duration()); - - // Never quantize a note to duration 0 - if (q_dur > 0 || ( !(*i)->enter_action() && !(*i)->exit_action() )) - (*i)->set_duration(q_dur); - } - } - - // Remove any useless states - for (Machine::Nodes::iterator i = _machine->nodes().begin(); - i != _machine->nodes().end() ; ) { - - if (!(*i)->enter_action() && !(*i)->exit_action() && (*i)->duration() == 0 - && (*i)->outgoing_edges().size() <= 1) { - - // Connect any predecessors to the successor - if ((*i)->outgoing_edges().size() == 1) { - SharedPtr<Node> successor = *((*i)->outgoing_edges().begin())->head(); - - for (Machine::Nodes::iterator i = _machine->nodes().begin(); - i != _machine->nodes().end() ; ) { - - - Machine::Nodes::iterator next = i; - ++next; - - _machine->remove_node(*i); - - i = next; - } - } -#endif } diff --git a/src/engine/MidiAction.cpp b/src/engine/MidiAction.cpp index 969e53a..9609bb6 100644 --- a/src/engine/MidiAction.cpp +++ b/src/engine/MidiAction.cpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <iostream> diff --git a/src/engine/Node.cpp b/src/engine/Node.cpp index b55619d..b03fa1c 100644 --- a/src/engine/Node.cpp +++ b/src/engine/Node.cpp @@ -77,13 +77,11 @@ Node::remove_exit_action() _exit_action.reset(); } -//using namespace std; void Node::enter(SharedPtr<Raul::MIDISink> sink, BeatTime time) { assert(!_is_active); - //std::cerr << "ENTER " << time << std::endl; _is_active = true; _enter_time = time; @@ -96,7 +94,6 @@ void Node::exit(SharedPtr<Raul::MIDISink> sink, BeatTime time) { assert(_is_active); - //std::cerr << "EXIT " << time << std::endl; if (sink && _exit_action) _exit_action->execute(sink, time); @@ -172,13 +169,8 @@ Node::write_state(Raul::RDFWriter& writer) RdfId(RdfId::RESOURCE, "machina:exitAction"), _exit_action->id()); } - - /*for (Node::Edges::const_iterator e = _outgoing_edges.begin(); - e != _outgoing_edges.end(); ++e) - (*e)->write_state(writer);*/ } - } // namespace Machina diff --git a/src/engine/Recorder.cpp b/src/engine/Recorder.cpp index c6130ab..615cd97 100644 --- a/src/engine/Recorder.cpp +++ b/src/engine/Recorder.cpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <iostream> @@ -31,23 +31,17 @@ Recorder::Recorder(size_t buffer_size, double tick_rate, double q) , _record_buffer(buffer_size) , _builder(new MachineBuilder(SharedPtr<Machine>(new Machine()), q)) { - cerr << "XXXXXXXXXXXX new recorder, q=" << q << endl; } void Recorder::_whipped() { - cerr << "Whipped" << endl; - TickTime t; size_t size; unsigned char buf[4]; while (_record_buffer.read(&t, &size, buf)) { - //cout << "RECORD EVENT: t=" << t * _tick_rate << ", size=" << size << ", buf=0x" - // << std::hex << (int)((unsigned char)buf[0]) << std::dec << endl; - _builder->set_time(t * _tick_rate); _builder->event(0, size, buf); } diff --git a/src/engine/SMFDriver.cpp b/src/engine/SMFDriver.cpp index 0283288..b936143 100644 --- a/src/engine/SMFDriver.cpp +++ b/src/engine/SMFDriver.cpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include <list> diff --git a/src/engine/machina/ActionFactory.hpp b/src/engine/machina/ActionFactory.hpp index c43bf72..72303ee 100644 --- a/src/engine/machina/ActionFactory.hpp +++ b/src/engine/machina/ActionFactory.hpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MACHINA_ACTIONFACTORY_HPP diff --git a/src/engine/machina/Driver.hpp b/src/engine/machina/Driver.hpp index acc4278..c28bfcf 100644 --- a/src/engine/machina/Driver.hpp +++ b/src/engine/machina/Driver.hpp @@ -1,5 +1,4 @@ /* This file is part of Machina. - * _engine->driver()->reset_time(); * Copyright (C) 2007 Dave Robillard <http://drobilla.net> * * Machina is free software; you can redistribute it and/or modify it under the @@ -13,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MACHINA_DRIVER_HPP diff --git a/src/engine/machina/Engine.hpp b/src/engine/machina/Engine.hpp index dc47b2a..a7d0ed7 100644 --- a/src/engine/machina/Engine.hpp +++ b/src/engine/machina/Engine.hpp @@ -20,6 +20,7 @@ #include <glibmm/ustring.h> #include <raul/SharedPtr.h> +#include <raul/types.h> #include "machina/Driver.hpp" namespace Machina { @@ -38,7 +39,7 @@ public: SharedPtr<Machine> load_machine(const Glib::ustring& uri); SharedPtr<Machine> import_machine(const Glib::ustring& uri); - SharedPtr<Machine> learn_midi(const Glib::ustring& uri); + SharedPtr<Machine> import_midi(const Glib::ustring& uri, Raul::BeatTime d); void set_bpm(double bpm); void set_quantization(double beat_fraction); diff --git a/src/engine/machina/JackDriver.hpp b/src/engine/machina/JackDriver.hpp index 1ab6643..ce95462 100644 --- a/src/engine/machina/JackDriver.hpp +++ b/src/engine/machina/JackDriver.hpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MACHINA_JACKDRIVER_HPP @@ -69,8 +69,9 @@ public: void finish_record(); private: - void process_input(SharedPtr<Machine> machine, - const Raul::TimeSlice& time); + void process_input(SharedPtr<Machine> machine, + const Raul::TimeSlice& time); + virtual void on_process(jack_nframes_t nframes); Raul::Semaphore _machine_changed; diff --git a/src/engine/machina/LearnRequest.hpp b/src/engine/machina/LearnRequest.hpp index 9284e90..20c02e5 100644 --- a/src/engine/machina/LearnRequest.hpp +++ b/src/engine/machina/LearnRequest.hpp @@ -43,10 +43,12 @@ public: return ret; } + void start(double q, BeatTime time) + { _started = true; _start_time = time; _quantization = q; } + void finish(BeatTime time); - - void start(double q, BeatTime time) { _started = true; _start_time = time; _quantization = q; } - bool started() { return _started; } + + bool started() { return _started; } const SharedPtr<Node>& node() { return _node; } const SharedPtr<MidiAction>& enter_action() { return _enter_action; } diff --git a/src/engine/machina/Loader.hpp b/src/engine/machina/Loader.hpp index af35c56..7e296c0 100644 --- a/src/engine/machina/Loader.hpp +++ b/src/engine/machina/Loader.hpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MACHINA_LOADER_HPP diff --git a/src/engine/machina/Machine.hpp b/src/engine/machina/Machine.hpp index 14632f0..9504217 100644 --- a/src/engine/machina/Machine.hpp +++ b/src/engine/machina/Machine.hpp @@ -56,10 +56,8 @@ public: // Any context Raul::BeatTime time() { return _time; } - //LearnRequest pop_learn() { return _pending_learns.pop_front(); } - //SharedPtr<LearnRequest> first_learn() { return *_pending_learns.begin(); } - SharedPtr<LearnRequest> pending_learn() { return _pending_learn; } - void clear_pending_learn() { _pending_learn.reset(); } + SharedPtr<LearnRequest> pending_learn() { return _pending_learn; } + void clear_pending_learn() { _pending_learn.reset(); } typedef Raul::List<SharedPtr<Node> > Nodes; Nodes& nodes() { return _nodes; } diff --git a/src/engine/machina/MachineBuilder.hpp b/src/engine/machina/MachineBuilder.hpp index 25104e8..ddb3e02 100644 --- a/src/engine/machina/MachineBuilder.hpp +++ b/src/engine/machina/MachineBuilder.hpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MACHINA_MACHINEBUILDER_HPP diff --git a/src/engine/machina/MidiAction.hpp b/src/engine/machina/MidiAction.hpp index 510c0d0..6541f0e 100644 --- a/src/engine/machina/MidiAction.hpp +++ b/src/engine/machina/MidiAction.hpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MACHINA_MIDIACTION_HPP diff --git a/src/engine/machina/Recorder.hpp b/src/engine/machina/Recorder.hpp index 1bc07c3..d03f6fc 100644 --- a/src/engine/machina/Recorder.hpp +++ b/src/engine/machina/Recorder.hpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MACHINA_RECORDER_HPP diff --git a/src/engine/machina/SMFDriver.hpp b/src/engine/machina/SMFDriver.hpp index 7b22a26..af6e1bb 100644 --- a/src/engine/machina/SMFDriver.hpp +++ b/src/engine/machina/SMFDriver.hpp @@ -12,7 +12,7 @@ * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef MACHINA_SMFDRIVER_HPP diff --git a/src/engine/machina/types.hpp b/src/engine/machina/types.hpp index 70eae7d..6e661ef 100644 --- a/src/engine/machina/types.hpp +++ b/src/engine/machina/types.hpp @@ -18,14 +18,8 @@ #ifndef MACHINA_TYPES_HPP #define MACHINA_TYPES_HPP -#include <jack/types.h> - namespace Machina { - -//typedef jack_nframes_t FrameCount; -//typedef jack_nframes_t Timestamp; - typedef unsigned char byte; } // namespace Machina diff --git a/src/gui/MachinaCanvas.cpp b/src/gui/MachinaCanvas.cpp index 716a40d..1be5ef0 100644 --- a/src/gui/MachinaCanvas.cpp +++ b/src/gui/MachinaCanvas.cpp @@ -99,7 +99,6 @@ MachinaCanvas::canvas_event(GdkEvent* event) string name = string("Note")+(char)(last++ +'0'); SharedPtr<Machina::Node> node(new Machina::Node(1.0, false)); - //node->add_enter_action(SharedPtr<Machina::Action>(new Machina::PrintAction(name))); SharedPtr<NodeView> view(new NodeView(_app->window(), shared_from_this(), node, name, x, y)); @@ -137,38 +136,6 @@ MachinaCanvas::disconnect_node(boost::shared_ptr<NodeView> src, { src->node()->remove_outgoing_edges_to(head->node()); remove_connection(src, head); - -#if 0 - boost::shared_ptr<MachinaPort> input - = boost::dynamic_pointer_cast<MachinaPort>(port1); - boost::shared_ptr<MachinaPort> output - = boost::dynamic_pointer_cast<MachinaPort>(port2); - - if (!input || !output) - return; - - if (input->is_output() && output->is_input()) { - // Damn, guessed wrong - boost::shared_ptr<MachinaPort> swap = input; - input = output; - output = swap; - } - - if (!input || !output || input->is_output() || output->is_input()) { - status_message("ERROR: Attempt to disconnect mismatched/unknown ports"); - return; - } - - if (input->type() == JACK_AUDIO && output->type() == JACK_AUDIO - || input->type() == JACK_MIDI && output->type() == JACK_MIDI) - _app->jack_driver()->disconnect(output, input); -#ifdef HAVE_ALSA - else if (input->type() == ALSA_MIDI && output->type() == ALSA_MIDI) - _app->alsa_driver()->disconnect(output, input); -#endif - else - status_message("ERROR: Attempt to disconnect ports with mismatched types"); -#endif } @@ -185,7 +152,6 @@ MachinaCanvas::create_node_view(SharedPtr<Machina::Node> node) &MachinaCanvas::node_clicked), WeakPtr<NodeView>(view))); add_item(view); - //view->resize(); return view; } @@ -235,20 +201,6 @@ MachinaCanvas::build(SharedPtr<Machina::Machine> machine) } arrange(); - /* - while (Gtk::Main::events_pending()) - Gtk::Main::iteration(false); - - for (list<boost::shared_ptr<Connection> >::iterator c = _connections.begin(); c != _connections.end(); ++c) { - const SharedPtr<EdgeView> view = PtrCast<EdgeView>(*c); - if (view) - view->update_label(); // very, very slow - - while (Gtk::Main::events_pending()) - Gtk::Main::iteration(false); - - } - */ } diff --git a/src/gui/MachinaGUI.cpp b/src/gui/MachinaGUI.cpp index e5e6d90..e1ba61f 100644 --- a/src/gui/MachinaGUI.cpp +++ b/src/gui/MachinaGUI.cpp @@ -33,16 +33,10 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine) -: _pane_closed(false), - _update_pane_position(true), - _user_pane_position(0), - _refresh(false), +: _refresh(false), _engine(engine), _maid(new Raul::Maid(32)) { - /*_settings_filename = getenv("HOME"); - _settings_filename += "/.machinarc";*/ - _canvas = boost::shared_ptr<MachinaCanvas>(new MachinaCanvas(this, 1600*2, 1200*2)); Glib::RefPtr<Gnome::Glade::Xml> xml = GladeXml::create(); @@ -60,14 +54,10 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine) xml->get_widget("export_graphviz_menuitem", _menu_export_graphviz); xml->get_widget("view_toolbar_menuitem", _menu_view_toolbar); xml->get_widget("view_labels_menuitem", _menu_view_labels); - //xml->get_widget("view_refresh_menuitem", _menu_view_refresh); - //xml->get_widget("view_messages_menuitem", _menu_view_messages); xml->get_widget("help_about_menuitem", _menu_help_about); xml->get_widget("help_help_menuitem", _menu_help_help); xml->get_widget("canvas_scrolledwindow", _canvas_scrolledwindow); xml->get_widget("status_text", _status_text); - xml->get_widget("main_paned", _main_paned); - xml->get_widget("messages_expander", _messages_expander); xml->get_widget("slave_radiobutton", _slave_radiobutton); xml->get_widget("bpm_radiobutton", _bpm_radiobutton); xml->get_widget("bpm_spinbutton", _bpm_spinbutton); @@ -86,8 +76,6 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine) _canvas->scroll_to(static_cast<int>(_canvas->width()/2 - 320), static_cast<int>(_canvas->height()/2 - 240)); // FIXME: hardcoded - //_zoom_slider->signal_value_changed().connect(sigc::mem_fun(this, &MachinaGUI::zoom_changed)); - _record_button->signal_toggled().connect(sigc::mem_fun(this, &MachinaGUI::record_toggled)); _stop_button->signal_clicked().connect(sigc::mem_fun(this, &MachinaGUI::stop_clicked)); _play_button->signal_toggled().connect(sigc::mem_fun(this, &MachinaGUI::play_toggled)); @@ -113,14 +101,10 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine) sigc::mem_fun(this, &MachinaGUI::menu_export_midi)); _menu_export_graphviz->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_export_graphviz)); - //_menu_view_refresh->signal_activate().connect( - // sigc::mem_fun(this, &MachinaGUI::menu_view_refresh)); _menu_view_toolbar->signal_toggled().connect( sigc::mem_fun(this, &MachinaGUI::show_toolbar_toggled)); _menu_view_labels->signal_toggled().connect( sigc::mem_fun(this, &MachinaGUI::show_labels_toggled)); - //_menu_view_messages->signal_toggled().connect( - // sigc::mem_fun(this, &MachinaGUI::show_messages_toggled)); _menu_help_about->signal_activate().connect( sigc::mem_fun(this, &MachinaGUI::menu_help_about)); _menu_help_help->signal_activate().connect( @@ -138,26 +122,10 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine) connect_widgets(); - //update_state(); - _canvas->show(); _main_window->present(); - _update_pane_position = false; - _main_paned->set_position(max_pane_position()); - - _main_paned->property_position().signal_changed().connect( - sigc::mem_fun(*this, &MachinaGUI::on_pane_position_changed)); - - _messages_expander->property_expanded().signal_changed().connect( - sigc::mem_fun(*this, &MachinaGUI::on_messages_expander_changed)); - - _main_paned->set_position(max_pane_position()); - _user_pane_position = max_pane_position() - _main_window->get_height()/8; - _update_pane_position = true; - _pane_closed = true; - _bpm_radiobutton->set_active(true); _quantize_checkbutton->set_active(false); @@ -171,9 +139,6 @@ MachinaGUI::MachinaGUI(SharedPtr<Machina::Engine> engine) // Idle callback to update node states Glib::signal_timeout().connect(sigc::mem_fun(this, &MachinaGUI::idle_callback), 100); - // Faster idle callback to update DSP load progress bar - //Glib::signal_timeout().connect(sigc::mem_fun(this, &MachinaGUI::update_load), 50); - _canvas->build(engine->machine()); } @@ -183,21 +148,6 @@ MachinaGUI::~MachinaGUI() } -void -MachinaGUI::attach() -{ -#if 0 - _jack_driver->attach(true); - - menu_view_refresh(); - - update_toolbar(); - - //m_status_bar->push("Connected to JACK server"); -#endif -} - - bool MachinaGUI::idle_callback() { @@ -274,46 +224,6 @@ MachinaGUI::zoom(double z) void -MachinaGUI::zoom_changed() -{ -/* - static bool enable_signal = true; - if (enable_signal) { - enable_signal = false; - zoom(_zoom_slider->get_value()); - enable_signal = true; - } - */ -} - - -#if 0 -void -MachinaGUI::update_state() -{ - for (ModuleMap::iterator i = _canvas->modules().begin(); i != _canvas->modules().end(); ++i) - (*i).second->load_location(); - - //cerr << "[Machina] Resizing window: (" << _state_manager->get_window_size().x - // << "," << _state_manager->get_window_size().y << ")" << endl; - - _main_window->resize( - static_cast<int>(_state_manager->get_window_size().x), - static_cast<int>(_state_manager->get_window_size().y)); - - //cerr << "[Machina] Moving window: (" << _state_manager->get_window_location().x - // << "," << _state_manager->get_window_location().y << ")" << endl; - - _main_window->move( - static_cast<int>(_state_manager->get_window_location().x), - static_cast<int>(_state_manager->get_window_location().y)); - -} - -#endif - - -void MachinaGUI::status_message(const string& msg) { if (_status_text->get_buffer()->size() > 0) @@ -352,7 +262,6 @@ MachinaGUI::menu_file_open() const int result = dialog.run(); if (result == Gtk::RESPONSE_OK) { - //SharedPtr<Machina::Machine> new_machine = _engine->load_machine(dialog.get_uri()); SharedPtr<Machina::Machine> new_machine = _engine->import_machine(dialog.get_uri()); if (new_machine) { _canvas->destroy(); @@ -457,23 +366,10 @@ MachinaGUI::menu_import_midi() extra_widget->show_all(); - /*Gtk::HBox* extra_widget = Gtk::manage(new Gtk::HBox()); - Gtk::SpinButton* track_sb = Gtk::manage(new Gtk::SpinButton()); - track_sb->set_increments(1, 10); - track_sb->set_range(1, 256); - extra_widget->pack_start(*Gtk::manage(new Gtk::Label("")), true, true); - extra_widget->pack_start(*Gtk::manage(new Gtk::Label("Track: ")), false, false); - extra_widget->pack_start(*track_sb, false, false); - dialog.set_extra_widget(*extra_widget); - extra_widget->show_all(); - */ - const int result = dialog.run(); if (result == Gtk::RESPONSE_OK) { SharedPtr<Machina::SMFDriver> file_driver(new Machina::SMFDriver()); - //SharedPtr<Machina::Machine> machine = file_driver->learn(dialog.get_uri(), - // track_sb->get_value_as_int()); double length = length_sb->get_value_as_int(); @@ -510,7 +406,7 @@ MachinaGUI::menu_export_midi() const SharedPtr<Machina::Machine> m = _engine->machine(); m->set_sink(file_driver->writer()); file_driver->writer()->start(dialog.get_filename()); - file_driver->run(m, 32); // FIXME: hardcoded max length. TODO: solve halting problem + file_driver->run(m, 32); // TODO: solve halting problem m->set_sink(_engine->driver()); m->reset(); file_driver->writer()->finish(); @@ -535,66 +431,6 @@ MachinaGUI::menu_export_graphviz() void -MachinaGUI::on_pane_position_changed() -{ - // avoid infinite recursion... - if (!_update_pane_position) - return; - - _update_pane_position = false; - - int new_position = _main_paned->get_position(); - - if (_pane_closed && new_position < max_pane_position()) { - // Auto open - _user_pane_position = new_position; - _messages_expander->set_expanded(true); - _pane_closed = false; - //_menu_view_messages->set_active(true); - } else if (new_position >= max_pane_position()) { - // Auto close - _pane_closed = true; - - _messages_expander->set_expanded(false); - if (new_position > max_pane_position()) - _main_paned->set_position(max_pane_position()); // ... here - //_menu_view_messages->set_active(false); - - _user_pane_position = max_pane_position() - _main_window->get_height()/8; - } - - _update_pane_position = true; -} - - -void -MachinaGUI::on_messages_expander_changed() -{ - if (!_pane_closed) { - // Store pane position for restoring - _user_pane_position = _main_paned->get_position(); - if (_update_pane_position) { - _update_pane_position = false; - _main_paned->set_position(max_pane_position()); - _update_pane_position = true; - } - _pane_closed = true; - } else { - _main_paned->set_position(_user_pane_position); - _pane_closed = false; - } -} - -/* -void -MachinaGUI::show_messages_toggled() -{ - if (_update_pane_position) - //_messages_expander->set_expanded(_menu_view_messages->get_active()); -} -*/ - -void MachinaGUI::show_toolbar_toggled() { if (_menu_view_toolbar->get_active()) @@ -624,16 +460,6 @@ MachinaGUI::show_labels_toggled() } -/* -void -MachinaGUI::menu_view_refresh() -{ - assert(_canvas); - - //_canvas->destroy(); -} -*/ - void MachinaGUI::menu_help_about() { diff --git a/src/gui/MachinaGUI.hpp b/src/gui/MachinaGUI.hpp index eba8a93..391884e 100644 --- a/src/gui/MachinaGUI.hpp +++ b/src/gui/MachinaGUI.hpp @@ -49,9 +49,6 @@ public: void status_message(const string& msg); inline void queue_refresh() { _refresh = true; } - int max_pane_position() - { return _main_paned->property_max_position() - _messages_expander->get_label_widget()->get_height() - 8; } - protected: void connect_widgets(); @@ -62,14 +59,11 @@ protected: void menu_import_midi(); void menu_export_midi(); void menu_export_graphviz(); - //void show_messages_toggled(); void show_toolbar_toggled(); void show_labels_toggled(); - //void menu_view_refresh(); void menu_help_about(); void menu_help_help(); void zoom(double z); - void zoom_changed(); bool idle_callback(); void update_toolbar(); bool scrolled_window_event(GdkEvent* ev); @@ -78,16 +72,9 @@ protected: void stop_clicked(); void play_toggled(); - void on_pane_position_changed(); - void on_messages_expander_changed(); - void quantize_changed(); void tempo_changed(); - bool _pane_closed; - bool _update_pane_position; - int _user_pane_position; - bool _refresh; string _save_uri; @@ -113,12 +100,9 @@ protected: Gtk::MenuItem* _menu_help_about; Gtk::CheckMenuItem* _menu_view_labels; Gtk::CheckMenuItem* _menu_view_toolbar; - //Gtk::CheckMenuItem* _menu_view_messages; - //Gtk::MenuItem* _menu_view_refresh; Gtk::MenuItem* _menu_help_help; Gtk::ScrolledWindow* _canvas_scrolledwindow; Gtk::TextView* _status_text; - Gtk::Paned* _main_paned; Gtk::Expander* _messages_expander; Gtk::RadioButton* _slave_radiobutton; Gtk::RadioButton* _bpm_radiobutton; diff --git a/src/gui/machina.glade b/src/gui/machina.glade index 61096f1..4002ba1 100644 --- a/src/gui/machina.glade +++ b/src/gui/machina.glade @@ -579,98 +579,19 @@ </child> <child> - <widget class="GtkVPaned" id="main_paned"> + <widget class="GtkScrolledWindow" id="canvas_scrolledwindow"> <property name="visible">True</property> + <property name="can_default">True</property> + <property name="has_default">True</property> <property name="can_focus">True</property> - <property name="position">0</property> + <property name="has_focus">True</property> + <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> + <property name="shadow_type">GTK_SHADOW_IN</property> + <property name="window_placement">GTK_CORNER_TOP_LEFT</property> <child> - <widget class="GtkScrolledWindow" id="canvas_scrolledwindow"> - <property name="visible">True</property> - <property name="can_default">True</property> - <property name="has_default">True</property> - <property name="can_focus">True</property> - <property name="has_focus">True</property> - <property name="hscrollbar_policy">GTK_POLICY_ALWAYS</property> - <property name="vscrollbar_policy">GTK_POLICY_ALWAYS</property> - <property name="shadow_type">GTK_SHADOW_IN</property> - <property name="window_placement">GTK_CORNER_TOP_LEFT</property> - - <child> - <placeholder/> - </child> - </widget> - <packing> - <property name="shrink">False</property> - <property name="resize">True</property> - </packing> - </child> - - <child> - <widget class="GtkExpander" id="messages_expander"> - <property name="can_focus">True</property> - <property name="expanded">False</property> - <property name="spacing">0</property> - - <child> - <widget class="GtkScrolledWindow" id="scrolledwindow1"> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="hscrollbar_policy">GTK_POLICY_NEVER</property> - <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property> - <property name="shadow_type">GTK_SHADOW_IN</property> - <property name="window_placement">GTK_CORNER_TOP_LEFT</property> - - <child> - <widget class="GtkTextView" id="status_text"> - <property name="visible">True</property> - <property name="sensitive">False</property> - <property name="can_focus">True</property> - <property name="editable">False</property> - <property name="overwrite">False</property> - <property name="accepts_tab">True</property> - <property name="justification">GTK_JUSTIFY_LEFT</property> - <property name="wrap_mode">GTK_WRAP_WORD</property> - <property name="cursor_visible">False</property> - <property name="pixels_above_lines">0</property> - <property name="pixels_below_lines">0</property> - <property name="pixels_inside_wrap">0</property> - <property name="left_margin">0</property> - <property name="right_margin">0</property> - <property name="indent">0</property> - <property name="text" translatable="yes"></property> - </widget> - </child> - </widget> - </child> - - <child> - <widget class="GtkLabel" id="label4"> - <property name="visible">True</property> - <property name="label" translatable="yes">Messages</property> - <property name="use_underline">False</property> - <property name="use_markup">False</property> - <property name="justify">GTK_JUSTIFY_LEFT</property> - <property name="wrap">False</property> - <property name="selectable">False</property> - <property name="xalign">0.5</property> - <property name="yalign">0.5</property> - <property name="xpad">0</property> - <property name="ypad">0</property> - <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property> - <property name="width_chars">-1</property> - <property name="single_line_mode">False</property> - <property name="angle">0</property> - </widget> - <packing> - <property name="type">label_item</property> - </packing> - </child> - </widget> - <packing> - <property name="shrink">True</property> - <property name="resize">True</property> - </packing> + <placeholder/> </child> </widget> <packing> |