git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@2796 0c269be4-1314-0410-8aa9-9f06e86f4224tags/1.90
| @@ -70,19 +70,19 @@ namespace Jack | |||
| return 0; | |||
| } | |||
| int JackAudioAdapter::BufferSize(jack_nframes_t buffer_size, void* arg) | |||
| int JackAudioAdapter::BufferSize ( jack_nframes_t buffer_size, void* arg ) | |||
| { | |||
| JackAudioAdapter* adapter = static_cast<JackAudioAdapter*>(arg); | |||
| adapter->Reset(); | |||
| adapter->fAudioAdapter->SetBufferSize(buffer_size); | |||
| adapter->fAudioAdapter->SetHostBufferSize ( buffer_size ); | |||
| return 0; | |||
| } | |||
| int JackAudioAdapter::SampleRate(jack_nframes_t sample_rate, void* arg) | |||
| int JackAudioAdapter::SampleRate ( jack_nframes_t sample_rate, void* arg ) | |||
| { | |||
| JackAudioAdapter* adapter = static_cast<JackAudioAdapter*>(arg); | |||
| adapter->Reset(); | |||
| adapter->fAudioAdapter->SetSampleRate(sample_rate); | |||
| adapter->fAudioAdapter->SetHostSampleRate(sample_rate); | |||
| return 0; | |||
| } | |||
| @@ -104,12 +104,12 @@ namespace Jack | |||
| void JackAudioAdapter::FreePorts() | |||
| { | |||
| int i; | |||
| for ( i = 0; i < fCaptureChannels; i++ ) | |||
| if ( fCapturePortList[i] ) | |||
| jack_port_unregister ( fJackClient, fCapturePortList[i] ); | |||
| for (i = 0; i < fCaptureChannels; i++) | |||
| if (fCapturePortList[i]) | |||
| jack_port_unregister(fJackClient, fCapturePortList[i]); | |||
| for (i = 0; i < fCaptureChannels; i++) | |||
| if (fPlaybackPortList[i]) | |||
| jack_port_unregister(fJackClient, fPlaybackPortList[i]); | |||
| if ( fPlaybackPortList[i] ) | |||
| jack_port_unregister (fJackClient, fPlaybackPortList[i] ); | |||
| delete[] fCapturePortList; | |||
| delete[] fPlaybackPortList; | |||
| @@ -127,7 +127,7 @@ namespace Jack | |||
| int JackAudioAdapter::Open() | |||
| { | |||
| jack_log("JackAudioAdapter::Open()"); | |||
| jack_log("JackAudioAdapter::Open"); | |||
| int i; | |||
| char name[32]; | |||
| @@ -138,15 +138,15 @@ namespace Jack | |||
| //ringbuffers | |||
| fCaptureRingBuffer = new JackResampler*[fCaptureChannels]; | |||
| fPlaybackRingBuffer = new JackResampler*[fPlaybackChannels]; | |||
| for (i = 0; i < fCaptureChannels; i++) | |||
| for ( i = 0; i < fCaptureChannels; i++ ) | |||
| fCaptureRingBuffer[i] = new JackLibSampleRateResampler(); | |||
| for (i = 0; i < fPlaybackChannels; i++) | |||
| for ( i = 0; i < fPlaybackChannels; i++ ) | |||
| fPlaybackRingBuffer[i] = new JackLibSampleRateResampler(); | |||
| fAudioAdapter->SetRingBuffers(fCaptureRingBuffer, fPlaybackRingBuffer); | |||
| if ( fCaptureChannels ) | |||
| jack_log("ReadSpace = %ld", fCaptureRingBuffer[0]->ReadSpace()); | |||
| jack_log ( "ReadSpace = %ld", fCaptureRingBuffer[0]->ReadSpace() ); | |||
| if ( fPlaybackChannels ) | |||
| jack_log("WriteSpace = %ld", fPlaybackRingBuffer[0]->WriteSpace()); | |||
| jack_log ( "WriteSpace = %ld", fPlaybackRingBuffer[0]->WriteSpace() ); | |||
| //jack ports | |||
| fCapturePortList = new jack_port_t* [fCaptureChannels]; | |||
| @@ -155,25 +155,25 @@ namespace Jack | |||
| for (i = 0; i < fCaptureChannels; i++) | |||
| { | |||
| sprintf(name, "capture_%d", i+1); | |||
| if ((fCapturePortList[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0)) == NULL) | |||
| if ( ( fCapturePortList[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0 ) ) == NULL ) | |||
| goto fail; | |||
| } | |||
| for (i = 0; i < fPlaybackChannels; i++) | |||
| { | |||
| sprintf(name, "playback_%d", i+1); | |||
| if ((fPlaybackPortList[i] = jack_port_register(fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0)) == NULL) | |||
| if ( ( fPlaybackPortList[i] = jack_port_register ( fJackClient, name, JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0 ) ) == NULL ) | |||
| goto fail; | |||
| } | |||
| //callbacks and activation | |||
| if (jack_set_process_callback(fJackClient, Process, this) < 0) | |||
| if ( jack_set_process_callback ( fJackClient, Process, this ) < 0 ) | |||
| goto fail; | |||
| if (jack_set_buffer_size_callback(fJackClient, BufferSize, this) < 0) | |||
| if ( jack_set_buffer_size_callback ( fJackClient, BufferSize, this ) < 0 ) | |||
| goto fail; | |||
| if (jack_set_sample_rate_callback(fJackClient, SampleRate, this) < 0) | |||
| if ( jack_set_sample_rate_callback ( fJackClient, SampleRate, this ) < 0 ) | |||
| goto fail; | |||
| if (jack_activate(fJackClient) < 0) | |||
| if ( jack_activate ( fJackClient ) < 0 ) | |||
| goto fail; | |||
| //ringbuffers and jack clients are ok, we can now open the adapter driver interface | |||
| @@ -25,120 +25,120 @@ namespace Jack | |||
| #ifdef JACK_MONITOR | |||
| void MeasureTable::Write(int time1, int time2, float r1, float r2, int pos1, int pos2) | |||
| { | |||
| int pos = (++fCount) % TABLE_MAX; | |||
| fTable[pos].time1 = time1; | |||
| fTable[pos].time2 = time2; | |||
| fTable[pos].r1 = r1; | |||
| fTable[pos].r2 = r2; | |||
| fTable[pos].pos1 = pos1; | |||
| fTable[pos].pos2 = pos2; | |||
| } | |||
| void MeasureTable::Save() | |||
| { | |||
| char buffer[1024]; | |||
| FILE* file = fopen("JackAudioAdapter.log", "w"); | |||
| int MAX = (fCount) % TABLE_MAX - 1; | |||
| for (int i = 1; i < MAX; i++) { | |||
| fprintf(file, "%d \t %d \t %d \t %f \t %f \t %d \t %d \n", | |||
| fTable[i].delta, fTable[i+1].time1 - fTable[i].time1, | |||
| fTable[i+1].time2 - fTable[i].time2, | |||
| fTable[i].r1, fTable[i].r2, fTable[i].pos1, fTable[i].pos2); | |||
| } | |||
| fclose(file); | |||
| // Adapter timing 1 | |||
| file = fopen("AdapterTiming1.plot", "w"); | |||
| fprintf(file, "set multiplot\n"); | |||
| fprintf(file, "set grid\n"); | |||
| fprintf(file, "set title \"Audio adapter timing\"\n"); | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"frames\"\n"); | |||
| fprintf(file, "plot "); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,"); | |||
| fprintf(file, buffer); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines"); | |||
| fprintf(file, buffer); | |||
| fclose(file); | |||
| // Adapter timing 2 | |||
| file = fopen("AdapterTiming2.plot", "w"); | |||
| fprintf(file, "set multiplot\n"); | |||
| fprintf(file, "set grid\n"); | |||
| fprintf(file, "set title \"Audio adapter timing\"\n"); | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"resampling ratio\"\n"); | |||
| fprintf(file, "plot "); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,"); | |||
| fprintf(file, buffer); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines"); | |||
| fprintf(file, buffer); | |||
| fclose(file); | |||
| // Adapter timing 3 | |||
| file = fopen("AdapterTiming3.plot", "w"); | |||
| fprintf(file, "set multiplot\n"); | |||
| fprintf(file, "set grid\n"); | |||
| fprintf(file, "set title \"Audio adapter timing\"\n"); | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"frames\"\n"); | |||
| fprintf(file, "plot "); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,"); | |||
| fprintf(file, buffer); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines"); | |||
| fprintf(file, buffer); | |||
| fclose(file); | |||
| } | |||
| void MeasureTable::Write(int time1, int time2, float r1, float r2, int pos1, int pos2) | |||
| { | |||
| int pos = (++fCount) % TABLE_MAX; | |||
| fTable[pos].time1 = time1; | |||
| fTable[pos].time2 = time2; | |||
| fTable[pos].r1 = r1; | |||
| fTable[pos].r2 = r2; | |||
| fTable[pos].pos1 = pos1; | |||
| fTable[pos].pos2 = pos2; | |||
| } | |||
| void MeasureTable::Save() | |||
| { | |||
| char buffer[1024]; | |||
| FILE* file = fopen("JackAudioAdapter.log", "w"); | |||
| int MAX = (fCount) % TABLE_MAX - 1; | |||
| for (int i = 1; i < MAX; i++) | |||
| { | |||
| fprintf(file, "%d \t %d \t %d \t %f \t %f \t %d \t %d \n", | |||
| fTable[i].delta, fTable[i+1].time1 - fTable[i].time1, | |||
| fTable[i+1].time2 - fTable[i].time2, | |||
| fTable[i].r1, fTable[i].r2, fTable[i].pos1, fTable[i].pos2); | |||
| } | |||
| fclose(file); | |||
| // Adapter timing 1 | |||
| file = fopen("AdapterTiming1.plot", "w"); | |||
| fprintf(file, "set multiplot\n"); | |||
| fprintf(file, "set grid\n"); | |||
| fprintf(file, "set title \"Audio adapter timing\"\n"); | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"frames\"\n"); | |||
| fprintf(file, "plot "); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 2 title \"Consumer interrupt period\" with lines,"); | |||
| fprintf(file, buffer); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 3 title \"Producer interrupt period\" with lines"); | |||
| fprintf(file, buffer); | |||
| fclose(file); | |||
| // Adapter timing 2 | |||
| file = fopen("AdapterTiming2.plot", "w"); | |||
| fprintf(file, "set multiplot\n"); | |||
| fprintf(file, "set grid\n"); | |||
| fprintf(file, "set title \"Audio adapter timing\"\n"); | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"resampling ratio\"\n"); | |||
| fprintf(file, "plot "); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 4 title \"Ratio 1\" with lines,"); | |||
| fprintf(file, buffer); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 5 title \"Ratio 2\" with lines"); | |||
| fprintf(file, buffer); | |||
| fclose(file); | |||
| // Adapter timing 3 | |||
| file = fopen("AdapterTiming3.plot", "w"); | |||
| fprintf(file, "set multiplot\n"); | |||
| fprintf(file, "set grid\n"); | |||
| fprintf(file, "set title \"Audio adapter timing\"\n"); | |||
| fprintf(file, "set xlabel \"audio cycles\"\n"); | |||
| fprintf(file, "set ylabel \"frames\"\n"); | |||
| fprintf(file, "plot "); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 6 title \"Frames position in consumer ringbuffer\" with lines,"); | |||
| fprintf(file, buffer); | |||
| sprintf(buffer, "\"JackAudioAdapter.log\" using 7 title \"Frames position in producer ringbuffer\" with lines"); | |||
| fprintf(file, buffer); | |||
| fclose(file); | |||
| } | |||
| #endif | |||
| void JackAudioAdapterInterface::ResetRingBuffers() | |||
| { | |||
| int i; | |||
| for (i = 0; i < fCaptureChannels; i++) { | |||
| fCaptureRingBuffer[i]->Reset(); | |||
| void JackAudioAdapterInterface::ResetRingBuffers() | |||
| { | |||
| int i; | |||
| for (i = 0; i < fCaptureChannels; i++) | |||
| fCaptureRingBuffer[i]->Reset(); | |||
| for (i = 0; i < fPlaybackChannels; i++) | |||
| fPlaybackRingBuffer[i]->Reset(); | |||
| } | |||
| for (i = 0; i < fPlaybackChannels; i++) { | |||
| fPlaybackRingBuffer[i]->Reset(); | |||
| void JackAudioAdapterInterface::ResampleFactor ( jack_nframes_t& frame1, jack_nframes_t& frame2 ) | |||
| { | |||
| jack_time_t time = jack_get_time(); | |||
| if ( !fRunning ) | |||
| { | |||
| // Init DLL | |||
| fRunning = true; | |||
| fHostDLL.Init ( time ); | |||
| fAdaptedDLL.Init ( time ); | |||
| frame1 = 1; | |||
| frame2 = 1; | |||
| } | |||
| else | |||
| { | |||
| // DLL | |||
| fAdaptedDLL.IncFrame(time); | |||
| jack_nframes_t time1 = fHostDLL.Time2Frames(time); | |||
| jack_nframes_t time2 = fAdaptedDLL.Time2Frames(time); | |||
| frame1 = time1; | |||
| frame2 = time2; | |||
| jack_log("JackAudioAdapterInterface::ResampleFactor time1 = %ld time2 = %ld src_ratio_input = %f src_ratio_output = %f", | |||
| long(time1), long(time2), double(time1) / double(time2), double(time2) / double(time1)); | |||
| } | |||
| } | |||
| } | |||
| void JackAudioAdapterInterface::ResampleFactor(jack_nframes_t& frame1, jack_nframes_t& frame2) | |||
| { | |||
| jack_time_t time = jack_get_time(); | |||
| if (!fRunning) { | |||
| // Init DLL | |||
| fRunning = true; | |||
| fProducerDLL.Init(time); | |||
| fConsumerDLL.Init(time); | |||
| frame1 = 1; | |||
| frame2 = 1; | |||
| } else { | |||
| // DLL | |||
| fProducerDLL.IncFrame(time); | |||
| jack_nframes_t time1 = fConsumerDLL.Time2Frames(time); | |||
| jack_nframes_t time2 = fProducerDLL.Time2Frames(time); | |||
| frame1 = time1; | |||
| frame2 = time2; | |||
| jack_log("JackAudioAdapterInterface::ResampleFactor time1 = %ld time2 = %ld src_ratio_input = %f src_ratio_output = %f", | |||
| long(time1), long(time2), double(time1) / double(time2), double(time2) / double(time1)); | |||
| int JackAudioAdapterInterface::Open() | |||
| { | |||
| return 0; | |||
| } | |||
| } | |||
| int JackAudioAdapterInterface::Open() | |||
| { | |||
| return 0; | |||
| } | |||
| int JackAudioAdapterInterface::Close() | |||
| { | |||
| return 0; | |||
| } | |||
| int JackAudioAdapterInterface::Close() | |||
| { | |||
| return 0; | |||
| } | |||
| } // namespace | |||
| @@ -72,138 +72,142 @@ namespace Jack | |||
| class JackAudioAdapterInterface | |||
| { | |||
| protected: | |||
| protected: | |||
| #ifdef JACK_MONITOR | |||
| MeasureTable fTable; | |||
| MeasureTable fTable; | |||
| #endif | |||
| //channels | |||
| int fCaptureChannels; | |||
| int fPlaybackChannels; | |||
| //host parameters | |||
| jack_nframes_t fHostBufferSize; | |||
| jack_nframes_t fHostSampleRate; | |||
| //adapted parameters | |||
| jack_nframes_t fAdaptedBufferSize; | |||
| jack_nframes_t fAdaptedSampleRate; | |||
| //delay locked loop | |||
| JackAtomicDelayLockedLoop fHostDLL; | |||
| JackAtomicDelayLockedLoop fAdaptedDLL; | |||
| JackResampler** fCaptureRingBuffer; | |||
| JackResampler** fPlaybackRingBuffer; | |||
| bool fRunning; | |||
| public: | |||
| JackAudioAdapterInterface ( jack_nframes_t buffer_size, jack_nframes_t sample_rate ) : | |||
| fCaptureChannels ( 0 ), | |||
| fPlaybackChannels ( 0 ), | |||
| fHostBufferSize ( buffer_size ), | |||
| fHostSampleRate ( sample_rate ), | |||
| fAdaptedBufferSize ( buffer_size), | |||
| fAdaptedSampleRate ( sample_rate ), | |||
| fHostDLL ( buffer_size, sample_rate ), | |||
| fAdaptedDLL ( buffer_size, sample_rate ), | |||
| fRunning ( false ) | |||
| {} | |||
| virtual ~JackAudioAdapterInterface() | |||
| {} | |||
| int fCaptureChannels; | |||
| int fPlaybackChannels; | |||
| jack_nframes_t fBufferSize; | |||
| jack_nframes_t fSampleRate; | |||
| // DLL | |||
| JackAtomicDelayLockedLoop fProducerDLL; | |||
| JackAtomicDelayLockedLoop fConsumerDLL; | |||
| JackResampler** fCaptureRingBuffer; | |||
| JackResampler** fPlaybackRingBuffer; | |||
| bool fRunning; | |||
| public: | |||
| JackAudioAdapterInterface ( jack_nframes_t buffer_size, jack_nframes_t sample_rate ) | |||
| :fCaptureChannels ( 0 ), | |||
| fPlaybackChannels ( 0 ), | |||
| fBufferSize ( buffer_size ), | |||
| fSampleRate ( sample_rate ), | |||
| fProducerDLL ( buffer_size, sample_rate ), | |||
| fConsumerDLL ( buffer_size, sample_rate ), | |||
| fRunning ( false ) | |||
| {} | |||
| virtual ~JackAudioAdapterInterface() | |||
| {} | |||
| void SetRingBuffers ( JackResampler** input, JackResampler** output ) | |||
| { | |||
| fCaptureRingBuffer = input; | |||
| fPlaybackRingBuffer = output; | |||
| } | |||
| bool IsRunning() {return fRunning;} | |||
| virtual void Reset() {fRunning = false;} | |||
| void ResetRingBuffers(); | |||
| virtual int Open(); | |||
| virtual int Close(); | |||
| virtual int SetBufferSize ( jack_nframes_t buffer_size ) | |||
| { | |||
| fBufferSize = buffer_size; | |||
| fConsumerDLL.Init ( fBufferSize, fSampleRate ); | |||
| fProducerDLL.Init ( fBufferSize, fSampleRate ); | |||
| return 0; | |||
| } | |||
| virtual int SetHostBufferSize ( jack_nframes_t buffer_size ) | |||
| { | |||
| fBufferSize = buffer_size; | |||
| fConsumerDLL.Init ( fBufferSize, fSampleRate ); | |||
| return 0; | |||
| } | |||
| virtual int SetAdaptedBufferSize ( jack_nframes_t buffer_size ) | |||
| { | |||
| fProducerDLL.Init ( buffer_size, fSampleRate ); | |||
| return 0; | |||
| } | |||
| //TODO : switch the two next methods to SetHost/AdaptedBufferSize in adapters | |||
| virtual int SetSampleRate ( jack_nframes_t sample_rate ) | |||
| { | |||
| fSampleRate = sample_rate; | |||
| fConsumerDLL.Init ( fBufferSize, fSampleRate ); | |||
| // Producer (Audio) keeps the same SR | |||
| return 0; | |||
| } | |||
| virtual int SetAudioSampleRate ( jack_nframes_t sample_rate ) | |||
| { | |||
| fSampleRate = sample_rate; | |||
| // Consumer keeps the same SR | |||
| fProducerDLL.Init ( fBufferSize, fSampleRate ); | |||
| return 0; | |||
| } | |||
| //host = driver that hosts the adapter | |||
| virtual int SetHostSampleRate ( jack_nframes_t sample_rate ) | |||
| { | |||
| fSampleRate = sample_rate; | |||
| fConsumerDLL.Init ( fBufferSize, fSampleRate ); | |||
| return 0; | |||
| } | |||
| //adapted = driver hosted by the adapter | |||
| virtual int SetAdaptedSampleRate ( jack_nframes_t sample_rate ) | |||
| { | |||
| fProducerDLL.Init ( fBufferSize, fSampleRate ); | |||
| return 0; | |||
| } | |||
| virtual void SetCallbackTime ( jack_time_t callback_usec ) | |||
| { | |||
| fConsumerDLL.IncFrame ( callback_usec ); | |||
| } | |||
| void ResampleFactor ( jack_nframes_t& frame1, jack_nframes_t& frame2 ); | |||
| void SetInputs ( int inputs ) | |||
| { | |||
| jack_log ( "JackAudioAdapterInterface::SetInputs %d", inputs ); | |||
| fCaptureChannels = inputs; | |||
| } | |||
| void SetOutputs ( int outputs ) | |||
| { | |||
| jack_log ( "JackAudioAdapterInterface::SetOutputs %d", outputs ); | |||
| fPlaybackChannels = outputs; | |||
| } | |||
| int GetInputs() | |||
| { | |||
| jack_log ( "JackAudioAdapterInterface::GetInputs %d", fCaptureChannels ); | |||
| return fCaptureChannels; | |||
| } | |||
| int GetOutputs() | |||
| { | |||
| jack_log ( "JackAudioAdapterInterface::GetOutputs %d", fPlaybackChannels ); | |||
| return fPlaybackChannels; | |||
| } | |||
| void SetRingBuffers ( JackResampler** input, JackResampler** output ) | |||
| { | |||
| fCaptureRingBuffer = input; | |||
| fPlaybackRingBuffer = output; | |||
| } | |||
| bool IsRunning() | |||
| { | |||
| return fRunning; | |||
| } | |||
| virtual void Reset() | |||
| { | |||
| fRunning = false; | |||
| } | |||
| void ResetRingBuffers(); | |||
| virtual int Open(); | |||
| virtual int Close(); | |||
| virtual int SetHostBufferSize ( jack_nframes_t buffer_size ) | |||
| { | |||
| fHostBufferSize = buffer_size; | |||
| fHostDLL.Init ( fHostBufferSize, fHostSampleRate ); | |||
| return 0; | |||
| } | |||
| virtual int SetAdaptedBufferSize ( jack_nframes_t buffer_size ) | |||
| { | |||
| fAdaptedBufferSize = buffer_size; | |||
| fAdaptedDLL.Init ( fAdaptedBufferSize, fAdaptedSampleRate ); | |||
| return 0; | |||
| } | |||
| virtual int SetBufferSize ( jack_nframes_t buffer_size ) | |||
| { | |||
| SetHostBufferSize ( buffer_size ); | |||
| SetAdaptedBufferSize ( buffer_size ); | |||
| return 0; | |||
| } | |||
| virtual int SetHostSampleRate ( jack_nframes_t sample_rate ) | |||
| { | |||
| fHostSampleRate = sample_rate; | |||
| fHostDLL.Init ( fHostBufferSize, fHostSampleRate ); | |||
| return 0; | |||
| } | |||
| virtual int SetAdaptedSampleRate ( jack_nframes_t sample_rate ) | |||
| { | |||
| fAdaptedSampleRate = sample_rate; | |||
| fAdaptedDLL.Init ( fAdaptedBufferSize, fAdaptedSampleRate ); | |||
| return 0; | |||
| } | |||
| virtual int SetSampleRate ( jack_nframes_t sample_rate ) | |||
| { | |||
| SetHostSampleRate ( sample_rate ); | |||
| SetAdaptedSampleRate ( sample_rate ); | |||
| return 0; | |||
| } | |||
| virtual void SetCallbackTime ( jack_time_t callback_usec ) | |||
| { | |||
| fHostDLL.IncFrame ( callback_usec ); | |||
| } | |||
| void ResampleFactor ( jack_nframes_t& frame1, jack_nframes_t& frame2 ); | |||
| void SetInputs ( int inputs ) | |||
| { | |||
| jack_log ( "JackAudioAdapterInterface::SetInputs %d", inputs ); | |||
| fCaptureChannels = inputs; | |||
| } | |||
| void SetOutputs ( int outputs ) | |||
| { | |||
| jack_log ( "JackAudioAdapterInterface::SetOutputs %d", outputs ); | |||
| fPlaybackChannels = outputs; | |||
| } | |||
| int GetInputs() | |||
| { | |||
| jack_log ( "JackAudioAdapterInterface::GetInputs %d", fCaptureChannels ); | |||
| return fCaptureChannels; | |||
| } | |||
| int GetOutputs() | |||
| { | |||
| jack_log ( "JackAudioAdapterInterface::GetOutputs %d", fPlaybackChannels ); | |||
| return fPlaybackChannels; | |||
| } | |||
| }; | |||
| @@ -178,7 +178,7 @@ namespace Jack | |||
| int JackNetAdapter::SetBufferSize ( jack_nframes_t buffer_size ) | |||
| { | |||
| JackAudioAdapterInterface::SetHostBufferSize ( buffer_size ); | |||
| JackAudioAdapterInterface::SetHostBufferSize ( buffer_size ); | |||
| return 0; | |||
| } | |||
| @@ -210,7 +210,8 @@ namespace Jack | |||
| } | |||
| //set audio adapter parameters | |||
| JackAudioAdapterInterface::SetAdaptedBufferSize ( fParams.fPeriodSize ); | |||
| SetAdaptedBufferSize ( fParams.fPeriodSize ); | |||
| SetAdaptedSampleRate ( fParams.fSampleRate ); | |||
| //init done, display parameters | |||
| SessionParamsDisplay ( &fParams ); | |||
| @@ -278,14 +279,14 @@ namespace Jack | |||
| for ( port_index = 0; port_index < fCaptureChannels; port_index++ ) | |||
| { | |||
| fCaptureRingBuffer[port_index]->SetRatio ( time1, time2 ); | |||
| if ( fCaptureRingBuffer[port_index]->WriteResample ( fSoftCaptureBuffer[port_index], fParams.fPeriodSize ) < fParams.fPeriodSize ) | |||
| if ( fCaptureRingBuffer[port_index]->WriteResample ( fSoftCaptureBuffer[port_index], fAdaptedBufferSize ) < fAdaptedBufferSize ) | |||
| failure = true; | |||
| } | |||
| //and output data, | |||
| for ( port_index = 0; port_index < fPlaybackChannels; port_index++ ) | |||
| { | |||
| fPlaybackRingBuffer[port_index]->SetRatio ( time2, time1 ); | |||
| if ( fPlaybackRingBuffer[port_index]->ReadResample ( fSoftPlaybackBuffer[port_index], fParams.fPeriodSize ) < fParams.fPeriodSize ) | |||
| if ( fPlaybackRingBuffer[port_index]->ReadResample ( fSoftPlaybackBuffer[port_index], fAdaptedBufferSize ) < fAdaptedBufferSize ) | |||
| failure = true; | |||
| } | |||
| @@ -30,46 +30,50 @@ namespace Jack | |||
| JackAlsaAdapter::JackAlsaAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params) | |||
| :JackAudioAdapterInterface(buffer_size, sample_rate) | |||
| ,fThread(this), fAudioInterface(GetInputs(), GetOutputs(), buffer_size, sample_rate) | |||
| ,fThread(this), fAudioInterface(GetInputs(), GetOutputs(), buffer_size, sample_rate) | |||
| { | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| fCaptureChannels = 2; | |||
| fPlaybackChannels = 2; | |||
| for (node = params; node; node = jack_slist_next(node)) { | |||
| param = (const jack_driver_param_t*) node->data; | |||
| switch (param->character) { | |||
| case 'i': | |||
| fCaptureChannels = param->value.ui; | |||
| break; | |||
| case 'o': | |||
| fPlaybackChannels = param->value.ui; | |||
| break; | |||
| case 'C': | |||
| break; | |||
| case 'P': | |||
| break; | |||
| case 'D': | |||
| break; | |||
| case 'n': | |||
| fAudioInterface.fPeriod = param->value.ui; | |||
| break; | |||
| case 'd': | |||
| fAudioInterface.fCardName = strdup(param->value.str); | |||
| break; | |||
| case 'r': | |||
| SetAudioSampleRate(param->value.ui); | |||
| SetAdaptedSampleRate(param->value.ui); | |||
| break; | |||
| case 'p': | |||
| SetAdaptedBufferSize(param->value.ui); | |||
| break; | |||
| } | |||
| } | |||
| @@ -77,14 +81,14 @@ namespace Jack | |||
| int JackAlsaAdapter::Open() | |||
| { | |||
| if (fAudioInterface.open() != 0) | |||
| if (fAudioInterface.open() != 0) | |||
| return -1; | |||
| if (fThread.StartSync() < 0) { | |||
| jack_error("Cannot start audioadapter thread"); | |||
| return -1; | |||
| } | |||
| fAudioInterface.longinfo(); | |||
| fThread.AcquireRealTime(JackServer::fInstance->GetEngineControl()->fPriority); | |||
| return 0; | |||
| @@ -96,7 +100,7 @@ int JackAlsaAdapter::Close() | |||
| fTable.Save(); | |||
| #endif | |||
| switch (fThread.GetStatus()) { | |||
| // Kill the thread in Init phase | |||
| case JackThread::kStarting: | |||
| case JackThread::kIniting: | |||
| @@ -105,15 +109,15 @@ int JackAlsaAdapter::Close() | |||
| return -1; | |||
| } | |||
| break; | |||
| // Stop when the thread cycle is finished | |||
| case JackThread::kRunning: | |||
| if (fThread.Stop() < 0) { | |||
| jack_error("Cannot stop thread"); | |||
| jack_error("Cannot stop thread"); | |||
| return -1; | |||
| } | |||
| break; | |||
| default: | |||
| break; | |||
| } | |||
| @@ -126,25 +130,25 @@ bool JackAlsaAdapter::Init() | |||
| fAudioInterface.write(); | |||
| return true; | |||
| } | |||
| bool JackAlsaAdapter::Execute() | |||
| { | |||
| if (fAudioInterface.read() < 0) | |||
| return false; | |||
| bool failure = false; | |||
| jack_nframes_t time1, time2; | |||
| jack_nframes_t time1, time2; | |||
| ResampleFactor(time1, time2); | |||
| for (int i = 0; i < fCaptureChannels; i++) { | |||
| fCaptureRingBuffer[i]->SetRatio(time1, time2); | |||
| if (fCaptureRingBuffer[i]->WriteResample(fAudioInterface.fInputSoftChannels[i], fBufferSize) < fBufferSize) | |||
| if (fCaptureRingBuffer[i]->WriteResample(fAudioInterface.fInputSoftChannels[i], fAdaptedBufferSize) < fAdaptedBufferSize) | |||
| failure = true; | |||
| } | |||
| for (int i = 0; i < fPlaybackChannels; i++) { | |||
| fPlaybackRingBuffer[i]->SetRatio(time2, time1); | |||
| if (fPlaybackRingBuffer[i]->ReadResample(fAudioInterface.fOutputSoftChannels[i], fBufferSize) < fBufferSize) | |||
| if (fPlaybackRingBuffer[i]->ReadResample(fAudioInterface.fOutputSoftChannels[i], fAdaptedBufferSize) < fAdaptedBufferSize) | |||
| failure = true; | |||
| } | |||
| @@ -152,10 +156,10 @@ bool JackAlsaAdapter::Execute() | |||
| fTable.Write(time1, time2, double(time1) / double(time2), double(time2) / double(time1), | |||
| fCaptureRingBuffer[0]->ReadSpace(), fPlaybackRingBuffer[0]->WriteSpace()); | |||
| #endif | |||
| if (fAudioInterface.write() < 0) | |||
| return false; | |||
| // Reset all ringbuffers in case of failure | |||
| if (failure) { | |||
| jack_error("JackAlsaAdapter::Execute ringbuffer failure... reset"); | |||
| @@ -164,13 +168,20 @@ bool JackAlsaAdapter::Execute() | |||
| return true; | |||
| } | |||
| int JackAlsaAdapter::SetSampleRate(jack_nframes_t sample_rate) | |||
| { | |||
| JackAudioAdapterInterface::SetHostSampleRate(sample_rate); | |||
| Close(); | |||
| return Open(); | |||
| } | |||
| int JackAlsaAdapter::SetBufferSize(jack_nframes_t buffer_size) | |||
| { | |||
| JackAudioAdapterInterface::SetBufferSize(buffer_size); | |||
| JackAudioAdapterInterface::SetHostBufferSize(buffer_size); | |||
| Close(); | |||
| return Open(); | |||
| } | |||
| } // namespace | |||
| #ifdef __cplusplus | |||
| @@ -183,12 +194,12 @@ extern "C" | |||
| jack_driver_desc_t *desc; | |||
| jack_driver_param_desc_t * params; | |||
| unsigned int i; | |||
| desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t)); | |||
| strcpy (desc->name, "alsa-adapter"); | |||
| desc->nparams = 8; | |||
| desc->nparams = 9; | |||
| params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); | |||
| i = 0; | |||
| strcpy(params[i].name, "capture"); | |||
| params[i].character = 'C'; | |||
| @@ -214,7 +225,7 @@ extern "C" | |||
| strcpy(params[i].value.str, "hw:0"); | |||
| strcpy(params[i].short_desc, "ALSA device name"); | |||
| strcpy(params[i].long_desc, params[i].short_desc); | |||
| i++; | |||
| strcpy (params[i].name, "rate"); | |||
| params[i].character = 'r'; | |||
| @@ -223,6 +234,14 @@ extern "C" | |||
| strcpy(params[i].short_desc, "Sample rate"); | |||
| strcpy(params[i].long_desc, params[i].short_desc); | |||
| i++; | |||
| strcpy (params[i].name, "periodsize"); | |||
| params[i].character = 'p'; | |||
| params[i].type = JackDriverParamUInt; | |||
| params[i].value.ui = 512U; | |||
| strcpy(params[i].short_desc, "Perdio size"); | |||
| strcpy(params[i].long_desc, params[i].short_desc); | |||
| i++; | |||
| strcpy(params[i].name, "nperiods"); | |||
| params[i].character = 'n'; | |||
| @@ -261,7 +280,7 @@ extern "C" | |||
| desc->params = params; | |||
| return desc; | |||
| } | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| @@ -49,32 +49,32 @@ class AudioParam | |||
| { | |||
| public: | |||
| const char* fCardName; | |||
| const char* fCardName; | |||
| unsigned int fFrequency; | |||
| int fBuffering; | |||
| int fBuffering; | |||
| unsigned int fSoftInputs; | |||
| unsigned int fSoftOutputs; | |||
| public: | |||
| AudioParam() : | |||
| AudioParam() : | |||
| fCardName("hw:0"), | |||
| fFrequency(44100), | |||
| fBuffering(512), | |||
| fSoftInputs(2), | |||
| fSoftOutputs(2) | |||
| {} | |||
| AudioParam(int input, int output, jack_nframes_t buffer_size, jack_nframes_t sample_rate) : | |||
| AudioParam(int input, int output, jack_nframes_t buffer_size, jack_nframes_t sample_rate) : | |||
| fCardName("hw:0"), | |||
| fFrequency(sample_rate), | |||
| fBuffering(buffer_size), | |||
| fSoftInputs(input), | |||
| fSoftOutputs(output) | |||
| {} | |||
| AudioParam& cardName(const char* n) { fCardName = n; return *this; } | |||
| AudioParam& frequency(int f) { fFrequency = f; return *this; } | |||
| AudioParam& buffering(int fpb) { fBuffering = fpb; return *this; } | |||
| @@ -89,44 +89,44 @@ class AudioInterface : public AudioParam | |||
| { | |||
| public: | |||
| snd_pcm_t* fOutputDevice; | |||
| snd_pcm_t* fInputDevice; | |||
| snd_pcm_t* fOutputDevice; | |||
| snd_pcm_t* fInputDevice; | |||
| snd_pcm_hw_params_t* fInputParams; | |||
| snd_pcm_hw_params_t* fOutputParams; | |||
| snd_pcm_format_t fSampleFormat; | |||
| snd_pcm_access_t fSampleAccess; | |||
| unsigned int fCardInputs; | |||
| unsigned int fCardOutputs; | |||
| unsigned int fChanInputs; | |||
| unsigned int fChanOutputs; | |||
| unsigned int fPeriod; | |||
| // interleaved mode audiocard buffers | |||
| void* fInputCardBuffer; | |||
| void* fOutputCardBuffer; | |||
| // non interleaved mode audiocard buffers | |||
| void* fInputCardChannels[256]; | |||
| void* fOutputCardChannels[256]; | |||
| // non interleaved mod, floating point software buffers | |||
| float* fInputSoftChannels[256]; | |||
| float* fOutputSoftChannels[256]; | |||
| public: | |||
| const char* cardName() { return fCardName; } | |||
| int frequency() { return fFrequency; } | |||
| int buffering() { return fBuffering; } | |||
| float** inputSoftChannels() { return fInputSoftChannels; } | |||
| float** outputSoftChannels() { return fOutputSoftChannels; } | |||
| AudioInterface(const AudioParam& ap = AudioParam()) : AudioParam(ap) | |||
| { | |||
| fInputDevice = 0; | |||
| @@ -136,7 +136,7 @@ class AudioInterface : public AudioParam | |||
| fPeriod = 2; | |||
| } | |||
| AudioInterface(int input, int output, jack_nframes_t buffer_size, jack_nframes_t sample_rate) : | |||
| AudioInterface(int input, int output, jack_nframes_t buffer_size, jack_nframes_t sample_rate) : | |||
| AudioParam(input, output, buffer_size, sample_rate) | |||
| { | |||
| fInputCardBuffer = 0; | |||
| @@ -149,7 +149,7 @@ class AudioInterface : public AudioParam | |||
| fOutputSoftChannels[i] = 0; | |||
| } | |||
| } | |||
| /** | |||
| * Open the audio interface | |||
| */ | |||
| @@ -188,7 +188,7 @@ class AudioInterface : public AudioParam | |||
| fOutputCardChannels[i] = aligned_calloc(noninterleavedBufferSize(fOutputParams), 1); | |||
| } | |||
| } | |||
| // allocation of floating point buffers needed by the dsp code | |||
| fChanInputs = max(fSoftInputs, fCardInputs); assert (fChanInputs < 256); | |||
| fChanOutputs = max(fSoftOutputs, fCardOutputs); assert (fChanOutputs < 256); | |||
| @@ -208,7 +208,7 @@ class AudioInterface : public AudioParam | |||
| } | |||
| return 0; | |||
| } | |||
| int close() | |||
| { | |||
| snd_pcm_hw_params_free(fInputParams); | |||
| @@ -240,26 +240,26 @@ class AudioInterface : public AudioParam | |||
| free(fInputCardBuffer); | |||
| if (fOutputCardBuffer) | |||
| free(fOutputCardBuffer); | |||
| return 0; | |||
| } | |||
| int setAudioParams(snd_pcm_t* stream, snd_pcm_hw_params_t* params) | |||
| { | |||
| { | |||
| int err; | |||
| // set params record with initial values | |||
| err = snd_pcm_hw_params_any ( stream, params ); | |||
| err = snd_pcm_hw_params_any ( stream, params ); | |||
| check_error_msg(err, "unable to init parameters") | |||
| // set alsa access mode (and fSampleAccess field) either to non interleaved or interleaved | |||
| err = snd_pcm_hw_params_set_access (stream, params, SND_PCM_ACCESS_RW_NONINTERLEAVED ); | |||
| if (err) { | |||
| err = snd_pcm_hw_params_set_access (stream, params, SND_PCM_ACCESS_RW_INTERLEAVED ); | |||
| check_error_msg(err, "unable to set access mode neither to non-interleaved or to interleaved"); | |||
| } | |||
| snd_pcm_hw_params_get_access(params, &fSampleAccess); | |||
| snd_pcm_hw_params_get_access(params, &fSampleAccess); | |||
| // search for 32-bits or 16-bits format | |||
| err = snd_pcm_hw_params_set_format (stream, params, SND_PCM_FORMAT_S32); | |||
| @@ -269,13 +269,13 @@ class AudioInterface : public AudioParam | |||
| } | |||
| snd_pcm_hw_params_get_format(params, &fSampleFormat); | |||
| // set sample frequency | |||
| snd_pcm_hw_params_set_rate_near (stream, params, &fFrequency, 0); | |||
| snd_pcm_hw_params_set_rate_near (stream, params, &fFrequency, 0); | |||
| // set period and period size (buffering) | |||
| err = snd_pcm_hw_params_set_period_size (stream, params, fBuffering, 0); | |||
| err = snd_pcm_hw_params_set_period_size (stream, params, fBuffering, 0); | |||
| check_error_msg(err, "period size not available"); | |||
| err = snd_pcm_hw_params_set_periods (stream, params, fPeriod, 0); | |||
| err = snd_pcm_hw_params_set_periods (stream, params, fPeriod, 0); | |||
| check_error_msg(err, "number of periods not available"); | |||
| return 0; | |||
| } | |||
| @@ -298,20 +298,20 @@ class AudioInterface : public AudioParam | |||
| } | |||
| /** | |||
| * Read audio samples from the audio card. Convert samples to floats and take | |||
| * Read audio samples from the audio card. Convert samples to floats and take | |||
| * care of interleaved buffers | |||
| */ | |||
| int read() | |||
| { | |||
| if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) { | |||
| int count = snd_pcm_readi(fInputDevice, fInputCardBuffer, fBuffering); | |||
| if (count<0) { | |||
| int count = snd_pcm_readi(fInputDevice, fInputCardBuffer, fBuffering); | |||
| if (count<0) { | |||
| display_error_msg(count, "reading samples"); | |||
| int err = snd_pcm_prepare(fInputDevice); | |||
| int err = snd_pcm_prepare(fInputDevice); | |||
| check_error_msg(err, "preparing input stream"); | |||
| } | |||
| if (fSampleFormat == SND_PCM_FORMAT_S16) { | |||
| short* buffer16b = (short*) fInputCardBuffer; | |||
| @@ -330,16 +330,16 @@ class AudioInterface : public AudioParam | |||
| } | |||
| } | |||
| } | |||
| } else if (fSampleAccess == SND_PCM_ACCESS_RW_NONINTERLEAVED) { | |||
| int count = snd_pcm_readn(fInputDevice, fInputCardChannels, fBuffering); | |||
| if (count < 0) { | |||
| int count = snd_pcm_readn(fInputDevice, fInputCardChannels, fBuffering); | |||
| if (count < 0) { | |||
| display_error_msg(count, "reading samples"); | |||
| int err = snd_pcm_prepare(fInputDevice); | |||
| int err = snd_pcm_prepare(fInputDevice); | |||
| check_error_msg(err, "preparing input stream"); | |||
| } | |||
| if (fSampleFormat == SND_PCM_FORMAT_S16) { | |||
| for (unsigned int c = 0; c < fCardInputs; c++) { | |||
| @@ -358,7 +358,7 @@ class AudioInterface : public AudioParam | |||
| } | |||
| } | |||
| } | |||
| } else { | |||
| check_error_msg(-10000, "unknow access mode"); | |||
| } | |||
| @@ -367,15 +367,15 @@ class AudioInterface : public AudioParam | |||
| } | |||
| /** | |||
| * write the output soft channels to the audio card. Convert sample | |||
| * write the output soft channels to the audio card. Convert sample | |||
| * format and interleaves buffers when needed | |||
| */ | |||
| int write() | |||
| { | |||
| recovery: | |||
| if (fSampleAccess == SND_PCM_ACCESS_RW_INTERLEAVED) { | |||
| if (fSampleFormat == SND_PCM_FORMAT_S16) { | |||
| short* buffer16b = (short*) fOutputCardBuffer; | |||
| @@ -397,17 +397,17 @@ class AudioInterface : public AudioParam | |||
| } | |||
| } | |||
| int count = snd_pcm_writei(fOutputDevice, fOutputCardBuffer, fBuffering); | |||
| if (count < 0) { | |||
| display_error_msg(count, "w3"); | |||
| int err = snd_pcm_prepare(fOutputDevice); | |||
| int count = snd_pcm_writei(fOutputDevice, fOutputCardBuffer, fBuffering); | |||
| if (count < 0) { | |||
| display_error_msg(count, "w3"); | |||
| int err = snd_pcm_prepare(fOutputDevice); | |||
| check_error_msg(err, "preparing output stream"); | |||
| goto recovery; | |||
| } | |||
| } else if (fSampleAccess == SND_PCM_ACCESS_RW_NONINTERLEAVED) { | |||
| if (fSampleFormat == SND_PCM_FORMAT_S16) { | |||
| for (unsigned int c = 0; c < fCardOutputs; c++) { | |||
| @@ -429,21 +429,21 @@ class AudioInterface : public AudioParam | |||
| } | |||
| } | |||
| int count = snd_pcm_writen(fOutputDevice, fOutputCardChannels, fBuffering); | |||
| if (count<0) { | |||
| display_error_msg(count, "w3"); | |||
| int err = snd_pcm_prepare(fOutputDevice); | |||
| int count = snd_pcm_writen(fOutputDevice, fOutputCardChannels, fBuffering); | |||
| if (count<0) { | |||
| display_error_msg(count, "w3"); | |||
| int err = snd_pcm_prepare(fOutputDevice); | |||
| check_error_msg(err, "preparing output stream"); | |||
| goto recovery; | |||
| } | |||
| } else { | |||
| check_error_msg(-10000, "unknow access mode"); | |||
| } | |||
| return 0; | |||
| } | |||
| /** | |||
| * print short information on the audio device | |||
| */ | |||
| @@ -455,13 +455,13 @@ class AudioInterface : public AudioParam | |||
| err = snd_ctl_open(&ctl_handle, fCardName, 0); check_error(err); | |||
| snd_ctl_card_info_alloca(&card_info); | |||
| err = snd_ctl_card_info(ctl_handle, card_info); check_error(err); | |||
| jack_info("%s|%d|%d|%d|%d|%s", | |||
| jack_info("%s|%d|%d|%d|%d|%s", | |||
| snd_ctl_card_info_get_driver(card_info), | |||
| fCardInputs, fCardOutputs, | |||
| fFrequency, fBuffering, | |||
| snd_pcm_format_name((_snd_pcm_format)fSampleFormat)); | |||
| } | |||
| /** | |||
| * print more detailled information on the audio device | |||
| */ | |||
| @@ -472,12 +472,12 @@ class AudioInterface : public AudioParam | |||
| snd_ctl_t* ctl_handle; | |||
| jack_info("Audio Interface Description :"); | |||
| jack_info("Sampling Frequency : %d, Sample Format : %s, buffering : %d nperiod : %d", | |||
| jack_info("Sampling Frequency : %d, Sample Format : %s, buffering : %d nperiod : %d", | |||
| fFrequency, snd_pcm_format_name((_snd_pcm_format)fSampleFormat), fBuffering, fPeriod); | |||
| jack_info("Software inputs : %2d, Software outputs : %2d", fSoftInputs, fSoftOutputs); | |||
| jack_info("Hardware inputs : %2d, Hardware outputs : %2d", fCardInputs, fCardOutputs); | |||
| jack_info("Channel inputs : %2d, Channel outputs : %2d", fChanInputs, fChanOutputs); | |||
| // affichage des infos de la carte | |||
| err = snd_ctl_open (&ctl_handle, fCardName, 0); check_error(err); | |||
| snd_ctl_card_info_alloca (&card_info); | |||
| @@ -489,7 +489,7 @@ class AudioInterface : public AudioParam | |||
| if (fSoftOutputs > 0) printHWParams(fOutputParams); | |||
| return 0; | |||
| } | |||
| void printCardInfo(snd_ctl_card_info_t* ci) | |||
| { | |||
| jack_info("Card info (address : %p)", ci); | |||
| @@ -528,24 +528,25 @@ class JackAlsaAdapter : public JackAudioAdapterInterface, public JackRunnableInt | |||
| { | |||
| private: | |||
| JackThread fThread; | |||
| AudioInterface fAudioInterface; | |||
| public: | |||
| JackAlsaAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params); | |||
| ~JackAlsaAdapter() | |||
| {} | |||
| virtual int Open(); | |||
| virtual int Close(); | |||
| virtual int SetSampleRate(jack_nframes_t sample_rate); | |||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | |||
| virtual bool Init(); | |||
| virtual bool Execute(); | |||
| }; | |||
| } | |||
| @@ -116,7 +116,7 @@ OSStatus JackCoreAudioAdapter::SRNotificationCallback(AudioDeviceID inDevice, | |||
| return noErr; | |||
| } | |||
| OSStatus JackCoreAudioAdapter::Render(void *inRefCon, | |||
| AudioUnitRenderActionFlags *ioActionFlags, | |||
| const AudioTimeStamp *inTimeStamp, | |||
| @@ -127,27 +127,27 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon, | |||
| JackCoreAudioAdapter* adapter = static_cast<JackCoreAudioAdapter*>(inRefCon); | |||
| AudioUnitRender(adapter->fAUHAL, ioActionFlags, inTimeStamp, 1, inNumberFrames, adapter->fInputData); | |||
| bool failure = false; | |||
| jack_nframes_t time1, time2; | |||
| jack_nframes_t time1, time2; | |||
| adapter->ResampleFactor(time1, time2); | |||
| for (int i = 0; i < adapter->fCaptureChannels; i++) { | |||
| adapter->fCaptureRingBuffer[i]->SetRatio(time1, time2); | |||
| if (adapter->fCaptureRingBuffer[i]->WriteResample((float*)adapter->fInputData->mBuffers[i].mData, inNumberFrames) < inNumberFrames) | |||
| failure = true; | |||
| } | |||
| for (int i = 0; i < adapter->fPlaybackChannels; i++) { | |||
| adapter->fPlaybackRingBuffer[i]->SetRatio(time2, time1); | |||
| if (adapter->fPlaybackRingBuffer[i]->ReadResample((float*)ioData->mBuffers[i].mData, inNumberFrames) < inNumberFrames) | |||
| failure = true; | |||
| } | |||
| #ifdef JACK_MONITOR | |||
| adapter->fTable.Write(time1, time2, double(time1) / double(time2), double(time2) / double(time1), | |||
| #ifdef JACK_MONITOR | |||
| adapter->fTable.Write(time1, time2, double(time1) / double(time2), double(time2) / double(time1), | |||
| adapter->fCaptureRingBuffer[0]->ReadSpace(), adapter->fPlaybackRingBuffer[0]->WriteSpace()); | |||
| #endif | |||
| // Reset all ringbuffers in case of failure | |||
| if (failure) { | |||
| jack_error("JackCoreAudioAdapter::Render ringbuffer failure... reset"); | |||
| @@ -162,39 +162,42 @@ OSStatus JackCoreAudioAdapter::Render(void *inRefCon, | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| fCaptureChannels = 2; | |||
| fPlaybackChannels = 2; | |||
| for (node = params; node; node = jack_slist_next(node)) { | |||
| param = (const jack_driver_param_t*) node->data; | |||
| switch (param->character) { | |||
| case 'c' : | |||
| break; | |||
| case 'i': | |||
| fCaptureChannels = param->value.ui; | |||
| break; | |||
| case 'o': | |||
| fPlaybackChannels = param->value.ui; | |||
| break; | |||
| case 'C': | |||
| break; | |||
| case 'P': | |||
| break; | |||
| case 'D': | |||
| break; | |||
| case 'r': | |||
| SetAudioSampleRate(param->value.ui); | |||
| SetAdaptedSampleRate(param->value.ui); | |||
| break; | |||
| case 'p': | |||
| SetAdaptedBufferSize(param->value.ui); | |||
| break; | |||
| case 'l': | |||
| break; | |||
| } | |||
| @@ -260,7 +263,7 @@ int JackCoreAudioAdapter::SetupDevices(const char* capture_driver_uid, | |||
| jack_error("Cannot open default device"); | |||
| return -1; | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -273,21 +276,21 @@ int JackCoreAudioAdapter::SetupChannels(bool capturing, | |||
| bool strict) | |||
| { | |||
| OSStatus err = noErr; | |||
| err = GetTotalChannels(fDeviceID, &in_nChannels, true); | |||
| if (err != noErr) { | |||
| jack_error("Cannot get input channel number"); | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| err = GetTotalChannels(fDeviceID, &out_nChannels, false); | |||
| if (err != noErr) { | |||
| jack_error("Cannot get output channel number"); | |||
| printError(err); | |||
| return -1; | |||
| } | |||
| return 0; | |||
| } | |||
| @@ -350,7 +353,7 @@ int JackCoreAudioAdapter::SetupBufferSizeAndSampleRate(jack_nframes_t nframes, j | |||
| int JackCoreAudioAdapter::SetupBuffers(int inchannels, int outchannels) | |||
| { | |||
| jack_log("JackCoreAudioAdapter::SetupBuffers: input = %ld output = %ld", inchannels, outchannels); | |||
| // Prepare buffers | |||
| fInputData = (AudioBufferList*)malloc(sizeof(UInt32) + inchannels * sizeof(AudioBuffer)); | |||
| if (fInputData == 0) { | |||
| @@ -369,7 +372,7 @@ int JackCoreAudioAdapter::SetupBuffers(int inchannels, int outchannels) | |||
| void JackCoreAudioAdapter::DisposeBuffers() | |||
| { | |||
| if (fInputData) { | |||
| for (int i = 0; i < fCaptureChannels; i++) | |||
| for (int i = 0; i < fCaptureChannels; i++) | |||
| free(fInputData->mBuffers[i].mData); | |||
| free(fInputData); | |||
| fInputData = 0; | |||
| @@ -559,13 +562,13 @@ void JackCoreAudioAdapter::CloseAUHAL() | |||
| AudioUnitUninitialize(fAUHAL); | |||
| CloseComponent(fAUHAL); | |||
| } | |||
| int JackCoreAudioAdapter::Open() | |||
| { | |||
| OSStatus err; | |||
| int in_nChannels = 0; | |||
| int out_nChannels = 0; | |||
| if (SetupDevices("", "", "", "") < 0) | |||
| return -1; | |||
| @@ -580,11 +583,11 @@ int JackCoreAudioAdapter::Open() | |||
| if (SetupBuffers(fCaptureChannels, fPlaybackChannels) < 0) | |||
| goto error; | |||
| err = AudioOutputUnitStart(fAUHAL); | |||
| if (err != noErr) | |||
| goto error; | |||
| return 0; | |||
| error: | |||
| @@ -594,7 +597,7 @@ error: | |||
| int JackCoreAudioAdapter::Close() | |||
| { | |||
| #ifdef JACK_MONITOR | |||
| #ifdef JACK_MONITOR | |||
| fTable.Save(); | |||
| #endif | |||
| AudioOutputUnitStop(fAUHAL); | |||
| @@ -603,9 +606,15 @@ int JackCoreAudioAdapter::Close() | |||
| return 0; | |||
| } | |||
| int JackCoreAudioAdapter::SetBufferSize(jack_nframes_t buffer_size) | |||
| { | |||
| JackAudioAdapterInterface::SetBufferSize(buffer_size); | |||
| int JackCoreAudioAdapter::SetSampleRate ( jack_nframes_t sample_rate ) { | |||
| JackAudioAdapterInterface::SetHostSampleRate ( sample_rate ); | |||
| Close(); | |||
| return Open(); | |||
| } | |||
| int JackCoreAudioAdapter::SetBufferSize ( jack_nframes_t buffer_size ) { | |||
| JackAudioAdapterInterface::SetHostBufferSize ( buffer_size ); | |||
| Close(); | |||
| return Open(); | |||
| } | |||
| @@ -617,14 +626,14 @@ extern "C" | |||
| { | |||
| #endif | |||
| EXPORT jack_driver_desc_t* jack_get_descriptor() | |||
| EXPORT jack_driver_desc_t* jack_get_descriptor() | |||
| { | |||
| jack_driver_desc_t *desc; | |||
| unsigned int i; | |||
| desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t)); | |||
| strcpy(desc->name, "coreaudio-adapter"); | |||
| desc->nparams = 9; | |||
| desc->nparams = 10; | |||
| desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); | |||
| i = 0; | |||
| @@ -666,7 +675,7 @@ extern "C" | |||
| strcpy(desc->params[i].value.str, "will take default CoreAudio output device"); | |||
| strcpy(desc->params[i].short_desc, "Provide playback ports. Optionally set CoreAudio device name"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| i++; | |||
| strcpy(desc->params[i].name, "rate"); | |||
| desc->params[i].character = 'r'; | |||
| @@ -675,6 +684,14 @@ extern "C" | |||
| strcpy(desc->params[i].short_desc, "Sample rate"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| i++; | |||
| strcpy(desc->params[i].name, "periodsize"); | |||
| desc->params[i].character = 'p'; | |||
| desc->params[i].type = JackDriverParamUInt; | |||
| desc->params[i].value.ui = 512U; | |||
| strcpy(desc->params[i].short_desc, "Period size"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| i++; | |||
| strcpy(desc->params[i].name, "duplex"); | |||
| desc->params[i].character = 'D'; | |||
| @@ -698,11 +715,11 @@ extern "C" | |||
| desc->params[i].value.i = TRUE; | |||
| strcpy(desc->params[i].short_desc, "Display available CoreAudio devices"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| return desc; | |||
| } | |||
| #ifdef __cplusplus | |||
| } | |||
| #endif | |||
| @@ -44,23 +44,23 @@ class JackCoreAudioAdapter : public JackAudioAdapterInterface | |||
| { | |||
| private: | |||
| AudioUnit fAUHAL; | |||
| AudioBufferList* fInputData; | |||
| AudioDeviceID fDeviceID; | |||
| bool fState; | |||
| AudioUnitRenderActionFlags* fActionFags; | |||
| AudioTimeStamp* fCurrentTime; | |||
| static OSStatus Render(void *inRefCon, | |||
| AudioUnitRenderActionFlags *ioActionFlags, | |||
| const AudioTimeStamp *inTimeStamp, | |||
| UInt32 inBusNumber, | |||
| UInt32 inNumberFrames, | |||
| AudioBufferList *ioData); | |||
| static OSStatus SRNotificationCallback(AudioDeviceID inDevice, | |||
| UInt32 inChannel, | |||
| Boolean isInput, | |||
| @@ -83,7 +83,7 @@ class JackCoreAudioAdapter : public JackAudioAdapterInterface | |||
| int& in_nChannels, | |||
| int& out_nChannels, | |||
| bool strict); | |||
| int OpenAUHAL(bool capturing, | |||
| bool playing, | |||
| int inchannels, | |||
| @@ -100,16 +100,17 @@ class JackCoreAudioAdapter : public JackAudioAdapterInterface | |||
| void CloseAUHAL(); | |||
| public: | |||
| JackCoreAudioAdapter( jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params); | |||
| ~JackCoreAudioAdapter() | |||
| {} | |||
| virtual int Open(); | |||
| virtual int Close(); | |||
| virtual int SetSampleRate(jack_nframes_t sample_rate); | |||
| virtual int SetBufferSize(jack_nframes_t buffer_size); | |||
| }; | |||
| } | |||
| @@ -27,196 +27,206 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| namespace Jack | |||
| { | |||
| int JackPortAudioAdapter::Render(const void* inputBuffer, void* outputBuffer, | |||
| unsigned long framesPerBuffer, | |||
| const PaStreamCallbackTimeInfo* timeInfo, | |||
| PaStreamCallbackFlags statusFlags, | |||
| void* userData) | |||
| { | |||
| JackPortAudioAdapter* adapter = static_cast<JackPortAudioAdapter*>(userData); | |||
| float** paBuffer; | |||
| float* buffer; | |||
| bool failure = false; | |||
| jack_nframes_t time1, time2; | |||
| adapter->ResampleFactor(time1, time2); | |||
| paBuffer = (float**)inputBuffer; | |||
| for (int i = 0; i < adapter->fCaptureChannels; i++) { | |||
| buffer = (float*)paBuffer[i]; | |||
| adapter->fCaptureRingBuffer[i]->SetRatio(time1, time2); | |||
| if (adapter->fCaptureRingBuffer[i]->WriteResample(buffer, framesPerBuffer) < framesPerBuffer) | |||
| failure = true; | |||
| } | |||
| int JackPortAudioAdapter::Render ( const void* inputBuffer, | |||
| void* outputBuffer, | |||
| unsigned long framesPerBuffer, | |||
| const PaStreamCallbackTimeInfo* timeInfo, | |||
| PaStreamCallbackFlags statusFlags, | |||
| void* userData) | |||
| { | |||
| JackPortAudioAdapter* adapter = static_cast<JackPortAudioAdapter*>(userData); | |||
| float** paBuffer; | |||
| bool failure = false; | |||
| jack_nframes_t time1, time2; | |||
| adapter->ResampleFactor ( time1, time2 ); | |||
| paBuffer = (float**)inputBuffer; | |||
| for ( int i = 0; i < adapter->fCaptureChannels; i++ ) | |||
| { | |||
| adapter->fCaptureRingBuffer[i]->SetRatio ( time1, time2 ); | |||
| if (adapter->fCaptureRingBuffer[i]->WriteResample ( (float*)paBuffer[i], framesPerBuffer ) < framesPerBuffer ) | |||
| failure = true; | |||
| } | |||
| paBuffer = (float**)outputBuffer; | |||
| for (int i = 0; i < adapter->fPlaybackChannels; i++) { | |||
| buffer = (float*)paBuffer[i]; | |||
| adapter->fPlaybackRingBuffer[i]->SetRatio(time2, time1); | |||
| if (adapter->fPlaybackRingBuffer[i]->ReadResample(buffer, framesPerBuffer) < framesPerBuffer) | |||
| failure = true; | |||
| } | |||
| paBuffer = (float**)outputBuffer; | |||
| for ( int i = 0; i < adapter->fPlaybackChannels; i++ ) | |||
| { | |||
| adapter->fPlaybackRingBuffer[i]->SetRatio ( time2, time1 ); | |||
| if ( adapter->fPlaybackRingBuffer[i]->ReadResample ( (float*)paBuffer[i], framesPerBuffer ) < framesPerBuffer ) | |||
| failure = true; | |||
| } | |||
| #ifdef JACK_MONITOR | |||
| adapter->fTable.Write(time1, time2, double(time1) / double(time2), double(time2) / double(time1), | |||
| adapter->fCaptureRingBuffer[0]->ReadSpace(), adapter->fPlaybackRingBuffer[0]->WriteSpace()); | |||
| adapter->fTable.Write ( time1, time2, double(time1) / double(time2), double(time2) / double(time1), | |||
| adapter->fCaptureRingBuffer[0]->ReadSpace(), adapter->fPlaybackRingBuffer[0]->WriteSpace() ); | |||
| #endif | |||
| // Reset all ringbuffers in case of failure | |||
| if (failure) { | |||
| jack_error("JackPortAudioAdapter::Render ringbuffer failure... reset"); | |||
| adapter->ResetRingBuffers(); | |||
| // Reset all ringbuffers in case of failure | |||
| if ( failure ) | |||
| { | |||
| jack_error ( "JackPortAudioAdapter::Render ringbuffer failure... reset" ); | |||
| adapter->ResetRingBuffers(); | |||
| } | |||
| return paContinue; | |||
| } | |||
| return paContinue; | |||
| } | |||
| JackPortAudioAdapter::JackPortAudioAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params) | |||
| :JackAudioAdapterInterface(buffer_size, sample_rate) | |||
| { | |||
| jack_log ( "JackPortAudioAdapter::JackPortAudioAdapter buffer_size = %d, sample_rate = %d", buffer_size, sample_rate ); | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| int in_max = 0; | |||
| int out_max = 0; | |||
| fCaptureChannels = 0; | |||
| fPlaybackChannels = 0; | |||
| JackPortAudioAdapter::JackPortAudioAdapter ( jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params ) | |||
| : JackAudioAdapterInterface ( buffer_size, sample_rate ) | |||
| { | |||
| jack_log ( "JackPortAudioAdapter::JackPortAudioAdapter buffer_size = %d, sample_rate = %d", buffer_size, sample_rate ); | |||
| fInputDevice = Pa_GetDefaultInputDevice(); | |||
| fOutputDevice = Pa_GetDefaultOutputDevice(); | |||
| const JSList* node; | |||
| const jack_driver_param_t* param; | |||
| int in_max = 0; | |||
| int out_max = 0; | |||
| for (node = params; node; node = jack_slist_next(node)) { | |||
| param = (const jack_driver_param_t*) node->data; | |||
| fInputDevice = Pa_GetDefaultInputDevice(); | |||
| fOutputDevice = Pa_GetDefaultOutputDevice(); | |||
| switch (param->character) { | |||
| for (node = params; node; node = jack_slist_next(node)) | |||
| { | |||
| param = (const jack_driver_param_t*) node->data; | |||
| case 'i': | |||
| switch (param->character) | |||
| { | |||
| case 'i' : | |||
| fCaptureChannels = param->value.ui; | |||
| break; | |||
| case 'o': | |||
| case 'o' : | |||
| fPlaybackChannels = param->value.ui; | |||
| break; | |||
| case 'C': | |||
| if ( fPaDevices.GetInputDeviceFromName(param->value.str, fInputDevice, in_max) < 0 ) { | |||
| jack_error ( "Can't use %s, taking default input device", param->value.str ); | |||
| fInputDevice = Pa_GetDefaultInputDevice(); | |||
| } | |||
| case 'C' : | |||
| if ( fPaDevices.GetInputDeviceFromName(param->value.str, fInputDevice, in_max) < 0 ) | |||
| { | |||
| jack_error ( "Can't use %s, taking default input device", param->value.str ); | |||
| fInputDevice = Pa_GetDefaultInputDevice(); | |||
| } | |||
| break; | |||
| case 'P': | |||
| if ( fPaDevices.GetOutputDeviceFromName(param->value.str, fOutputDevice, out_max) < 0 ) { | |||
| jack_error ( "Can't use %s, taking default output device", param->value.str ); | |||
| fOutputDevice = Pa_GetDefaultOutputDevice(); | |||
| } | |||
| case 'P' : | |||
| if ( fPaDevices.GetOutputDeviceFromName(param->value.str, fOutputDevice, out_max) < 0 ) | |||
| { | |||
| jack_error ( "Can't use %s, taking default output device", param->value.str ); | |||
| fOutputDevice = Pa_GetDefaultOutputDevice(); | |||
| } | |||
| break; | |||
| case 'r': | |||
| SetAudioSampleRate(param->value.ui); | |||
| case 'r' : | |||
| SetAdaptedSampleRate ( param->value.ui ); | |||
| break; | |||
| case 'd': | |||
| if ( fPaDevices.GetInputDeviceFromName(param->value.str, fInputDevice, in_max) < 0 ) { | |||
| jack_error ( "Can't use %s, taking default input device", param->value.str ); | |||
| } | |||
| if ( fPaDevices.GetOutputDeviceFromName(param->value.str, fOutputDevice, out_max) < 0 ) { | |||
| jack_error ( "Can't use %s, taking default output device", param->value.str ); | |||
| } | |||
| case 'p' : | |||
| SetAdaptedBufferSize ( param->value.ui ); | |||
| break; | |||
| case 'l': | |||
| fPaDevices.DisplayDevicesNames(); | |||
| case 'd' : | |||
| if ( fPaDevices.GetInputDeviceFromName ( param->value.str, fInputDevice, in_max ) < 0 ) | |||
| jack_error ( "Can't use %s, taking default input device", param->value.str ); | |||
| if ( fPaDevices.GetOutputDeviceFromName ( param->value.str, fOutputDevice, out_max ) < 0 ) | |||
| jack_error ( "Can't use %s, taking default output device", param->value.str ); | |||
| break; | |||
| case 'l' : | |||
| fPaDevices.DisplayDevicesNames(); | |||
| break; | |||
| } | |||
| } | |||
| //max channels | |||
| if ( in_max == 0 ) | |||
| in_max = fPaDevices.GetDeviceInfo ( fInputDevice )->maxInputChannels; | |||
| if ( out_max == 0 ) | |||
| out_max = fPaDevices.GetDeviceInfo ( fOutputDevice )->maxOutputChannels; | |||
| //effective channels | |||
| if ( ( fCaptureChannels == 0 ) || ( fCaptureChannels > in_max ) ) | |||
| fCaptureChannels = in_max; | |||
| if ( ( fPlaybackChannels == 0 ) || ( fPlaybackChannels > out_max ) ) | |||
| fPlaybackChannels = out_max; | |||
| //set adapter interface channels | |||
| SetInputs ( fCaptureChannels ); | |||
| SetOutputs ( fPlaybackChannels ); | |||
| } | |||
| //max channels | |||
| if ( in_max == 0 ) | |||
| in_max = fPaDevices.GetDeviceInfo(fInputDevice)->maxInputChannels; | |||
| if ( out_max == 0 ) | |||
| out_max = fPaDevices.GetDeviceInfo(fOutputDevice)->maxOutputChannels; | |||
| //effective channels | |||
| if ( ( fCaptureChannels == 0 ) || ( fCaptureChannels > in_max ) ) | |||
| fCaptureChannels = in_max; | |||
| if ( ( fPlaybackChannels == 0 ) || ( fPlaybackChannels > out_max ) ) | |||
| fPlaybackChannels = out_max; | |||
| } | |||
| int JackPortAudioAdapter::Open() | |||
| { | |||
| PaError err; | |||
| PaStreamParameters inputParameters; | |||
| PaStreamParameters outputParameters; | |||
| if ( JackAudioAdapterInterface::Open() < 0 ) | |||
| return -1; | |||
| jack_log("JackPortAudioAdapter::Open fInputDevice = %d DeviceName %s", fInputDevice, fPaDevices.GetFullName(fInputDevice).c_str()); | |||
| jack_log("JackPortAudioAdapter::Open fOutputDevice = %d DeviceName %s", fOutputDevice, fPaDevices.GetFullName(fOutputDevice).c_str()); | |||
| jack_log("JackPortAudioAdapter::Open fAdaptedBufferSize = %u fAdaptedSampleRate %u", fAdaptedBufferSize, fAdaptedSampleRate); | |||
| inputParameters.device = fInputDevice; | |||
| inputParameters.channelCount = fCaptureChannels; | |||
| inputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output | |||
| inputParameters.suggestedLatency = ( fInputDevice != paNoDevice ) // TODO: check how to setup this on ASIO | |||
| ? fPaDevices.GetDeviceInfo(fInputDevice)->defaultLowInputLatency | |||
| : 0; | |||
| inputParameters.hostApiSpecificStreamInfo = NULL; | |||
| outputParameters.device = fOutputDevice; | |||
| outputParameters.channelCount = fPlaybackChannels; | |||
| outputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output | |||
| outputParameters.suggestedLatency = ( fOutputDevice != paNoDevice ) // TODO: check how to setup this on ASIO | |||
| ? fPaDevices.GetDeviceInfo(fOutputDevice)->defaultLowOutputLatency | |||
| : 0; | |||
| outputParameters.hostApiSpecificStreamInfo = NULL; | |||
| err = Pa_OpenStream( &fStream, | |||
| ( fInputDevice == paNoDevice ) ? 0 : &inputParameters, | |||
| ( fOutputDevice == paNoDevice ) ? 0 : &outputParameters, | |||
| fAdaptedSampleRate, | |||
| fAdaptedBufferSize, | |||
| paNoFlag, // Clipping is on... | |||
| Render, | |||
| this ); | |||
| if ( err != paNoError ) | |||
| { | |||
| jack_error ( "Pa_OpenStream error = %s", Pa_GetErrorText ( err ) ); | |||
| return -1; | |||
| } | |||
| int JackPortAudioAdapter::Open() | |||
| { | |||
| PaError err; | |||
| PaStreamParameters inputParameters; | |||
| PaStreamParameters outputParameters; | |||
| if (JackAudioAdapterInterface::Open() < 0) | |||
| return -1; | |||
| jack_log("JackPortAudioAdapter::Open fInputDevice = %d DeviceName %s", fInputDevice, fPaDevices.GetFullName(fInputDevice).c_str()); | |||
| jack_log("JackPortAudioAdapter::Open fOutputDevice = %d DeviceName %s", fOutputDevice, fPaDevices.GetFullName(fOutputDevice).c_str()); | |||
| jack_log("JackPortAudioAdapter::Open fBufferSize = %u fSampleRate %u", fBufferSize, fSampleRate); | |||
| inputParameters.device = fInputDevice; | |||
| inputParameters.channelCount = fCaptureChannels; | |||
| inputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output | |||
| inputParameters.suggestedLatency = (fInputDevice != paNoDevice) // TODO: check how to setup this on ASIO | |||
| ? fPaDevices.GetDeviceInfo(fInputDevice)->defaultLowInputLatency | |||
| : 0; | |||
| inputParameters.hostApiSpecificStreamInfo = NULL; | |||
| outputParameters.device = fOutputDevice; | |||
| outputParameters.channelCount = fPlaybackChannels; | |||
| outputParameters.sampleFormat = paFloat32 | paNonInterleaved; // 32 bit floating point output | |||
| outputParameters.suggestedLatency = (fOutputDevice != paNoDevice) // TODO: check how to setup this on ASIO | |||
| ? fPaDevices.GetDeviceInfo(fOutputDevice)->defaultLowOutputLatency | |||
| : 0; | |||
| outputParameters.hostApiSpecificStreamInfo = NULL; | |||
| err = Pa_OpenStream(&fStream, | |||
| (fInputDevice == paNoDevice) ? 0 : &inputParameters, | |||
| (fOutputDevice == paNoDevice) ? 0 : &outputParameters, | |||
| fSampleRate, | |||
| fBufferSize, | |||
| paNoFlag, // Clipping is on... | |||
| Render, | |||
| this); | |||
| if (err != paNoError) { | |||
| jack_error("Pa_OpenStream error = %s", Pa_GetErrorText(err)); | |||
| return -1; | |||
| } | |||
| err = Pa_StartStream ( fStream ); | |||
| err = Pa_StartStream(fStream); | |||
| if (err != paNoError) { | |||
| jack_error("Pa_StartStream error = %s", Pa_GetErrorText(err)); | |||
| return -1; | |||
| } | |||
| jack_log("JackPortAudioAdapter::Open OK"); | |||
| return 0; | |||
| if ( err != paNoError ) | |||
| { | |||
| jack_error ( "Pa_StartStream error = %s", Pa_GetErrorText ( err ) ); | |||
| return -1; | |||
| } | |||
| } | |||
| jack_log ( "JackPortAudioAdapter::Open OK" ); | |||
| return 0; | |||
| } | |||
| int JackPortAudioAdapter::Close() | |||
| { | |||
| int JackPortAudioAdapter::Close() | |||
| { | |||
| #ifdef JACK_MONITOR | |||
| fTable.Save(); | |||
| fTable.Save(); | |||
| #endif | |||
| jack_log("JackPortAudioAdapter::Close"); | |||
| Pa_StopStream(fStream); | |||
| jack_log("JackPortAudioAdapter:: Pa_StopStream"); | |||
| Pa_CloseStream(fStream); | |||
| jack_log("JackPortAudioAdapter:: Pa_CloseStream"); | |||
| return JackAudioAdapterInterface::Close(); | |||
| } | |||
| jack_log ( "JackPortAudioAdapter::Close" ); | |||
| Pa_StopStream ( fStream ); | |||
| jack_log ( "JackPortAudioAdapter:: Pa_StopStream" ); | |||
| Pa_CloseStream ( fStream ); | |||
| jack_log ( "JackPortAudioAdapter:: Pa_CloseStream" ); | |||
| return JackAudioAdapterInterface::Close(); | |||
| } | |||
| int JackPortAudioAdapter::SetBufferSize(jack_nframes_t buffer_size) | |||
| { | |||
| JackAudioAdapterInterface::SetBufferSize(buffer_size); | |||
| Close(); | |||
| return Open(); | |||
| } | |||
| int JackPortAudioAdapter::SetSampleRate ( jack_nframes_t sample_rate ) | |||
| { | |||
| JackAudioAdapterInterface::SetHostSampleRate ( sample_rate ); | |||
| Close(); | |||
| return Open(); | |||
| } | |||
| int JackPortAudioAdapter::SetBufferSize ( jack_nframes_t buffer_size ) | |||
| { | |||
| JackAudioAdapterInterface::SetHostBufferSize ( buffer_size ); | |||
| Close(); | |||
| return Open(); | |||
| } | |||
| } // namespace | |||
| @@ -232,7 +242,7 @@ extern "C" | |||
| desc = (jack_driver_desc_t*)calloc(1, sizeof(jack_driver_desc_t)); | |||
| strcpy(desc->name, "portaudio-adapter"); | |||
| desc->nparams = 7; | |||
| desc->nparams = 8; | |||
| desc->params = (jack_driver_param_desc_t*)calloc(desc->nparams, sizeof(jack_driver_param_desc_t)); | |||
| i = 0; | |||
| @@ -275,6 +285,14 @@ extern "C" | |||
| strcpy(desc->params[i].short_desc, "Sample rate"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| i++; | |||
| strcpy(desc->params[i].name, "periodsize"); | |||
| desc->params[i].character = 'p'; | |||
| desc->params[i].type = JackDriverParamUInt; | |||
| desc->params[i].value.ui = 512U; | |||
| strcpy(desc->params[i].short_desc, "Period size"); | |||
| strcpy(desc->params[i].long_desc, desc->params[i].short_desc); | |||
| i++; | |||
| strcpy(desc->params[i].name, "device"); | |||
| desc->params[i].character = 'd'; | |||
| @@ -27,12 +27,12 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
| namespace Jack | |||
| { | |||
| /*! | |||
| \brief Audio adapter using PortAudio API. | |||
| */ | |||
| /*! | |||
| \brief Audio adapter using PortAudio API. | |||
| */ | |||
| class JackPortAudioAdapter : public JackAudioAdapterInterface | |||
| { | |||
| class JackPortAudioAdapter : public JackAudioAdapterInterface | |||
| { | |||
| private: | |||
| @@ -41,24 +41,25 @@ class JackPortAudioAdapter : public JackAudioAdapterInterface | |||
| PaDeviceIndex fInputDevice; | |||
| PaDeviceIndex fOutputDevice; | |||
| static int Render(const void* inputBuffer, void* outputBuffer, | |||
| unsigned long framesPerBuffer, | |||
| const PaStreamCallbackTimeInfo* timeInfo, | |||
| PaStreamCallbackFlags statusFlags, | |||
| void* userData); | |||
| static int Render ( const void* inputBuffer, void* outputBuffer, | |||
| unsigned long framesPerBuffer, | |||
| const PaStreamCallbackTimeInfo* timeInfo, | |||
| PaStreamCallbackFlags statusFlags, | |||
| void* userData ); | |||
| public: | |||
| JackPortAudioAdapter(jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params); | |||
| JackPortAudioAdapter ( jack_nframes_t buffer_size, jack_nframes_t sample_rate, const JSList* params ); | |||
| ~JackPortAudioAdapter() | |||
| {} | |||
| int Open(); | |||
| int Close(); | |||
| int SetBufferSize(jack_nframes_t buffer_size); | |||
| int SetSampleRate ( jack_nframes_t sample_rate ); | |||
| int SetBufferSize ( jack_nframes_t buffer_size ); | |||
| }; | |||
| }; | |||
| } | |||
| @@ -70,7 +71,7 @@ extern "C" | |||
| #include "JackExports.h" | |||
| #include "driver_interface.h" | |||
| EXPORT jack_driver_desc_t* jack_get_descriptor(); | |||
| EXPORT jack_driver_desc_t* jack_get_descriptor(); | |||
| #ifdef __cplusplus | |||
| } | |||