756b4a6473
devices to be used as well - add jack output. these patches are back ported from hydrogen subversion. discussed with MAINTAINER
230 lines
9.4 KiB
Plaintext
230 lines
9.4 KiB
Plaintext
$OpenBSD: patch-src_lib_drivers_JackDriver_cpp,v 1.1 2008/03/24 03:09:42 jakemsr Exp $
|
|
--- src/lib/drivers/JackDriver.cpp.orig Fri Feb 29 17:46:02 2008
|
|
+++ src/lib/drivers/JackDriver.cpp Sat Mar 1 00:21:04 2008
|
|
@@ -59,8 +59,10 @@ JackDriver::JackDriver(JackProcessCallback processCall
|
|
{
|
|
infoLog( "INIT" );
|
|
jackDriverInstance = this;
|
|
- track_out_flag = true;
|
|
this->processCallback = processCallback;
|
|
+
|
|
+ must_relocate = 0;
|
|
+ bbt_frame_offset = 0;
|
|
}
|
|
|
|
|
|
@@ -94,14 +96,25 @@ int JackDriver::connect()
|
|
|
|
if ( connect_out_flag ) {
|
|
// connect the ports
|
|
- if ( jack_connect ( client, jack_port_name( output_port_1 ), output_port_name_1.c_str() ) ) {
|
|
- ( Hydrogen::getInstance() )->raiseError( Hydrogen::JACK_CANNOT_CONNECT_OUTPUT_PORT );
|
|
+ if ( jack_connect ( client, jack_port_name( output_port_1 ), output_port_name_1.c_str() ) == 0 &&
|
|
+ jack_connect ( client, jack_port_name( output_port_2 ), output_port_name_2.c_str() ) == 0 ) {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ infoLog("Could not connect to saved out-ports. Connecting to first pair of in-ports");
|
|
+ const char ** portnames = jack_get_ports ( client, NULL, NULL, JackPortIsInput );
|
|
+ if ( !portnames || !portnames[0] || !portnames[1] ) {
|
|
+ errorLog( "Couldn't locate two Jack input ports" );
|
|
+ Hydrogen::getInstance()->raiseError( Hydrogen::JACK_CANNOT_CONNECT_OUTPUT_PORT );
|
|
return 2;
|
|
}
|
|
- if ( jack_connect ( client, jack_port_name( output_port_2 ), output_port_name_2.c_str() ) ) {
|
|
- ( Hydrogen::getInstance() )->raiseError( Hydrogen::JACK_CANNOT_CONNECT_OUTPUT_PORT );
|
|
+ if ( jack_connect ( client, jack_port_name( output_port_1 ), portnames[0] ) != 0 ||
|
|
+ jack_connect ( client, jack_port_name( output_port_2 ), portnames[1] ) != 0 ) {
|
|
+ errorLog( "Couldn't connect to first pair of Jack input ports" );
|
|
+ Hydrogen::getInstance()->raiseError( Hydrogen::JACK_CANNOT_CONNECT_OUTPUT_PORT );
|
|
return 2;
|
|
}
|
|
+ free( portnames );
|
|
}
|
|
|
|
return 0;
|
|
@@ -159,9 +172,61 @@ unsigned JackDriver::getSampleRate()
|
|
return jack_server_sampleRate;
|
|
}
|
|
|
|
+void JackDriver::calculateFrameOffset()
|
|
+{
|
|
+ bbt_frame_offset = m_JackTransportPos.frame - m_transport.m_nFrames;
|
|
+}
|
|
|
|
|
|
|
|
+/// Take beat-bar-tick info from the Jack system, and translate it to a new internal frame position and ticksize.
|
|
+void JackDriver::relocateBBT()
|
|
+{
|
|
+ if ( m_transport.m_status != TransportInfo::ROLLING || !( m_JackTransportPos.valid & JackPositionBBT ) /**the last check is *probably* redundant*/ ) return;
|
|
+
|
|
+ Hydrogen * H = Hydrogen::getInstance();
|
|
+ Song * S = H->getSong();
|
|
+
|
|
+ float hydrogen_TPB = ( float )S->m_nResolution;
|
|
+
|
|
+ long bar_ticks = 0;
|
|
+ if ( S->getMode() == Song::SONG_MODE ) {
|
|
+ bar_ticks = H->getTickForPosition( m_JackTransportPos.bar ); // (Reasonable?) assumption that one pattern is _always_ 1 bar long!
|
|
+ if ( bar_ticks < 0 ) bar_ticks = 0; // ignore error NOTE This is wrong -- if loop state is off, transport should just stop ??
|
|
+ }
|
|
+ float hydrogen_ticks_to_locate = bar_ticks + ( m_JackTransportPos.beat-1 )*hydrogen_TPB + m_JackTransportPos.tick*( hydrogen_TPB/m_JackTransportPos.ticks_per_beat );
|
|
+
|
|
+ // char bbt[15];
|
|
+ // sprintf( bbt, "[%d,%d,%d]", m_JackTransportPos.bar, m_JackTransportPos.beat, m_JackTransportPos.tick );
|
|
+ string bbt;
|
|
+ bbt = "[" + toString(m_JackTransportPos.bar) +
|
|
+ "," + toString(m_JackTransportPos.beat) +
|
|
+ "," + toString(m_JackTransportPos.tick) + "]";
|
|
+ warningLog( "Locating BBT: " + bbt + /*" -- Tx/Beat = "+toString(m_JackTransportPos.ticks_per_beat)+", Meter "+toString(m_JackTransportPos.beats_per_bar)+"/"+toString(m_JackTransportPos.beat_type)+*/" =>tick " + toString( hydrogen_ticks_to_locate ) );
|
|
+
|
|
+ float fNewTickSize = getSampleRate() * 60.0 / m_transport.m_nBPM / S->m_nResolution;;
|
|
+ // not S->m_fBPM !??
|
|
+
|
|
+ if ( fNewTickSize == 0 ) return; // ??!?
|
|
+
|
|
+ // NOTE this _should_ prevent audioEngine_process_checkBPMChanged in Hydrogen.cpp from recalculating things.
|
|
+ m_transport.m_nTickSize = fNewTickSize;
|
|
+
|
|
+ long long nNewFrames = ( long long )( hydrogen_ticks_to_locate * fNewTickSize );
|
|
+ if ( m_JackTransportPos.valid & JackBBTFrameOffset )
|
|
+ nNewFrames += m_JackTransportPos.bbt_offset;
|
|
+ m_transport.m_nFrames = nNewFrames;
|
|
+
|
|
+ /// offset between jack- and internal position
|
|
+ calculateFrameOffset();
|
|
+
|
|
+}
|
|
+
|
|
+///
|
|
+/// When jack_transport_start() is called, it takes effect from the next processing cycle.
|
|
+/// The location info from the timebase_master, if there is one, will not be available until the _next_ next cycle.
|
|
+/// The code must therefore wait one cycle before syncing up with timebase_master.
|
|
+///
|
|
void JackDriver::updateTransportInfo()
|
|
{
|
|
if (Preferences::getInstance()->m_bJackTransportMode == Preferences::USE_JACK_TRANSPORT) {
|
|
@@ -175,6 +240,10 @@ void JackDriver::updateTransportInfo()
|
|
break;
|
|
|
|
case JackTransportRolling:
|
|
+ if ( m_transport.m_status != TransportInfo::ROLLING && ( m_JackTransportPos.valid & JackPositionBBT ) ) {
|
|
+ must_relocate = 2;
|
|
+ warningLog( "Jack transport starting: Resyncing in 2 x Buffersize!!" );
|
|
+ }
|
|
m_transport.m_status = TransportInfo::ROLLING;
|
|
//infoLog( "[updateTransportInfo] ROLLING - frames: " + toString(m_transportPos.frame) );
|
|
break;
|
|
@@ -189,22 +258,37 @@ void JackDriver::updateTransportInfo()
|
|
}
|
|
|
|
|
|
-/*
|
|
// FIXME
|
|
// TickSize and BPM
|
|
if ( m_JackTransportPos.valid & JackPositionBBT ) {
|
|
- if ( m_transport.m_nBPM != m_JackTransportPos.beats_per_minute ) {
|
|
- m_transport.m_nBPM = m_JackTransportPos.beats_per_minute;
|
|
- (Hydrogen::getInstance())->getSong()->m_fBPM = m_JackTransportPos.beats_per_minute;
|
|
- warningLog( "[updateTransportInfo] new BPM from jack-transport: " + toString(m_JackTransportPos.beats_per_minute) );
|
|
+ float bpm = ( float )m_JackTransportPos.beats_per_minute;
|
|
+ if ( m_transport.m_nBPM != bpm ) {
|
|
+
|
|
+ warningLog( "Tempo change from jack-transport: " + toString( bpm ) );
|
|
+
|
|
+ m_transport.m_nBPM = bpm;
|
|
+
|
|
+ must_relocate = 1; // The tempo change has happened somewhere during the previous cycle; relocate right away.
|
|
+
|
|
+ // Hydrogen::getInstance()->setBPM( m_JackTransportPos.beats_per_minute ); // unnecessary, as Song->m_BPM gets updated in audioEngine_process_transport (after calling this function)
|
|
}
|
|
}
|
|
-*/
|
|
|
|
- if ( m_transport.m_nFrames != m_JackTransportPos.frame ) {
|
|
- m_transport.m_nFrames = m_JackTransportPos.frame;
|
|
- warningLog( "[updateTransportInfo] internal frames != jack transport frames. resync!" );
|
|
+ if ( m_transport.m_nFrames + bbt_frame_offset != m_JackTransportPos.frame ) {
|
|
+ if ( ( m_JackTransportPos.valid & JackPositionBBT ) && must_relocate == 0 ) {
|
|
+ warningLog( "Frame offset mismatch; triggering resync in 2 cycles" );
|
|
+ must_relocate = 2;
|
|
+ } else { // NOTE There's no timebase_master. If audioEngine_process_checkBPMChanged handled a tempo change during last cycle, the offset doesn't match.
|
|
+ m_transport.m_nFrames = m_JackTransportPos.frame - bbt_frame_offset;
|
|
+// bbt_frame_offset = 0;
|
|
+ }
|
|
}
|
|
+ if ( must_relocate == 1 ) {
|
|
+ warningLog( "Resyncing!" );
|
|
+ relocateBBT();
|
|
+ }
|
|
+
|
|
+ if ( must_relocate > 0 ) must_relocate--;
|
|
}
|
|
}
|
|
|
|
@@ -242,6 +326,11 @@ int JackDriver::init(unsigned nBufferSize)
|
|
output_port_name_1 = Preferences::getInstance()->m_sJackPortName1;
|
|
output_port_name_2 = Preferences::getInstance()->m_sJackPortName2;
|
|
|
|
+ if ( ( client = jack_client_open( "hydrogen", JackNullOption, NULL ) ) == NULL ) {
|
|
+ warningLog( "Error: can't start JACK server" );
|
|
+ return 3;
|
|
+ }
|
|
+
|
|
// check if another hydrogen instance is connected to jack
|
|
if ( (client = jack_client_new( "hydrogen-tmp" ) ) == 0 ) {
|
|
warningLog("Jack server not running?");
|
|
@@ -256,7 +345,7 @@ int JackDriver::init(unsigned nBufferSize)
|
|
int nColonPos = sPort.find( ":" );
|
|
string sClient = sPort.substr( 0, nColonPos );
|
|
bool bClientExist = false;
|
|
- for ( int j = 0; j < clientList.size(); j++ ) {
|
|
+ for ( int j = 0; j < (int)clientList.size(); j++ ) {
|
|
if ( sClient == clientList[ j ] ) {
|
|
bClientExist = true;
|
|
break;
|
|
@@ -267,6 +356,7 @@ int JackDriver::init(unsigned nBufferSize)
|
|
}
|
|
nPort++;
|
|
}
|
|
+ free(readports);
|
|
jack_client_close( client );
|
|
|
|
string sClientName = "";
|
|
@@ -275,7 +365,7 @@ int JackDriver::init(unsigned nBufferSize)
|
|
// sprintf( clientName, "Hydrogen-%d", getpid() );
|
|
sClientName = "Hydrogen-" + toString( nInstance );
|
|
bool bExist = false;
|
|
- for ( int i = 0; i < clientList.size(); i++ ) {
|
|
+ for ( int i = 0; i < (int)clientList.size(); i++ ) {
|
|
if ( sClientName == clientList[ i ] ){
|
|
bExist = true;
|
|
break;
|
|
@@ -325,25 +415,6 @@ int JackDriver::init(unsigned nBufferSize)
|
|
return 4;
|
|
}
|
|
|
|
-
|
|
- /* create MAX_INSTRUMENTS dedicated channel output ports */
|
|
- if (track_out_flag) {
|
|
- char tmpbuf[255];
|
|
-
|
|
- for (unsigned int n=0; n < MAX_INSTRUMENTS; ++n) {
|
|
- snprintf (tmpbuf, sizeof(tmpbuf), "track_out_%d_L", n+1);
|
|
- track_output_ports_L[n] = jack_port_register ( client, tmpbuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
|
|
- if (track_output_ports_L[n] == NULL) {
|
|
- ( Hydrogen::getInstance() )->raiseError( Hydrogen::JACK_ERROR_IN_PORT_REGISTER );
|
|
- }
|
|
-
|
|
- snprintf (tmpbuf, sizeof(tmpbuf), "track_out_%d_R", n+1);
|
|
- track_output_ports_R[n] = jack_port_register ( client, tmpbuf, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 );
|
|
- if (track_output_ports_R[n] == NULL) {
|
|
- ( Hydrogen::getInstance() )->raiseError( Hydrogen::JACK_ERROR_IN_PORT_REGISTER );
|
|
- }
|
|
- }
|
|
- }
|
|
|
|
// clear buffers
|
|
// jack_default_audio_sample_t *out_L = (jack_default_audio_sample_t *) jack_port_get_buffer (output_port_1, jack_server_bufferSize);
|