From 2f4392f043fe174f798f0d2ca60dc37b2dd8ec7b Mon Sep 17 00:00:00 2001 From: David Robillard Date: Fri, 9 Jun 2006 01:48:38 +0000 Subject: [PATCH] Removed excessive debug printing, added missing files for SMPTE namespace and Jack libmidi++ ports git-svn-id: svn://localhost/ardour2/branches/midi@577 d708f5d6-7413-0410-9779-e7cbd77b26cf --- libs/ardour/ardour/smpte.h | 76 ++++++ libs/ardour/session_midi.cc | 1 + libs/ardour/session_process.cc | 10 +- libs/ardour/smpte.cc | 406 +++++++++++++++++++++++++++++++++ libs/midi++2/jack_midiport.cc | 128 +++++++++++ libs/midi++2/midi++/jack.h | 68 ++++++ 6 files changed, 681 insertions(+), 8 deletions(-) create mode 100644 libs/ardour/ardour/smpte.h create mode 100644 libs/ardour/smpte.cc create mode 100644 libs/midi++2/jack_midiport.cc create mode 100644 libs/midi++2/midi++/jack.h diff --git a/libs/ardour/ardour/smpte.h b/libs/ardour/ardour/smpte.h new file mode 100644 index 0000000000..6a7684c5ba --- /dev/null +++ b/libs/ardour/ardour/smpte.h @@ -0,0 +1,76 @@ +/* Copyright (C) 2006 Paul Davis + + 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., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef __ardour_smpte_h__ +#define __ardour_smpte_h__ + +#include + +namespace SMPTE { + +enum Wrap { + NONE = 0, + FRAMES, + SECONDS, + MINUTES, + HOURS +}; + +// FIXME: make this a float +enum FPS { + MTC_24_FPS = 0, + MTC_25_FPS = 1, + MTC_30_FPS_DROP = 2, + MTC_30_FPS = 3 +}; + +struct Time { + bool negative; + uint32_t hours; + uint32_t minutes; + uint32_t seconds; + uint32_t frames; ///< SMPTE frames (not audio samples) + uint32_t subframes; ///< Typically unused + FPS rate; ///< Frame rate of this Time + static FPS default_rate; ///< Rate to use for default constructor + + Time(FPS a_rate = default_rate) { + negative = false; + hours = 0; + minutes = 0; + seconds = 0; + frames = 0; + subframes = 0; + rate = a_rate; + } +}; + +Wrap increment( Time& smpte ); +Wrap decrement( Time& smpte ); +Wrap increment_subframes( Time& smpte ); +Wrap decrement_subframes( Time& smpte ); +Wrap increment_seconds( Time& smpte ); +Wrap increment_minutes( Time& smpte ); +Wrap increment_hours( Time& smpte ); +void frames_floor( Time& smpte ); +void seconds_floor( Time& smpte ); +void minutes_floor( Time& smpte ); +void hours_floor( Time& smpte ); + +} // namespace SMPTE + +#endif // __ardour_smpte_h__ diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index 95d6d02f39..bb3c0018df 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include diff --git a/libs/ardour/session_process.cc b/libs/ardour/session_process.cc index bbd35a9055..2f35bbfee2 100644 --- a/libs/ardour/session_process.cc +++ b/libs/ardour/session_process.cc @@ -49,7 +49,7 @@ using namespace std; void Session::process (jack_nframes_t nframes) { - cerr << "CYCLE START " << _transport_frame << "-------------------" << endl; + //cerr << "CYCLE START " << _transport_frame << "-------------------" << endl; MIDI::Manager::instance()->cycle_start(nframes); @@ -69,7 +69,7 @@ Session::process (jack_nframes_t nframes) MIDI::Manager::instance()->cycle_end(); - cerr << "CYCLE END " << _transport_frame << "-----------------------" << endl; + //cerr << "CYCLE END " << _transport_frame << "-----------------------" << endl; } void @@ -87,8 +87,6 @@ Session::no_roll (jack_nframes_t nframes, jack_nframes_t offset) int ret = 0; bool declick = get_transport_declick_required(); - cerr << "[DR] no_roll\n"; - if (_click_io) { _click_io->silence (nframes, offset); } @@ -261,8 +259,6 @@ Session::process_with_events (jack_nframes_t nframes) long frames_moved; bool session_needs_butler = false; - cerr << "[DR] with events" << endl; - if (auditioner) { auditioner->silence (nframes, 0); } @@ -741,8 +737,6 @@ Session::follow_slave (jack_nframes_t nframes, jack_nframes_t offset) void Session::process_without_events (jack_nframes_t nframes) { - cerr << "[DR] without events" << endl; - bool session_needs_butler = false; jack_nframes_t stop_limit; long frames_moved; diff --git a/libs/ardour/smpte.cc b/libs/ardour/smpte.cc new file mode 100644 index 0000000000..17e5a6b42b --- /dev/null +++ b/libs/ardour/smpte.cc @@ -0,0 +1,406 @@ +/* Copyright (C) 2006 Paul Davis + + 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., + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#define SMPTE_IS_AROUND_ZERO( sm ) (!(sm).frames && !(sm).seconds && !(sm).minutes && !(sm).hours) +#define SMPTE_IS_ZERO( sm ) (!(sm).frames && !(sm).seconds && !(sm).minutes && !(sm).hours && !(sm.subframes)) + +#include + +namespace SMPTE { + +FPS Time::default_rate = MTC_30_FPS; + + +/** Increment @a smpte by exactly one frame (keep subframes value). + * Realtime safe. + * @return true if seconds wrap. + */ +Wrap +increment( Time& smpte ) +{ + //Wrap wrap = NONE; + Wrap wrap = NONE; + + if (smpte.negative) { + if (SMPTE_IS_AROUND_ZERO(smpte) && smpte.subframes) { + // We have a zero transition involving only subframes + smpte.subframes = 80 - smpte.subframes; + smpte.negative = false; + return SECONDS; + } + + smpte.negative = false; + wrap = decrement( smpte ); + if (!SMPTE_IS_ZERO( smpte )) { + smpte.negative = true; + } + return wrap; + } + + switch (smpte.rate) { + case MTC_24_FPS: + if (smpte.frames == 23) { + smpte.frames = 0; + wrap = SECONDS; + } + break; + case MTC_25_FPS: + if (smpte.frames == 24) { + smpte.frames = 0; + wrap = SECONDS; + } + break; + case MTC_30_FPS_DROP: + if (smpte.frames == 29) { + if ( ((smpte.minutes + 1) % 10) && (smpte.seconds == 59) ) { + smpte.frames = 2; + } + else { + smpte.frames = 0; + } + wrap = SECONDS; + } + break; + case MTC_30_FPS: + if (smpte.frames == 29) { + smpte.frames = 0; + wrap = SECONDS; + } + break; + } + + if (wrap == SECONDS) { + if (smpte.seconds == 59) { + smpte.seconds = 0; + wrap = MINUTES; + if (smpte.minutes == 59) { + smpte.minutes = 0; + wrap = HOURS; + smpte.hours++; + } else { + smpte.minutes++; + } + } else { + smpte.seconds++; + } + } else { + smpte.frames++; + } + + return wrap; +} + + +/** Decrement @a smpte by exactly one frame (keep subframes value) + * Realtime safe. + * @return true if seconds wrap. */ +Wrap +decrement( Time& smpte ) +{ + Wrap wrap = NONE; + + + if (smpte.negative || SMPTE_IS_ZERO(smpte)) { + smpte.negative = false; + wrap = increment( smpte ); + smpte.negative = true; + return wrap; + } else if (SMPTE_IS_AROUND_ZERO(smpte) && smpte.subframes) { + // We have a zero transition involving only subframes + smpte.subframes = 80 - smpte.subframes; + smpte.negative = true; + return SECONDS; + } + + switch (smpte.rate) { + case MTC_24_FPS: + if (smpte.frames == 0) { + smpte.frames = 23; + wrap = SECONDS; + } + break; + case MTC_25_FPS: + if (smpte.frames == 0) { + smpte.frames = 24; + wrap = SECONDS; + } + break; + case MTC_30_FPS_DROP: + if ((smpte.minutes % 10) && (smpte.seconds == 0)) { + if (smpte.frames <= 2) { + smpte.frames = 29; + wrap = SECONDS; + } + } else if (smpte.frames == 0) { + smpte.frames = 29; + wrap = SECONDS; + } + break; + case MTC_30_FPS: + if (smpte.frames == 0) { + smpte.frames = 29; + wrap = SECONDS; + } + break; + } + + if (wrap == SECONDS) { + if (smpte.seconds == 0) { + smpte.seconds = 59; + wrap = MINUTES; + if (smpte.minutes == 0) { + smpte.minutes = 59; + wrap = HOURS; + smpte.hours--; + } + else { + smpte.minutes--; + } + } else { + smpte.seconds--; + } + } else { + smpte.frames--; + } + + if (SMPTE_IS_ZERO( smpte )) { + smpte.negative = false; + } + + return wrap; +} + + +/** Go to lowest absolute subframe value in this frame (set to 0 :-) ) */ +void +frames_floor( Time& smpte ) +{ + smpte.subframes = 0; + if (SMPTE_IS_ZERO(smpte)) { + smpte.negative = false; + } +} + + +/** Increment @a smpte by one subframe */ +Wrap +increment_subframes( Time& smpte ) +{ + Wrap wrap = NONE; + + if (smpte.negative) { + smpte.negative = false; + wrap = decrement_subframes( smpte ); + if (!SMPTE_IS_ZERO(smpte)) { + smpte.negative = true; + } + return wrap; + } + + smpte.subframes++; + if (smpte.subframes >= 80) { + smpte.subframes = 0; + increment( smpte ); + return FRAMES; + } + return NONE; +} + + +/** Decrement @a smpte by one subframe */ +Wrap +decrement_subframes( Time& smpte ) +{ + Wrap wrap = NONE; + + if (smpte.negative) { + smpte.negative = false; + wrap = increment_subframes( smpte ); + smpte.negative = true; + return wrap; + } + + if (smpte.subframes <= 0) { + smpte.subframes = 0; + if (SMPTE_IS_ZERO(smpte)) { + smpte.negative = true; + smpte.subframes = 1; + return FRAMES; + } else { + decrement( smpte ); + smpte.subframes = 79; + return FRAMES; + } + } else { + smpte.subframes--; + if (SMPTE_IS_ZERO(smpte)) { + smpte.negative = false; + } + return NONE; + } +} + + +/** Go to next whole second (frames == 0 or frames == 2) */ +Wrap +increment_seconds( Time& smpte ) +{ + Wrap wrap = NONE; + + // Clear subframes + frames_floor( smpte ); + + if (smpte.negative) { + // Wrap second if on second boundary + wrap = increment(smpte); + // Go to lowest absolute frame value + seconds_floor( smpte ); + if (SMPTE_IS_ZERO(smpte)) { + smpte.negative = false; + } + } else { + // Go to highest possible frame in this second + switch (smpte.rate) { + case MTC_24_FPS: + smpte.frames = 23; + break; + case MTC_25_FPS: + smpte.frames = 24; + break; + case MTC_30_FPS_DROP: + case MTC_30_FPS: + smpte.frames = 29; + break; + } + + // Increment by one frame + wrap = increment( smpte ); + } + + return wrap; +} + + +/** Go to lowest (absolute) frame value in this second + * Doesn't care about positive/negative */ +void +seconds_floor( Time& smpte ) +{ + // Clear subframes + frames_floor( smpte ); + + // Go to lowest possible frame in this second + switch (smpte.rate) { + case MTC_24_FPS: + case MTC_25_FPS: + case MTC_30_FPS: + smpte.frames = 0; + break; + case MTC_30_FPS_DROP: + if ((smpte.minutes % 10) && (smpte.seconds == 0)) { + smpte.frames = 2; + } else { + smpte.frames = 0; + } + break; + } + + if (SMPTE_IS_ZERO(smpte)) { + smpte.negative = false; + } +} + + +/** Go to next whole minute (seconds == 0, frames == 0 or frames == 2) */ +Wrap +increment_minutes( Time& smpte ) +{ + Wrap wrap = NONE; + + // Clear subframes + frames_floor( smpte ); + + if (smpte.negative) { + // Wrap if on minute boundary + wrap = increment_seconds( smpte ); + // Go to lowest possible value in this minute + minutes_floor( smpte ); + } else { + // Go to highest possible second + smpte.seconds = 59; + // Wrap minute by incrementing second + wrap = increment_seconds( smpte ); + } + + return wrap; +} + + +/** Go to lowest absolute value in this minute */ +void +minutes_floor( Time& smpte ) +{ + // Go to lowest possible second + smpte.seconds = 0; + // Go to lowest possible frame + seconds_floor( smpte ); + + if (SMPTE_IS_ZERO(smpte)) { + smpte.negative = false; + } +} + + +/** Go to next whole hour (minute = 0, second = 0, frame = 0) */ +Wrap +increment_hours( Time& smpte ) +{ + Wrap wrap = NONE; + + // Clear subframes + frames_floor(smpte); + + if (smpte.negative) { + // Wrap if on hour boundary + wrap = increment_minutes( smpte ); + // Go to lowest possible value in this hour + hours_floor( smpte ); + } else { + smpte.minutes = 59; + wrap = increment_minutes( smpte ); + } + + return wrap; +} + + +/** Go to lowest absolute value in this hour */ +void +hours_floor( Time& smpte ) +{ + smpte.minutes = 0; + smpte.seconds = 0; + smpte.frames = 0; + smpte.subframes = 0; + + if (SMPTE_IS_ZERO(smpte)) { + smpte.negative = false; + } +} + + +} // namespace SMPTE diff --git a/libs/midi++2/jack_midiport.cc b/libs/midi++2/jack_midiport.cc new file mode 100644 index 0000000000..4fc24e8711 --- /dev/null +++ b/libs/midi++2/jack_midiport.cc @@ -0,0 +1,128 @@ +/* + Copyright (C) 2006 Paul Davis + Written by Dave Robillard + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: alsa_sequencer_midiport.cc 244 2006-01-06 04:59:17Z essej $ +*/ + +#include +#include +#include + +#include +#include +#include + +using namespace std; +using namespace MIDI; + +JACK_MidiPort::JACK_MidiPort(PortRequest & req, jack_client_t* jack_client) + : Port(req) + , _jack_client(jack_client) + , _jack_input_port(NULL) + , _jack_output_port(NULL) + , _last_read_index(0) +{ + int err = create_ports(req); + + if (!err) { + req.status = PortRequest::OK; + _ok = true; + } else { + req.status = PortRequest::Unknown; + } +} + +JACK_MidiPort::~JACK_MidiPort() +{ + // FIXME: remove port +} + +void +JACK_MidiPort::cycle_start (nframes_t nframes) +{ + Port::cycle_start(nframes); + assert(_nframes_this_cycle == nframes); + _last_read_index = 0; + jack_midi_clear_buffer(jack_port_get_buffer(_jack_output_port, nframes), nframes); +} + +int +JACK_MidiPort::write(byte * msg, size_t msglen, timestamp_t timestamp) +{ + assert(_currently_in_cycle); + assert(timestamp < _nframes_this_cycle); + assert(_jack_output_port); + + // FIXME: return value correct? + return jack_midi_event_write ( + jack_port_get_buffer(_jack_output_port, _nframes_this_cycle), + timestamp, msg, msglen, _nframes_this_cycle); +} + +int +JACK_MidiPort::read(byte * buf, size_t max, timestamp_t timestamp) +{ + assert(_currently_in_cycle); + assert(timestamp < _nframes_this_cycle); + assert(_jack_input_port); + + jack_midi_event_t ev; + + int err = jack_midi_event_get (&ev, + jack_port_get_buffer(_jack_input_port, _nframes_this_cycle), + _last_read_index++, _nframes_this_cycle); + + if (!err) { + memcpy(buf, ev.buffer, ev.size); + return ev.size; + } else { + return 0; + } +} + +int +JACK_MidiPort::create_ports(PortRequest & req) +{ + assert(!_jack_input_port); + assert(!_jack_output_port); + + jack_nframes_t nframes = jack_get_buffer_size(_jack_client); + + bool ret = true; + + if (req.mode == O_RDWR || req.mode == O_WRONLY) { + _jack_output_port = jack_port_register(_jack_client, + string(req.tagname).append("_out").c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsOutput, 0); + jack_midi_reset_new_port( + jack_port_get_buffer(_jack_output_port, nframes), nframes); + ret = ret && (_jack_output_port != NULL); + } + + if (req.mode == O_RDWR || req.mode == O_RDONLY) { + _jack_input_port = jack_port_register(_jack_client, + string(req.tagname).append("_in").c_str(), + JACK_DEFAULT_MIDI_TYPE, JackPortIsInput, 0); + jack_midi_reset_new_port( + jack_port_get_buffer(_jack_input_port, nframes), nframes); + ret = ret && (_jack_input_port != NULL); + } + + return ret ? 0 : -1; +} + diff --git a/libs/midi++2/midi++/jack.h b/libs/midi++2/midi++/jack.h new file mode 100644 index 0000000000..c20b2693f1 --- /dev/null +++ b/libs/midi++2/midi++/jack.h @@ -0,0 +1,68 @@ +/* + Copyright (C) 2006 Paul Davis + Written by Dave Robillard + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: jack.h 4 2005-05-13 20:47:18Z taybin $ +*/ + +#ifndef __jack_midiport_h__ +#define __jack_midiport_h__ + +#include +#include + +#include +#include + +#include +#include +#include + +namespace MIDI +{ + + +class JACK_MidiPort : public Port +{ +public: + JACK_MidiPort (PortRequest &req, jack_client_t* jack_client); + virtual ~JACK_MidiPort (); + + /* No select(2)/poll(2)-based I/O */ + virtual int selectable() const { return -1; } + + virtual void cycle_start(nframes_t nframes); + +protected: + /* Direct I/O */ + int write(byte *msg, size_t msglen, timestamp_t timestamp); + int read(byte *buf, size_t max, timestamp_t timestamp); + +private: + int create_ports(PortRequest &req); + + jack_client_t* _jack_client; + jack_port_t* _jack_input_port; + jack_port_t* _jack_output_port; + nframes_t _last_read_index; +}; + + +} /* namespace MIDI */ + +#endif // __jack_midiport_h__ +