From 38ef2df8f72fe3289beb42284b1f2f3162636519 Mon Sep 17 00:00:00 2001 From: Joerg Mueller Date: Sun, 21 Feb 2010 18:01:41 +0000 Subject: 2.5 Audio: * Jack Transport support! * Minor sequencer audio corrections. --- intern/audaspace/intern/AUD_C-API.cpp | 63 ++++++++++++ intern/audaspace/intern/AUD_C-API.h | 13 +++ intern/audaspace/jack/AUD_JackDevice.cpp | 161 +++++++++++++++++++++++++------ intern/audaspace/jack/AUD_JackDevice.h | 45 +++++++-- 4 files changed, 244 insertions(+), 38 deletions(-) (limited to 'intern') diff --git a/intern/audaspace/intern/AUD_C-API.cpp b/intern/audaspace/intern/AUD_C-API.cpp index 3c29b5d9e08..d2540d59eda 100644 --- a/intern/audaspace/intern/AUD_C-API.cpp +++ b/intern/audaspace/intern/AUD_C-API.cpp @@ -761,6 +761,69 @@ int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length) return length; } +void AUD_startPlayback() +{ +#ifdef WITH_JACK + AUD_JackDevice* device = dynamic_cast(AUD_device); + if(device) + device->startPlayback(); +#endif +} + +void AUD_stopPlayback() +{ +#ifdef WITH_JACK + AUD_JackDevice* device = dynamic_cast(AUD_device); + if(device) + device->stopPlayback(); +#endif +} + +void AUD_seekSequencer(AUD_Handle* handle, float time) +{ +#ifdef WITH_JACK + AUD_JackDevice* device = dynamic_cast(AUD_device); + if(device) + device->seekPlayback(time); + else +#endif + { + AUD_device->seek(handle, time); + } +} + +float AUD_getSequencerPosition(AUD_Handle* handle) +{ +#ifdef WITH_JACK + AUD_JackDevice* device = dynamic_cast(AUD_device); + if(device) + return device->getPlaybackPosition(); + else +#endif + { + return AUD_device->getPosition(handle); + } +} + +void AUD_setSyncCallback(AUD_syncFunction function, void* data) +{ +#ifdef WITH_JACK + AUD_JackDevice* device = dynamic_cast(AUD_device); + if(device) + device->setSyncCallback(function, data); +#endif +} + +int AUD_doesPlayback() +{ +#ifdef WITH_JACK + AUD_JackDevice* device = dynamic_cast(AUD_device); + if(device) + return device->doesPlayback(); +#endif + return -1; +} + #ifdef AUD_DEBUG_MEMORY int AUD_References(int count, const char* text) { diff --git a/intern/audaspace/intern/AUD_C-API.h b/intern/audaspace/intern/AUD_C-API.h index ce1791886de..a252ad904b6 100644 --- a/intern/audaspace/intern/AUD_C-API.h +++ b/intern/audaspace/intern/AUD_C-API.h @@ -52,6 +52,7 @@ typedef struct typedef void AUD_Device; typedef void AUD_SequencerEntry; typedef float (*AUD_volumeFunction)(void*, void*, float); + typedef void (*AUD_syncFunction)(void*, int, float); #endif /** @@ -383,6 +384,18 @@ extern void AUD_muteSequencer(AUD_Sound* sequencer, AUD_SequencerEntry* entry, extern int AUD_readSound(AUD_Sound* sound, sample_t* buffer, int length); +extern void AUD_startPlayback(); + +extern void AUD_stopPlayback(); + +extern void AUD_seekSequencer(AUD_Handle* handle, float time); + +extern float AUD_getSequencerPosition(AUD_Handle* handle); + +extern void AUD_setSyncCallback(AUD_syncFunction function, void* data); + +extern int AUD_doesPlayback(); + #ifdef __cplusplus } #endif diff --git a/intern/audaspace/jack/AUD_JackDevice.cpp b/intern/audaspace/jack/AUD_JackDevice.cpp index dfb2a60d629..ae7725be81c 100644 --- a/intern/audaspace/jack/AUD_JackDevice.cpp +++ b/intern/audaspace/jack/AUD_JackDevice.cpp @@ -31,7 +31,7 @@ #include #include -void* AUD_JackDevice::runThread(void* device) +void* AUD_JackDevice::runMixingThread(void* device) { ((AUD_JackDevice*)device)->updateRingBuffers(); return NULL; @@ -45,10 +45,24 @@ void AUD_JackDevice::updateRingBuffers() unsigned int channels = m_specs.channels; sample_t* buffer = m_buffer->getBuffer(); float* deinterleave = m_deinterleavebuf->getBuffer(); + jack_transport_state_t state; + jack_position_t position; - pthread_mutex_lock(&m_lock); + pthread_mutex_lock(&m_mixingLock); while(m_valid) { + if(m_sync > 1) + { + if(m_syncFunc) + { + state = jack_transport_query(m_client, &position); + m_syncFunc(m_syncFuncData, state != JackTransportStopped, position.frame / (float) m_specs.rate); + } + + for(i = 0; i < channels; i++) + jack_ringbuffer_reset(m_ringbuffers[i]); + } + size = jack_ringbuffer_write_space(m_ringbuffers[0]); for(i = 1; i < channels; i++) if((temp = jack_ringbuffer_write_space(m_ringbuffers[i])) < size) @@ -71,9 +85,14 @@ void AUD_JackDevice::updateRingBuffers() size = temp; } - pthread_cond_wait(&m_condition, &m_lock); + if(m_sync > 1) + { + m_sync = 3; + } + + pthread_cond_wait(&m_mixingCondition, &m_mixingLock); } - pthread_mutex_unlock(&m_lock); + pthread_mutex_unlock(&m_mixingLock); } int AUD_JackDevice::jack_mix(jack_nframes_t length, void *data) @@ -83,27 +102,67 @@ int AUD_JackDevice::jack_mix(jack_nframes_t length, void *data) int count = device->m_specs.channels; char* buffer; - size_t temp; - size_t readsamples = jack_ringbuffer_read_space(device->m_ringbuffers[0]); - for(i = 1; i < count; i++) - if((temp = jack_ringbuffer_read_space(device->m_ringbuffers[i])) < readsamples) - readsamples = temp; + if(device->m_sync) + { + // play silence while syncing + for(unsigned int i = 0; i < count; i++) + memset(jack_port_get_buffer(device->m_ports[i], length), 0, length * sizeof(float)); + } + else + { + size_t temp; + size_t readsamples = jack_ringbuffer_read_space(device->m_ringbuffers[0]); + for(i = 1; i < count; i++) + if((temp = jack_ringbuffer_read_space(device->m_ringbuffers[i])) < readsamples) + readsamples = temp; - readsamples = AUD_MIN(readsamples / sizeof(float), length); + readsamples = AUD_MIN(readsamples / sizeof(float), length); - for(unsigned int i = 0; i < count; i++) - { - buffer = (char*)jack_port_get_buffer(device->m_ports[i], length); - jack_ringbuffer_read(device->m_ringbuffers[i], buffer, readsamples * sizeof(float)); - if(readsamples < length) - memset(buffer + readsamples * sizeof(float), 0, (length - readsamples) * sizeof(float)); + for(unsigned int i = 0; i < count; i++) + { + buffer = (char*)jack_port_get_buffer(device->m_ports[i], length); + jack_ringbuffer_read(device->m_ringbuffers[i], buffer, readsamples * sizeof(float)); + if(readsamples < length) + memset(buffer + readsamples * sizeof(float), 0, (length - readsamples) * sizeof(float)); + } + + if(pthread_mutex_trylock(&(device->m_mixingLock)) == 0) + { + pthread_cond_signal(&(device->m_mixingCondition)); + pthread_mutex_unlock(&(device->m_mixingLock)); + } } - if(pthread_mutex_trylock(&(device->m_lock)) == 0) + return 0; +} + +int AUD_JackDevice::jack_sync(jack_transport_state_t state, jack_position_t* pos, void* data) +{ + AUD_JackDevice* device = (AUD_JackDevice*)data; + + if(state == JackTransportStopped) + return 1; + + if(pthread_mutex_trylock(&(device->m_mixingLock)) == 0) { - pthread_cond_signal(&(device->m_condition)); - pthread_mutex_unlock(&(device->m_lock)); + if(device->m_sync > 2) + { + if(device->m_sync == 3) + { + device->m_sync = 0; + pthread_mutex_unlock(&(device->m_mixingLock)); + return 1; + } + } + else + { + device->m_sync = 2; + pthread_cond_signal(&(device->m_mixingCondition)); + } + pthread_mutex_unlock(&(device->m_mixingLock)); } + else if(!device->m_sync) + device->m_sync = 1; return 0; } @@ -134,6 +193,7 @@ AUD_JackDevice::AUD_JackDevice(AUD_DeviceSpecs specs, int buffersize) // set callbacks jack_set_process_callback(m_client, AUD_JackDevice::jack_mix, this); jack_on_shutdown(m_client, AUD_JackDevice::jack_shutdown, this); + jack_set_sync_callback(m_client, AUD_JackDevice::jack_sync, this); // register our output channels which are called ports in jack m_ports = new jack_port_t*[m_specs.channels]; AUD_NEW("jack_port") @@ -170,6 +230,14 @@ AUD_JackDevice::AUD_JackDevice(AUD_DeviceSpecs specs, int buffersize) create(); + m_valid = true; + m_playing = false; + m_sync = 0; + m_syncFunc = NULL; + + pthread_mutex_init(&m_mixingLock, NULL); + pthread_cond_init(&m_mixingCondition, NULL); + try { // activate the client @@ -185,6 +253,8 @@ AUD_JackDevice::AUD_JackDevice(AUD_DeviceSpecs specs, int buffersize) for(unsigned int i = 0; i < specs.channels; i++) jack_ringbuffer_free(m_ringbuffers[i]); delete[] m_ringbuffers; AUD_DELETE("jack_buffers") + pthread_mutex_destroy(&m_mixingLock); + pthread_cond_destroy(&m_mixingCondition); destroy(); throw; } @@ -199,16 +269,11 @@ AUD_JackDevice::AUD_JackDevice(AUD_DeviceSpecs specs, int buffersize) free(ports); } - m_valid = true; - - pthread_mutex_init(&m_lock, NULL); - pthread_cond_init(&m_condition, NULL); - pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); - pthread_create(&m_thread, &attr, runThread, this); + pthread_create(&m_mixingThread, &attr, runMixingThread, this); pthread_attr_destroy(&attr); } @@ -221,13 +286,13 @@ AUD_JackDevice::~AUD_JackDevice() delete[] m_ports; AUD_DELETE("jack_port") - pthread_mutex_lock(&m_lock); - pthread_cond_signal(&m_condition); - pthread_mutex_unlock(&m_lock); - pthread_join(m_thread, NULL); + pthread_mutex_lock(&m_mixingLock); + pthread_cond_signal(&m_mixingCondition); + pthread_mutex_unlock(&m_mixingLock); + pthread_join(m_mixingThread, NULL); - pthread_cond_destroy(&m_condition); - pthread_mutex_destroy(&m_lock); + pthread_cond_destroy(&m_mixingCondition); + pthread_mutex_destroy(&m_mixingLock); delete m_buffer; AUD_DELETE("buffer"); delete m_deinterleavebuf; AUD_DELETE("buffer"); for(unsigned int i = 0; i < m_specs.channels; i++) @@ -241,3 +306,37 @@ void AUD_JackDevice::playing(bool playing) { // Do nothing. } + +void AUD_JackDevice::startPlayback() +{ + jack_transport_start(m_client); +} + +void AUD_JackDevice::stopPlayback() +{ + jack_transport_stop(m_client); +} + +void AUD_JackDevice::seekPlayback(float time) +{ + if(time >= 0.0f) + jack_transport_locate(m_client, time * m_specs.rate); +} + +void AUD_JackDevice::setSyncCallback(AUD_syncFunction sync, void* data) +{ + m_syncFunc = sync; + m_syncFuncData = data; +} + +float AUD_JackDevice::getPlaybackPosition() +{ + jack_position_t position; + jack_transport_query(m_client, &position); + return position.frame / (float) m_specs.rate; +} + +bool AUD_JackDevice::doesPlayback() +{ + return jack_transport_query(m_client, NULL) != JackTransportStopped; +} diff --git a/intern/audaspace/jack/AUD_JackDevice.h b/intern/audaspace/jack/AUD_JackDevice.h index 96388e1ee50..58e34978c1f 100644 --- a/intern/audaspace/jack/AUD_JackDevice.h +++ b/intern/audaspace/jack/AUD_JackDevice.h @@ -33,6 +33,8 @@ class AUD_Buffer; #include #include +typedef void (*AUD_syncFunction)(void*, int, float); + /** * This device plays back through Jack. */ @@ -56,6 +58,8 @@ private: AUD_Buffer* m_deinterleavebuf; + jack_ringbuffer_t** m_ringbuffers; + /** * Whether the device is valid. */ @@ -75,20 +79,40 @@ private: */ static int jack_mix(jack_nframes_t length, void *data); - static void* runThread(void* device); + static int jack_sync(jack_transport_state_t state, jack_position_t* pos, void* data); - void updateRingBuffers(); + /** + * Last Jack Transport playing state. + */ + bool m_playing; - jack_ringbuffer_t** m_ringbuffers; + /** + * Syncronisation state. + */ + int m_sync; /** - * The streaming thread. + * External syncronisation callback function. */ - pthread_t m_thread; + AUD_syncFunction m_syncFunc; - pthread_mutex_t m_lock; + /** + * Data for the sync function. + */ + void* m_syncFuncData; + + /** + * The mixing thread. + */ + pthread_t m_mixingThread; + + pthread_mutex_t m_mixingLock; - pthread_cond_t m_condition; + pthread_cond_t m_mixingCondition; + + static void* runMixingThread(void* device); + + void updateRingBuffers(); protected: virtual void playing(bool playing); @@ -105,6 +129,13 @@ public: * Closes the Jack client. */ virtual ~AUD_JackDevice(); + + void startPlayback(); + void stopPlayback(); + void seekPlayback(float time); + void setSyncCallback(AUD_syncFunction sync, void* data); + float getPlaybackPosition(); + bool doesPlayback(); }; #endif //AUD_JACKDEVICE -- cgit v1.2.3