[Sugar-devel] [PATCH TamTam 1/2 v2] Output to ALSA directly from csound

Gonzalo Odiard gonzalo at laptop.org
Thu May 2 09:44:23 EDT 2013


Thanks Daniel.
Two questions:
when was the change done? I mean, what sugar version should we mark as
compatible
with a activity with this change?

The second is, if you already have the binaries compiled for every xo,
if you can send me the binaries, I don't need do it again.

Gonzalo


On Wed, May 1, 2013 at 12:25 PM, Daniel Drake <dsd at laptop.org> wrote:

> 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.
> ---
>  common/Config.py                |   5 -
>  common/Resources/tamtamorc.csd  |   2 +-
>  common/Util/CSoundClient.py     |   4 +-
>  common/Util/Clooper/Makefile    |   4 +-
>  common/Util/Clooper/aclient.cpp | 127 +++------------------
>  common/Util/Clooper/audio.cpp   | 237
> ----------------------------------------
>  6 files changed, 17 insertions(+), 362 deletions(-)
>  delete mode 100644 common/Util/Clooper/audio.cpp
>
> v2: totally remove dependency on ALSA header and library
>
> diff --git a/common/Config.py b/common/Config.py
> index b1c1318..bb9c3ff 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 = 1024
> -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..4fddb2e 100644
> --- a/common/Util/Clooper/Makefile
> +++ b/common/Util/Clooper/Makefile
> @@ -15,7 +15,7 @@ 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)
> @@ -23,7 +23,7 @@ all : 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/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 at 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
> --
> 1.8.1.4
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.sugarlabs.org/archive/sugar-devel/attachments/20130502/3a733d06/attachment-0001.html>


More information about the Sugar-devel mailing list