Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGonzalo Odiard <godiard@gmail.com>2013-05-02 21:07:23 (GMT)
committer Gonzalo Odiard <godiard@gmail.com>2013-05-02 21:07:23 (GMT)
commit9e987a46e1365bdc82a9d8516740f43ce9c32fb9 (patch)
tree67635703e02edf63e0f701fe094f4930aed0ac4c
parentb1e39bb668516e55128b6c8e3264f4267df0db68 (diff)
Output to ALSA directly from csound
TamTam sound is crackly on some setups (e.g. XO-1.5 and newer with dmix running at 48000Hz). Clooper seems to implement its own ALSA sample rate resampling, as well as upsampling of the period rate to overcome any differences in csound period size and ALSA period size. This code is the cause of the crackles. Switch to csound's internal ALSA backend, which works well, and does not have these problems. Tested on XO-1, XO-1.5, XO-1.75 and XO-4. Signed-off-by: Daniel Drake <dsd@laptop.org>
-rw-r--r--common/Config.py5
-rw-r--r--common/Resources/tamtamorc.csd2
-rw-r--r--common/Util/CSoundClient.py4
-rw-r--r--common/Util/Clooper/Makefile5
-rw-r--r--common/Util/Clooper/aclient.cpp127
-rwxr-xr-xcommon/Util/Clooper/armv7l_510/aclient.sobin226576 -> 0 bytes
-rw-r--r--common/Util/Clooper/armv7l_513/__init__.py (renamed from common/Util/Clooper/armv7l_510/__init__.py)0
-rw-r--r--common/Util/Clooper/armv7l_513/aclient.sobin0 -> 26964 bytes
-rw-r--r--common/Util/Clooper/audio.cpp237
-rwxr-xr-xcommon/Util/Clooper/linux32_510/aclient.sobin230425 -> 0 bytes
-rw-r--r--common/Util/Clooper/linux32_513/__init__.py (renamed from common/Util/Clooper/linux32_510/__init__.py)0
-rw-r--r--common/Util/Clooper/linux32_513/aclient.sobin0 -> 30720 bytes
-rwxr-xr-xcommon/Util/Clooper/linux64_/aclient.sobin275125 -> 36088 bytes
13 files changed, 18 insertions, 362 deletions
diff --git a/common/Config.py b/common/Config.py
index 835765f..e9a65e6 100644
--- a/common/Config.py
+++ b/common/Config.py
@@ -55,13 +55,8 @@ for i in (INSTANCE_DIR, DATA_DIR, SNDS_INFO_DIR, TMP_DIR):
PLUGIN_DEBUG = os.getenv("CSOUND_LOGFILE", "")
PLUGIN_VERBOSE = DEBUG
PLUGIN_UNIVORC = join(FILES_DIR, "tamtamorc.csd")
-PLUGIN_KSMPS = 64
PLUGIN_RATE = 16000
-## PLUGIN ALSA PARAMETERS:
-PLUGIN_PERIOD = 256 # 512
-PLUGIN_NPERIODS = 2
-
try:
from sugar3.graphics.toolbarbox import ToolbarBox, ToolbarButton
HAVE_TOOLBOX = True
diff --git a/common/Resources/tamtamorc.csd b/common/Resources/tamtamorc.csd
index f0a63f1..3adf81b 100644
--- a/common/Resources/tamtamorc.csd
+++ b/common/Resources/tamtamorc.csd
@@ -1,6 +1,6 @@
<CsoundSynthesizer>
<CsOptions>
--n -m0 -W -s -d
+-n -odac -m0 -W -s -d
</CsOptions>
<CsInstruments>
sr=16000
diff --git a/common/Util/CSoundClient.py b/common/Util/CSoundClient.py
index 3cf6794..c082137 100644
--- a/common/Util/CSoundClient.py
+++ b/common/Util/CSoundClient.py
@@ -47,9 +47,7 @@ class _CSoundClientPlugin:
def __init__(self):
sc_initialize( Config.PLUGIN_UNIVORC, Config.PLUGIN_DEBUG,
- Config.PLUGIN_PERIOD, Config.PLUGIN_NPERIODS,
- Config.PLUGIN_VERBOSE,
- Config.PLUGIN_KSMPS, Config.PLUGIN_RATE)
+ Config.PLUGIN_VERBOSE, Config.PLUGIN_RATE)
self.on = False
#self.masterVolume = 100.0
self.periods_per_buffer = 2
diff --git a/common/Util/Clooper/Makefile b/common/Util/Clooper/Makefile
index 0f28366..1a5a3c1 100644
--- a/common/Util/Clooper/Makefile
+++ b/common/Util/Clooper/Makefile
@@ -15,15 +15,16 @@ LIB_NAME = $(CSOUND_ARCH)_$(CSOUND_VERSION)
CXXFLAGS = $(shell python-config --cflags) \
-Wall -Werror -fPIC -O2 -finline
LDFLAGS+= $(python-config --libs) \
- -lasound -lcsound
+ -lcsound
all : aclient.so
rm -rf $(LIB_NAME)
mkdir $(LIB_NAME)
+ strip aclient.so
mv aclient.so $(LIB_NAME)/
touch $(LIB_NAME)/__init__.py
-aclient.so : aclient.cpp audio.cpp
+aclient.so : aclient.cpp
g++ $(CXXFLAGS) -shared -o $@ $< $(LDFLAGS)
clean :
diff --git a/common/Util/Clooper/aclient.cpp b/common/Util/Clooper/aclient.cpp
index f238c36..e68b8cb 100644
--- a/common/Util/Clooper/aclient.cpp
+++ b/common/Util/Clooper/aclient.cpp
@@ -12,20 +12,8 @@
#include <cmath>
#include <csound/csound.h>
-#include <alsa/asoundlib.h>
-static double pytime(const struct timeval * tv)
-{
- struct timeval t;
- if (!tv)
- {
- tv = &t;
- gettimeofday(&t, NULL);
- }
- return (double) tv->tv_sec + (double) tv->tv_usec / 1000000.0;
-}
#include "log.cpp"
-#include "audio.cpp"
int VERBOSE = 3;
@@ -510,52 +498,31 @@ struct TamTamSound
MYFLT tick_total;
/** the upsampling ratio from csound */
- unsigned int csound_ksmps;
- snd_pcm_uframes_t csound_frame_rate;
- snd_pcm_uframes_t csound_period_size;
- snd_pcm_uframes_t period0;
- unsigned int period_per_buffer; //should be 2
- int up_ratio; //if the hardware only supports a small integer multiple of our effective samplerate, do a real-time conversion
+ int csound_frame_rate;
+ long csound_period_size;
log_t * ll;
- SystemStuff * sys_stuff;
- TamTamSound(log_t * ll, char * orc, snd_pcm_uframes_t period0, unsigned int ppb, int ksmps, int framerate )
+ TamTamSound(log_t * ll, char * orc, int framerate )
: ThreadID(NULL), PERF_STATUS(STOP), csound(NULL),
music(),
ticks_per_period(0.0),
tick_adjustment(0.0),
tick_total(0.0),
- csound_ksmps(ksmps), //must agree with the orchestra file
csound_frame_rate(framerate), //must agree with the orchestra file
- period0(period0),
- period_per_buffer(ppb),
- up_ratio(1),
- ll( ll ),
- sys_stuff(NULL)
+ ll( ll )
{
- sys_stuff = new SystemStuff(ll);
- if (0 > sys_stuff->open(csound_frame_rate, 4, period0, period_per_buffer))
- {
- return;
- }
- sys_stuff->close(0);
- up_ratio = sys_stuff->rate / csound_frame_rate;
- csound_period_size = (sys_stuff->period_size % up_ratio == 0)
- ? sys_stuff->period_size / up_ratio
- : csound_ksmps * 4;
-
csound = csoundCreate(NULL);
- int argc=3;
+ int argc=4;
const char **argv = (const char**)malloc(argc*sizeof(char*));
argv[0] = "csound";
argv[1] = "-m0";
- argv[2] = orc;
+ argv[2] = "-+rtaudio=alsa";
+ argv[3] = orc;
ll->printf(1, "loading csound orchestra file %s\n", orc);
//csoundInitialize(&argc, &argv, 0);
csoundPreCompile(csound);
- csoundSetHostImplementedAudioIO(csound, 1, csound_period_size);
int result = csoundCompile(csound, argc, (char**)argv);
if (result)
{
@@ -563,6 +530,8 @@ struct TamTamSound
ll->printf( "ERROR: csoundCompile of orchestra %s failed with code %i\n", orc, result);
}
free(argv);
+ csound_period_size = csoundGetOutputBufferSize(csound);
+ csound_period_size /= 2; /* channels */
setTickDuration(0.05);
}
~TamTamSound()
@@ -574,7 +543,6 @@ struct TamTamSound
csoundDestroy(csound);
}
ll->printf(2, "TamTamSound destroyed\n");
- if (sys_stuff) delete sys_stuff;
delete ll;
}
bool good()
@@ -586,76 +554,10 @@ struct TamTamSound
{
assert(csound);
- const int nchannels = 2;
- int nloops = 0;
- long int csound_nsamples = csoundGetOutputBufferSize(csound);
- long int csound_nframes = csound_nsamples / nchannels;
-
- ll->printf(2, "INFO: nsamples = %li nframes = %li\n", csound_nsamples, csound_nframes);
-
- if (0 > sys_stuff->open(csound_frame_rate, 4, period0, period_per_buffer))
- {
- ll->printf( "ERROR: failed to open alsa device, thread abort\n");
- return 1;
- }
-
- assert(up_ratio == (signed)(sys_stuff->rate / csound_frame_rate));
-
- bool do_upsample = (signed)sys_stuff->period_size != csound_nframes;
- short *upbuf = new short[ sys_stuff->period_size * nchannels ];
- int cbuf_pos = csound_nframes; // trigger a call to csoundPerformBuffer immediately
- float *cbuf = NULL;
- int up_pos = 0;
- int ratio_pos = 0;
-
tick_total = 0.0f;
-
while (PERF_STATUS == CONTINUE)
{
- if ( do_upsample ) //fill one period of audio buffer data by 0 or more calls to csound
- {
- up_pos = 0;
- int messed = 0;
- short cursample[2]={0,0};
- while(!messed)
- {
- if (cbuf_pos == csound_nframes)
- {
- cbuf_pos = 0;
- if (csoundPerformBuffer(csound)) { messed = 1;break;}
- cbuf = csoundGetOutputBuffer(csound);
- cursample[0] = (signed short int) (cbuf[cbuf_pos*2+0] * (1<<15));
- cursample[1] = (signed short int) (cbuf[cbuf_pos*2+1] * (1<<15));
-
- }
- upbuf[2*up_pos+0] = cursample[0];
- upbuf[2*up_pos+1] = cursample[1];
- if (++ratio_pos == up_ratio)
- {
- ratio_pos = 0;
- ++cbuf_pos;
- cursample[0] = (signed short int) (cbuf[cbuf_pos*2+0] * (1<<15));
- cursample[1] = (signed short int) (cbuf[cbuf_pos*2+1] * (1<<15));
- }
-
- if (++up_pos == (signed)sys_stuff->period_size) break;
- }
- if (messed || (up_pos != (signed)sys_stuff->period_size)) break;
-
- if (0 > sys_stuff->writebuf(sys_stuff->period_size, upbuf)) break;
- }
- else //fill one period of audio directly from csound
- {
- if (csoundPerformBuffer(csound)) break;
- cbuf = csoundGetOutputBuffer(csound);
- for (int i = 0; i < csound_nframes * nchannels; ++i)
- {
- cbuf[i] *= (float) ((1<<15)-100.0f);
- upbuf[i] = (signed short int) cbuf[i];
- }
- if (0 > sys_stuff->writebuf(csound_nframes,upbuf)) break;
- }
-
+ if (csoundPerformBuffer(csound)) break;
if (tick_adjustment > - ticks_per_period)
{
MYFLT tick_inc = ticks_per_period + tick_adjustment;
@@ -667,11 +569,8 @@ struct TamTamSound
{
tick_adjustment += ticks_per_period;
}
- ++nloops;
}
- sys_stuff->close(1);
- delete [] upbuf;
ll->printf(2, "INFO: performance thread returning 0\n");
return 0;
}
@@ -820,8 +719,8 @@ DECL(sc_initialize) //(char * csd)
{
char * str;
char * log_file;
- int period, ppb, ksmps, framerate;
- if (!PyArg_ParseTuple(args, "ssiiiii", &str, &log_file, &period, &ppb, &VERBOSE, &ksmps, &framerate ))
+ int framerate;
+ if (!PyArg_ParseTuple(args, "ssii", &str, &log_file, &VERBOSE, &framerate ))
{
return NULL;
}
@@ -840,7 +739,7 @@ DECL(sc_initialize) //(char * csd)
fprintf(stderr, "Logging disabled on purpose\n");
}
g_log = new log_t(_debug, VERBOSE);
- g_tt = new TamTamSound(g_log, str, period, ppb, ksmps, framerate);
+ g_tt = new TamTamSound(g_log, str, framerate);
g_music = & g_tt->music;
atexit(&cleanup);
if (g_tt->good())
diff --git a/common/Util/Clooper/armv7l_510/aclient.so b/common/Util/Clooper/armv7l_510/aclient.so
deleted file mode 100755
index f1ec578..0000000
--- a/common/Util/Clooper/armv7l_510/aclient.so
+++ /dev/null
Binary files differ
diff --git a/common/Util/Clooper/armv7l_510/__init__.py b/common/Util/Clooper/armv7l_513/__init__.py
index e69de29..e69de29 100644
--- a/common/Util/Clooper/armv7l_510/__init__.py
+++ b/common/Util/Clooper/armv7l_513/__init__.py
diff --git a/common/Util/Clooper/armv7l_513/aclient.so b/common/Util/Clooper/armv7l_513/aclient.so
new file mode 100644
index 0000000..fe50a03
--- /dev/null
+++ b/common/Util/Clooper/armv7l_513/aclient.so
Binary files differ
diff --git a/common/Util/Clooper/audio.cpp b/common/Util/Clooper/audio.cpp
deleted file mode 100644
index 6f5a271..0000000
--- a/common/Util/Clooper/audio.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-#ifndef AUDIO_HXX
-#define AUDIO_HXX
-
-/*
- * Latency test program
- *
- * Author: Jaroslav Kysela <perex@suse.cz>
- *
- * This small demo program can be used for measuring latency between
- * capture and playback. This latency is measured from driver (diff when
- * playback and capture was started). Scheduler is set to SCHED_RR.
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sched.h>
-#include <errno.h>
-#include <getopt.h>
-#include <sys/time.h>
-#include <math.h>
-
-#include <string>
-#include <alsa/asoundlib.h>
-
-#define ERROR_HERE ll->printf("ERROR_HERE: %s %i\n", __FILE__, __LINE__)
-
-struct SystemStuff
-{
- log_t * ll;
-
- snd_pcm_t *phandle;
- snd_pcm_uframes_t period_size;
- unsigned int rate;
- const snd_pcm_format_t sample_format;
- SystemStuff(log_t * ll) : ll(ll), phandle(NULL), period_size(0), rate(0), sample_format(SND_PCM_FORMAT_S16)
- {
- }
- ~SystemStuff()
- {
- if (phandle) close(0);
- }
-
- void setscheduler(void)
- {
- struct sched_param sched_param;
-
- if (sched_getparam(0, &sched_param) < 0) {
- ll->printf( "Scheduler getparam failed...\n");
- return;
- }
- sched_param.sched_priority = sched_get_priority_max(SCHED_RR);
- if (!sched_setscheduler(0, SCHED_RR, &sched_param)) {
- ll->printf( "Scheduler set to Round Robin with priority %i...\n", sched_param.sched_priority);
- return;
- }
- ll->printf( "!!!Scheduler set to Round Robin with priority %i FAILED!!!\n", sched_param.sched_priority);
- }
-
- int open(unsigned int rate0, int upsample_max, snd_pcm_uframes_t period0, unsigned int p_per_buff)
- {
- snd_pcm_hw_params_t *hw;
-
- if (phandle)
- {
- ll->printf( "ERROR: open called twice! First close the sound device\n");
- return -1;
- }
-
- if ( 0 > snd_pcm_open(&phandle, "default", SND_PCM_STREAM_PLAYBACK, 0)) { ERROR_HERE; return -1; }
- if ( 0 > snd_pcm_hw_params_malloc(&hw)) { ERROR_HERE; snd_pcm_close(phandle); phandle = NULL; return -1; }
-
- //now we can be a bit flexible with the buffer size and the sample-rate...
-
- int upsample;
- for (upsample = 1; upsample < upsample_max; ++upsample)
- {
- rate = rate0 * upsample;
-
- if ( 0 > snd_pcm_hw_params_any(phandle, hw)) { ERROR_HERE; goto open_error;}
-
- //first do the compulsory steps... interleaved float, 2 channel
- if ( 0 > snd_pcm_hw_params_set_rate_resample(phandle, hw, 0)) { ERROR_HERE; goto open_error;}
- if ( 0 > snd_pcm_hw_params_test_access(phandle, hw, SND_PCM_ACCESS_RW_INTERLEAVED)){ ERROR_HERE; goto open_error;}
- if ( 0 > snd_pcm_hw_params_set_access(phandle, hw, SND_PCM_ACCESS_RW_INTERLEAVED)){ ERROR_HERE; goto open_error;}
- if ( 0 > snd_pcm_hw_params_test_format(phandle, hw, sample_format)) { ERROR_HERE; goto open_error;}
- if ( 0 > snd_pcm_hw_params_set_format(phandle, hw, sample_format)) { ERROR_HERE; goto open_error;}
- if ( 0 > snd_pcm_hw_params_set_channels(phandle, hw, 2)) { ERROR_HERE; goto open_error;}
-
- if ( snd_pcm_hw_params_set_rate_near(phandle, hw, &rate, 0))
- {
- ll->printf("test_rate failed( %i\n", rate);
- continue;
- }
- else
- {
- ll->printf(1, "success! setting rate : %i\n", rate);
-
- snd_pcm_uframes_t minb=0, maxb= 0;
- int mind=0, maxd=0;
- snd_pcm_hw_params_get_period_size_min(hw, &minb,&mind);
- snd_pcm_hw_params_get_period_size_max(hw, &maxb,&maxd);
- ll->printf(2, "FYI: period size range is [%li/%i,%li/%i]\n", minb,mind, maxb, maxd);
-
- if ((mind != 0) || (maxd == 0))
- {
- ll->printf(2, "watch out, mind and maxd non-zero... you didn't set rate_resample to 0 did you...\n");
- }
-
- if (period0 < minb)
- {
- ll->printf(1, "requested period size (%li) < min (%li), adjusting to min\n", period_size, minb);
- period_size = minb;
- }
- else if (period0 > maxb)
- {
- ll->printf(2, "requested period size (%li) < max (%li), adjusting to min\n", period_size, maxb);
- period_size = maxb;
- }
- else
- {
- period_size = period0;
- }
-
- ll->printf(1, "testing period size : %li\n", period_size);
- if ( 0 > snd_pcm_hw_params_test_period_size(phandle, hw, period_size, 0)){ ERROR_HERE; goto open_error;}
-
-
- ll->printf(1, "setting period size : %li\n", period_size);
- if ( 0 > snd_pcm_hw_params_set_period_size_near(phandle, hw, &period_size, 0)){ ERROR_HERE; goto open_error;}
-
- ll->printf(1, "setting buffer size : %i * %li = %li\n", p_per_buff, period_size, p_per_buff * period_size);
- snd_pcm_uframes_t buff_size = p_per_buff * period_size;
- if ( 0 > snd_pcm_hw_params_set_buffer_size_near(phandle, hw, &buff_size)) { ERROR_HERE; goto open_error;}
-
- break;
- }
- }
-
- if (upsample_max == upsample) { ERROR_HERE; goto open_error; }
-
- if (0 > snd_pcm_hw_params(phandle, hw)) { ERROR_HERE; goto open_error; }
-
- snd_pcm_hw_params_free (hw);
- return 0;
-
-open_error:
- snd_pcm_hw_params_free (hw);
- snd_pcm_close(phandle);
- phandle = NULL;
- return -1;
- }
- void close(int drain = 0)
- {
- if (!phandle)
- {
- ll->printf(0, "WARNING: attempt to close already-closed pcm\n");
- return;
- }
- ll->printf(1, "INFO: closing phandle device\n");
- if (drain) snd_pcm_drain(phandle);
- snd_pcm_close(phandle);
- phandle = NULL;
- }
- void prepare()
- {
- if (!phandle)
- {
- ll->printf(0, "ERROR: attempt to prepare a closed pcm\n");
- return;
- }
- if (0 > snd_pcm_prepare(phandle)) { ERROR_HERE; }
- }
- int writebuf(snd_pcm_uframes_t frame_count, short int * frame_data)
- {
- if (!phandle)
- {
- ll->printf(0, "ERROR: attempt to write a closed phandle\n");
- return -1;
- }
- int err = 0;
- while (frame_count > 0) {
- err = snd_pcm_writei (phandle, frame_data, frame_count );
- if (err == (signed)frame_count) return 0; //success
- if (err == -EAGAIN)
- continue;
- if (err < 0)
- break;
- frame_data += err * 4;
- frame_count -= err;
- }
-
- if (err >= 0)
- {
- ll->printf(0, "madness on line %s:%i\n", __FILE__, __LINE__);
- return -1;
- }
-
- const char * msg = NULL;
- snd_pcm_state_t state = snd_pcm_state(phandle);
- switch (state)
- {
- case SND_PCM_STATE_OPEN: msg = "open"; break;
- case SND_PCM_STATE_SETUP: msg = "setup"; break;
- case SND_PCM_STATE_PREPARED:msg = "prepared"; break;
- case SND_PCM_STATE_RUNNING: msg = "running"; break;
- case SND_PCM_STATE_XRUN: msg = "xrun"; break;
- case SND_PCM_STATE_DRAINING: msg = "draining"; break;
- case SND_PCM_STATE_PAUSED: msg = "paused"; break;
- case SND_PCM_STATE_SUSPENDED: msg = "suspended"; break;
- case SND_PCM_STATE_DISCONNECTED: msg = "disconnected"; break;
- }
- ll->printf(1, "WARNING: write failed (%s)\tstate = %s\ttime=%lf\n", snd_strerror (err), msg, pytime(NULL));
- if (0 > snd_pcm_recover(phandle, err, 0)) { ERROR_HERE; return err;}
- if (0 > snd_pcm_prepare(phandle)) { ERROR_HERE; return err;}
- return 1; //warning
- }
-};
-#undef ERROR_HERE
-
-#endif
diff --git a/common/Util/Clooper/linux32_510/aclient.so b/common/Util/Clooper/linux32_510/aclient.so
deleted file mode 100755
index 60bca73..0000000
--- a/common/Util/Clooper/linux32_510/aclient.so
+++ /dev/null
Binary files differ
diff --git a/common/Util/Clooper/linux32_510/__init__.py b/common/Util/Clooper/linux32_513/__init__.py
index e69de29..e69de29 100644
--- a/common/Util/Clooper/linux32_510/__init__.py
+++ b/common/Util/Clooper/linux32_513/__init__.py
diff --git a/common/Util/Clooper/linux32_513/aclient.so b/common/Util/Clooper/linux32_513/aclient.so
new file mode 100644
index 0000000..4f04b12
--- /dev/null
+++ b/common/Util/Clooper/linux32_513/aclient.so
Binary files differ
diff --git a/common/Util/Clooper/linux64_/aclient.so b/common/Util/Clooper/linux64_/aclient.so
index 96893b5..eb9eddf 100755
--- a/common/Util/Clooper/linux64_/aclient.so
+++ b/common/Util/Clooper/linux64_/aclient.so
Binary files differ