[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [26816] trunk/blender/intern/audaspace: 2. 5 Audio: The jack backend is now realtime capable and will not produce so much xruns anymore .

Joerg Mueller nexyon at gmail.com
Thu Feb 11 21:09:45 CET 2010


Revision: 26816
          http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=26816
Author:   nexyon
Date:     2010-02-11 21:09:45 +0100 (Thu, 11 Feb 2010)

Log Message:
-----------
2.5 Audio: The jack backend is now realtime capable and will not produce so much xruns anymore. :-)

Modified Paths:
--------------
    trunk/blender/intern/audaspace/intern/AUD_C-API.cpp
    trunk/blender/intern/audaspace/jack/AUD_JackDevice.cpp
    trunk/blender/intern/audaspace/jack/AUD_JackDevice.h

Modified: trunk/blender/intern/audaspace/intern/AUD_C-API.cpp
===================================================================
--- trunk/blender/intern/audaspace/intern/AUD_C-API.cpp	2010-02-11 19:56:56 UTC (rev 26815)
+++ trunk/blender/intern/audaspace/intern/AUD_C-API.cpp	2010-02-11 20:09:45 UTC (rev 26816)
@@ -113,7 +113,7 @@
 #endif
 #ifdef WITH_JACK
 		case AUD_JACK_DEVICE:
-			dev = new AUD_JackDevice(specs);
+			dev = new AUD_JackDevice(specs, buffersize);
 			break;
 #endif
 		default:

Modified: trunk/blender/intern/audaspace/jack/AUD_JackDevice.cpp
===================================================================
--- trunk/blender/intern/audaspace/jack/AUD_JackDevice.cpp	2010-02-11 19:56:56 UTC (rev 26815)
+++ trunk/blender/intern/audaspace/jack/AUD_JackDevice.cpp	2010-02-11 20:09:45 UTC (rev 26816)
@@ -31,26 +31,80 @@
 #include <stdio.h>
 #include <stdlib.h>
 
-// AUD_XXX this is not realtime suitable!
+void* AUD_JackDevice::runThread(void* device)
+{
+	((AUD_JackDevice*)device)->updateRingBuffers();
+	return NULL;
+}
+
+void AUD_JackDevice::updateRingBuffers()
+{
+	size_t size, temp;
+	unsigned int samplesize = AUD_SAMPLE_SIZE(m_specs);
+	unsigned int i, j;
+	unsigned int channels = m_specs.channels;
+	sample_t* buffer = m_buffer->getBuffer();
+	float* deinterleave = m_deinterleavebuf->getBuffer();
+
+	pthread_mutex_lock(&m_lock);
+	while(m_valid)
+	{
+		size = jack_ringbuffer_write_space(m_ringbuffers[0]);
+		for(i = 1; i < channels; i++)
+			if((temp = jack_ringbuffer_write_space(m_ringbuffers[i])) < size)
+				size = temp;
+
+		while(size > samplesize)
+		{
+			size /= samplesize;
+			mix((data_t*)buffer, size);
+			for(i = 0; i < channels; i++)
+			{
+				for(j = 0; j < size; j++)
+					deinterleave[i * size + j] = buffer[i + j * channels];
+				jack_ringbuffer_write(m_ringbuffers[i], (char*)(deinterleave + i * size), size * sizeof(float));
+			}
+
+			size = jack_ringbuffer_write_space(m_ringbuffers[0]);
+			for(i = 1; i < channels; i++)
+				if((temp = jack_ringbuffer_write_space(m_ringbuffers[i])) < size)
+					size = temp;
+		}
+
+		pthread_cond_wait(&m_condition, &m_lock);
+	}
+	pthread_mutex_unlock(&m_lock);
+}
+
 int AUD_JackDevice::jack_mix(jack_nframes_t length, void *data)
 {
 	AUD_JackDevice* device = (AUD_JackDevice*)data;
-	unsigned int samplesize = AUD_SAMPLE_SIZE(device->m_specs);
-	if(device->m_buffer->getSize() < samplesize * length)
-		device->m_buffer->resize(samplesize * length);
-	device->mix((data_t*)device->m_buffer->getBuffer(), length);
-
-	float* in = (float*) device->m_buffer->getBuffer();
-	float* out;
+	unsigned int i;
 	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;
+
+	readsamples = AUD_MIN(readsamples / sizeof(float), length);
+
 	for(unsigned int i = 0; i < count; i++)
 	{
-		out = (float*)jack_port_get_buffer(device->m_ports[i], length);
-		for(unsigned int j = 0; j < length; j++)
-			out[j] = in[j * 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_lock)) == 0)
+	{
+		pthread_cond_signal(&(device->m_condition));
+		pthread_mutex_unlock(&(device->m_lock));
+	}
+
 	return 0;
 }
 
@@ -60,7 +114,7 @@
 	device->m_valid = false;
 }
 
-AUD_JackDevice::AUD_JackDevice(AUD_DeviceSpecs specs)
+AUD_JackDevice::AUD_JackDevice(AUD_DeviceSpecs specs, int buffersize)
 {
 	if(specs.channels == AUD_CHANNELS_INVALID)
 		specs.channels = AUD_CHANNELS_STEREO;
@@ -77,8 +131,6 @@
 	if(m_client == NULL)
 		AUD_THROW(AUD_ERROR_JACK);
 
-	m_buffer = new AUD_Buffer(); AUD_NEW("buffer");
-
 	// set callbacks
 	jack_set_process_callback(m_client, AUD_JackDevice::jack_mix, this);
 	jack_on_shutdown(m_client, AUD_JackDevice::jack_shutdown, this);
@@ -98,9 +150,31 @@
 			if(m_ports[i] == NULL)
 				AUD_THROW(AUD_ERROR_JACK);
 		}
+	}
+	catch(AUD_Exception)
+	{
+		jack_client_close(m_client);
+		delete[] m_ports; AUD_DELETE("jack_port")
+		throw;
+	}
 
-		m_specs.rate = (AUD_SampleRate)jack_get_sample_rate(m_client);
+	m_specs.rate = (AUD_SampleRate)jack_get_sample_rate(m_client);
 
+	buffersize /= 256;
+	buffersize *= m_specs.rate;
+	buffersize /= 4 * sizeof(sample_t);
+	buffersize *= sizeof(sample_t);
+	m_ringbuffers = new jack_ringbuffer_t*[specs.channels]; AUD_NEW("jack_buffers")
+	for(unsigned int i = 0; i < specs.channels; i++)
+		m_ringbuffers[i] = jack_ringbuffer_create(buffersize);
+	buffersize *= specs.channels;
+	m_buffer = new AUD_Buffer(buffersize); AUD_NEW("buffer");
+	m_deinterleavebuf = new AUD_Buffer(buffersize); AUD_NEW("buffer");
+
+	create();
+
+	try
+	{
 		// activate the client
 		if(jack_activate(m_client))
 			AUD_THROW(AUD_ERROR_JACK);
@@ -110,6 +184,11 @@
 		jack_client_close(m_client);
 		delete[] m_ports; AUD_DELETE("jack_port")
 		delete m_buffer; AUD_DELETE("buffer");
+		delete m_deinterleavebuf; AUD_DELETE("buffer");
+		for(unsigned int i = 0; i < specs.channels; i++)
+			jack_ringbuffer_free(m_ringbuffers[i]);
+		delete[] m_ringbuffers; AUD_DELETE("jack_buffers")
+		destroy();
 		throw;
 	}
 
@@ -125,17 +204,38 @@
 
 	m_valid = true;
 
-	create();
+	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_attr_destroy(&attr);
 }
 
 AUD_JackDevice::~AUD_JackDevice()
 {
-	lock();
 	if(m_valid)
 		jack_client_close(m_client);
+	m_valid = false;
+
 	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_cond_destroy(&m_condition);
+	pthread_mutex_destroy(&m_lock);
 	delete m_buffer; AUD_DELETE("buffer");
-	unlock();
+	delete m_deinterleavebuf; AUD_DELETE("buffer");
+	for(unsigned int i = 0; i < m_specs.channels; i++)
+		jack_ringbuffer_free(m_ringbuffers[i]);
+	delete[] m_ringbuffers; AUD_DELETE("jack_buffers")
 
 	destroy();
 }

Modified: trunk/blender/intern/audaspace/jack/AUD_JackDevice.h
===================================================================
--- trunk/blender/intern/audaspace/jack/AUD_JackDevice.h	2010-02-11 19:56:56 UTC (rev 26815)
+++ trunk/blender/intern/audaspace/jack/AUD_JackDevice.h	2010-02-11 20:09:45 UTC (rev 26816)
@@ -31,6 +31,7 @@
 class AUD_Buffer;
 
 #include <jack.h>
+#include <ringbuffer.h>
 
 /**
  * This device plays back through Jack.
@@ -53,6 +54,8 @@
 	 */
 	AUD_Buffer* m_buffer;
 
+	AUD_Buffer* m_deinterleavebuf;
+
 	/**
 	 * Whether the device is valid.
 	 */
@@ -72,6 +75,21 @@
 	 */
 	static int jack_mix(jack_nframes_t length, void *data);
 
+	static void* runThread(void* device);
+
+	void updateRingBuffers();
+
+	jack_ringbuffer_t** m_ringbuffers;
+
+	/**
+	 * The streaming thread.
+	 */
+	pthread_t m_thread;
+
+	pthread_mutex_t m_lock;
+
+	pthread_cond_t m_condition;
+
 protected:
 	virtual void playing(bool playing);
 
@@ -81,7 +99,7 @@
 	 * \param specs The wanted audio specification, where only the channel count is important.
 	 * \exception AUD_Exception Thrown if the audio device cannot be opened.
 	 */
-	AUD_JackDevice(AUD_DeviceSpecs specs);
+	AUD_JackDevice(AUD_DeviceSpecs specs, int buffersize = AUD_DEFAULT_BUFFER_SIZE);
 
 	/**
 	 * Closes the Jack client.





More information about the Bf-blender-cvs mailing list