/**************************************************************************** Dino - A simple pattern based MIDI sequencer Copyright (C) 2006 Lars Luthman This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ****************************************************************************/ #ifndef SEQUENCER_HPP #define SEQUENCER_HPP #include #include #include #include #include #include "debug.hpp" using namespace std; namespace Dino { class Song; /** This class sequences a Song to a string of MIDI events that are sent to JACK MIDI ports. It has functions for starting and stopping playback, changing the song position, and also for checking which instruments are available and for connecting a Track in the Song to one of those instruments. */ class Sequencer { public: /** This struct contains information about a writable MIDI port. */ struct InstrumentInfo { InstrumentInfo(const string& str) : name(str), connected(false) { } InstrumentInfo(const char* str) : name(str), connected(false) { } string name; bool connected; }; /** This will create a new Sequencer object with the JACK client name @c client_name and the Song object @c song. */ Sequencer(const string& client_name, Song& song); ~Sequencer(); /// @name Transport //@{ /** This starts the MIDI playback. */ void play(); /** This stops the MIDI playback. */ void stop(); /** This seeks to the given beat in the song. */ void go_to_beat(double beat); //@} /** Returns @c true if this Sequencer object is valid. */ bool is_valid() const; /// @name Instrument control //@{ /** This returns a vector of all instruments that are available for the sequencer to play. */ vector get_instruments(int track = -1) const; /** This assigns the given instrument to the given track, i.e. connects the track's output port to the instruments input port. This is not saved in the .dino file since all connections are supposed to be restored by LASH. */ void set_instrument(int track, const string& instrument); /** This creates new MIDI output ports for all tracks. */ void reset_ports(); //@} /// @name Signals //@{ sigc::signal signal_beat_changed; sigc::signal signal_instruments_changed; //@} private: bool beat_checker(); bool ports_checker(); /** This initialises the internal JACK client object. */ bool init_jack(const string& client_name); /// @name JACK callbacks //@{ /** This function is called whenever the JACK daemon wants to know the beat and tick for a given frame position. */ void jack_timebase_callback(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos); /** This is called once for each JACK cycle. MIDI is sequenced from here. @callgraph */ int jack_process_callback(jack_nframes_t nframes); /** This is called when the JACK daemon is being shut down. */ void jack_shutdown_handler(); /** This is called when ports are registered or unregistered. */ void jack_port_registration_callback(jack_port_id_t port, int m); //@} /// @name JACK callback wrappers //@{ static void jack_timebase_callback_(jack_transport_state_t state, jack_nframes_t nframes, jack_position_t* pos, int new_pos, void* arg) { static_cast(arg)->jack_timebase_callback(state, nframes, pos, new_pos); } static int jack_process_callback_(jack_nframes_t nframes, void* arg) { return static_cast(arg)->jack_process_callback(nframes); } static void jack_shutdown_handler_(void* arg) { static_cast(arg)->jack_shutdown_handler(); } static void jack_port_registration_callback_(jack_port_id_t port, int m, void* arg) { static_cast(arg)->jack_port_registration_callback(port, m); } static void jack_error_function(const char* msg) { using namespace Dino; dbg0<<"JACK: "< m_output_ports; jack_port_t* m_input_port; double m_cc_resolution; double m_time_to_next_cc; int m_last_beat; int m_last_tick; bool m_sent_all_off; volatile int m_current_beat; volatile int m_old_current_beat; volatile int m_ports_changed; int m_old_ports_changed; }; } #endif