[EMAIL PROTECTED] said:
> The unofficial Csound package includes Fred Floberg's code for
> supporting the ALSA drivers. The code enabled two soundcards to be
> used for separated i/o, but alas the code no longer works. 

>   The ALSA API has changed quite a bit since Fred's original work.
> I've made some of the necessary updates, and I can get it to compile,
> but Csound dies with the informative message "Input/output error" when
> I try to run it. ALSA OSS emulation works perfectly (i.e., if you
> don't select  --with-ALSA as a configuration option).

I've hacked Fred Flobergs code to work with my ALSA installation, which is 
0.5.8. I've tested both ALSA interfaces, the "block mode" 
(ALSArtaudio-block.c) and "stream mode" (ALSArtaudio-stream.c), both with the 
mode to start transfer, when data is written to the buffer.

I use "stream mode" ALSArtaudio-stream.c, because transfer starts immediately 
without hearable latency, when data is written to the buffer, whereas with 
"block mode" ALSArtaudio-block.c, sound comes from the speaker with a delay 
approximately around half a second. Is this the right behaviour of block mode 
with start_mode=SND_PCM_START_DATA ? Shouldn't transfer start after writing 
the first fragment to the buffer. It seems that transfer starts, when the 
whole buffer is filled, thus causing the latency.

With ALSArtaudio-stream.c I'm able to record sound, do some reverbs or 
something like that on it and immediately play it back with very low latency 
(I don't hear it).
This "stream mode" works well with my trident-4dwave-nx card. Using "stream 
mode" with my ess solo1 card hangs up my machine, but block mode works with 
rather low latency, because the transfer buffer is small :-)

Markus
/* ALSArtaudio.c - hacked version of rtaudio.c to enable realtime full-duplex
 audio support for csound under Linux/ALSA.
This file incorporates the functions from LINUXaudio.c (with the exception of
sndsetvolume() which isn't used in this hacked version) so that file is no
longer needed  - fcf */
/*
 * $Id: ALSArtaudio.c,v 1.6 1999/06/23 18:23:57 nicb Exp $
 */

/*  This module is included when RTAUDIO is defined at compile time.
    It provides an interface between Csound realtime record/play calls
    and the device-driver code that controls the actual hardware.
*/

/* This is an updated version of the csound to ALSA interface,
   and works with latest ALSA 0.5.8.
   The code in this file (ALSArtaudio-block.c) uses the ALSA block transfer
   mode. You may want to use stream transfer mode (look at
   ALSArtaudio-stream.c), which is faster (much less latency = much more
   realtime than the block mode version used in this file).
   -
   Markus Gruber <[EMAIL PROTECTED]>
   */

#include <sys/asoundlib.h>
#include "cs.h"
#include "soundio.h"

static snd_pcm_t *capture_handle = NULL, *playback_handle = NULL;

extern  long    nrecs;
extern  OPARMS  O;

#ifdef PIPES
extern FILE* Linepipe;
#define _pclose pclose
#endif

char errorstring[1024];

static int getformat()
{
        int p = 0;

        switch ( O.informat ) {
                case AE_UNCH:  /* unsigned char - standard Linux 8-bit format */
                        p = SND_PCM_SFMT_U8;
                        break;
                case AE_CHAR:  /* signed char. supported by ALSA */
                        p = SND_PCM_SFMT_S8;
                        break;
                case AE_ULAW:
                        p = SND_PCM_SFMT_MU_LAW; 
                        break;
                case AE_ALAW:
                        p = SND_PCM_SFMT_A_LAW;
                        break;
                case AE_SHORT:
                        p = SND_PCM_SFMT_S16_LE; /* Linux on Intel x86 is 
little-endian */
                        break;
                case AE_LONG:
                        die("ALSA sound driver does not (yet) support long integer 
samples");
                case AE_FLOAT:
                        die("ALSA sound driver does not (yet) support floating-point 
samples");
                default:
                        die("unknown sample format");
        }
        return (p);
}

void recopen(int nchnls, int dsize, FLOAT esr, int scale)
                                /* open for audio input */
{
        extern int incard;
        static snd_pcm_channel_params_t params;
        int err;
        char *cardname;

        if ((err = snd_card_get_longname(incard, &cardname))) {
                sprintf(errorstring, "%s\n", snd_strerror(err));
                die(errorstring);
        }
        fprintf(stderr, "ALSA incard: %s\n", cardname);

        /* Open ALSA audio driver, card #incard, device #0 in CAPTURE mode */
        if((err = snd_pcm_open(&capture_handle, incard, 0, SND_PCM_OPEN_CAPTURE))){
                sprintf(errorstring, "Opening CAPTURE channel: %s\n", 
snd_strerror(err));
                die(errorstring);
        }

        memset(&params, 0, sizeof(snd_pcm_channel_params_t));
        
        params.channel = SND_PCM_CHANNEL_CAPTURE;
        params.mode    = SND_PCM_MODE_BLOCK;
        
        params.format.interleave = 1;
        params.format.format     = getformat();
        params.format.rate       = (int)esr;
        params.format.voices     = nchnls;

        /* digital */
        params.start_mode = SND_PCM_START_DATA;
        params.stop_mode  = SND_PCM_STOP_ROLLOVER;
        params.buf.block.frag_size = O.outbufsamps * O.outsampsiz;
        
        params.buf.block.frags_min = 1;
        params.buf.block.frags_max = -1;
        
        if ((err = snd_pcm_plugin_params(capture_handle, &params))) {
                sprintf(errorstring, "CAPTURE channel parameterizing error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        if ((err = snd_pcm_plugin_prepare(capture_handle, SND_PCM_CHANNEL_CAPTURE))) {
                sprintf(errorstring, "CAPTURE channel prepare error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }

        fprintf(stderr, "Running CAPTURE mode at %d hz on card #%d\n", 
params.format.rate, incard);
}

void playopen(int nchnls, int dsize, FLOAT esr, int scale)
                                /* open for audio output */
{
        extern int outcard;
        static snd_pcm_channel_params_t params;
        int err;
        char *cardname;

        if ((err = snd_card_get_longname(outcard, &cardname))) {
                sprintf(errorstring, "%s\n", snd_strerror(err));
                die(errorstring);
        }
        fprintf(stderr, "ALSA outcard: %s\n", cardname);

        /* Open ALSA audio driver, card # outcard, device #0 in PLAYBACK mode */
        if((err = snd_pcm_open(&playback_handle, outcard, 0, SND_PCM_OPEN_PLAYBACK))){
                sprintf(errorstring, "Opening PLAYBACK channel: %s\n", 
snd_strerror(err));
                die(errorstring);
        }

        memset(&params, 0, sizeof(snd_pcm_channel_params_t));
        
        params.channel = SND_PCM_CHANNEL_PLAYBACK;
        params.mode    = SND_PCM_MODE_BLOCK;
        
        params.format.interleave = 1;
        params.format.format     = getformat();
        params.format.rate       = (int)esr;
        params.format.voices     = nchnls;

        /* digital */
        params.start_mode = SND_PCM_START_DATA;
        params.stop_mode  = SND_PCM_STOP_ROLLOVER;
        
        params.buf.block.frag_size = O.outbufsamps * O.outsampsiz;
        params.buf.block.frags_min = 1;
        params.buf.block.frags_max = -1;
        
        if ((err = snd_pcm_plugin_params(playback_handle, &params))) {
                sprintf(errorstring, "PLAYBACK channel parameterizing error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        if ((err = snd_pcm_plugin_prepare(playback_handle, SND_PCM_CHANNEL_PLAYBACK))) 
{
                sprintf(errorstring, "PLAYBACK channel prepare error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        
        fprintf(stderr, "Running PLAYBACK mode at %d hz on card #%d\n", 
params.format.rate, outcard);

#ifdef HIPRI
        setscheduler();
#endif
}

int rtrecord(char *inbuf, int nbytes) /* get samples from ADC */
{
        int fragsize, count, x=0, i, limit;
        char *buf;
        /* fprintf(stderr, "reading %d bytes from DAC\n", nbytes); */
        fragsize = O.outbufsamps * O.outsampsiz;
        if (fragsize > nbytes) {
                x = 1;
                buf = (char *)alloca(fragsize);
        } else {
                buf = inbuf;
        }
        if((count = snd_pcm_plugin_read(capture_handle, (void *)buf, 
(size_t)fragsize)) < 0) {
                sprintf(errorstring, "Capture error: %s", snd_strerror(count));
                die(errorstring);
        }
        limit = (count > nbytes ? nbytes : count);
        if (x) {
                for (i=0; i<limit ; i++) {
                        inbuf[i] = buf[i];
                }
        }
        return(limit);
}

void rtplay(char *outbuf, int nbytes) /* put samples to DAC - see notes in rtaudio.c */
{
        int err, fragsize, i;
        char *buf;
        /* fprintf(stderr, "writing %d bytes to DAC\n", nbytes); */
        fragsize = O.outbufsamps * O.outsampsiz;
        if (fragsize > nbytes) {
                buf = (char *)alloca(fragsize);
                memset(buf, 0, fragsize);
                for (i=0; i<nbytes; i++) {
                    buf[i] = outbuf[i];
                }
        } else {
                buf = outbuf;
        }
        if ((err = snd_pcm_plugin_write(playback_handle, (void *)buf, 
(size_t)fragsize)) < fragsize) {
                sprintf(errorstring, "Playback error: %s\n", snd_strerror(err));
                die(errorstring);
        }
        nrecs++;
}

void rtclose(void)              /* close the I/O device entirely  */
{                               /* called only when both complete */
        int err;
        if(capture_handle) {
                if ((err = snd_pcm_close(capture_handle))) {
                        sprintf(errorstring, "CAPTURE channel close error: %s\n", 
snd_strerror(err));
                        die(errorstring);
                }
        }
        if(playback_handle) {
                if ((err = snd_pcm_plugin_playback_drain(playback_handle))) {
                        sprintf(errorstring, "PLAYBACK channel drain error: %s\n", 
snd_strerror(err));
                        die(errorstring);
                }
                if ((err = snd_pcm_close(playback_handle))) {
                        sprintf(errorstring, "PLAYBACK channel close error: %s\n", 
snd_strerror(err));
                        die(errorstring);
                }
        }
        if (O.Linein) {
#ifdef PIPES
          if (O.Linename[0]=='|') _pclose(Linepipe);
#endif
        }
}
/* ALSArtaudio.c - hacked version of rtaudio.c to enable realtime full-duplex
 audio support for csound under Linux/ALSA.
This file incorporates the functions from LINUXaudio.c (with the exception of
sndsetvolume() which isn't used in this hacked version) so that file is no
longer needed  - fcf */
/*
 * $Id: ALSArtaudio.c,v 1.6 1999/06/23 18:23:57 nicb Exp $
 */

/*  This module is included when RTAUDIO is defined at compile time.
    It provides an interface between Csound realtime record/play calls
    and the device-driver code that controls the actual hardware.
*/

/* This file contains an updated version of the csound to ALSA interface.
   It is tested against ALSA 0.5.8.
   Code in this file (ALSArtaudio-stream.c) utilizes the ALSA stream transfer
   interface, which induces much less latency compared to ALSA block mode
   transfer, (look at ALSArtaudio-block.c).
   -
   Markus Gruber <[EMAIL PROTECTED]>
   */

#include <sys/asoundlib.h>
#include "cs.h"
#include "soundio.h"
#include <errno.h>

static snd_pcm_t *capture_handle = NULL, *playback_handle = NULL;

extern  long    nrecs;
static  int     processed = 0;
extern  OPARMS  O;

#ifdef PIPES
extern FILE* Linepipe;
#define _pclose pclose
#endif

char errorstring[1024];

static int getformat()
{
        int p = 0;

        switch ( O.informat ) {
                case AE_UNCH:  /* unsigned char - standard Linux 8-bit format */
                        p = SND_PCM_SFMT_U8;
                        break;
                case AE_CHAR:  /* signed char. supported by ALSA */
                        p = SND_PCM_SFMT_S8;
                        break;
                case AE_ULAW:
                        p = SND_PCM_SFMT_MU_LAW; 
                        break;
                case AE_ALAW:
                        p = SND_PCM_SFMT_A_LAW;
                        break;
                case AE_SHORT:
                        p = SND_PCM_SFMT_S16_LE; /* Linux on Intel x86 is 
little-endian */
                        break;
                case AE_LONG:
                        die("ALSA sound driver does not (yet) support long integer 
samples");
                case AE_FLOAT:
                        die("ALSA sound driver does not (yet) support floating-point 
samples");
                default:
                        die("unknown sample format");
        }
        return (p);
}

void recopen(int nchnls, int dsize, FLOAT esr, int scale)
                                /* open for audio input */
{
        extern int incard;
        static snd_pcm_channel_params_t params;
        int err;
        char *cardname;

        if ((err = snd_card_get_longname(incard, &cardname))) {
                sprintf(errorstring, "%s\n", snd_strerror(err));
                die(errorstring);
        }
        fprintf(stderr, "ALSA incard: %s\n", cardname);

        /* Open ALSA audio driver, card #incard, device #0 in CAPTURE mode */
        if((err = snd_pcm_open(&capture_handle, incard, 0, SND_PCM_OPEN_CAPTURE))){
                sprintf(errorstring, "Opening CAPTURE channel: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        //snd_pcm_channel_flush(capture_handle, SND_PCM_CHANNEL_CAPTURE);       /* be 
in right state */
        
        memset(&params, 0, sizeof(snd_pcm_channel_params_t));
        
        params.channel = SND_PCM_CHANNEL_CAPTURE;
        params.mode = SND_PCM_MODE_STREAM;
        
        params.format.interleave = 1;
        params.format.format     = getformat();
        params.format.rate       = (int)esr;
        params.format.voices     = nchnls;

        /* digital */
        params.start_mode = SND_PCM_START_GO;
        params.stop_mode  = SND_PCM_STOP_ROLLOVER;
        
        params.buf.stream.queue_size = 1024*1024;/* maximum for smooth action
                                                   shorter queue would cause
                                                   less latency, but is more
                                                   choppy */
        params.buf.stream.fill = SND_PCM_FILL_SILENCE_WHOLE;
        params.buf.stream.max_fill = 1024;
        
        if ((err = snd_pcm_plugin_params(capture_handle, &params))) {
                sprintf(errorstring, "CAPTURE channel parameterizing error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        if ((err = snd_pcm_plugin_prepare(capture_handle, SND_PCM_CHANNEL_CAPTURE))) {
                sprintf(errorstring, "CAPTURE channel prepare error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        if ((err = snd_pcm_channel_go(capture_handle, SND_PCM_CHANNEL_CAPTURE))) {
                sprintf(errorstring, "CAPTURE channel go error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        
        fprintf(stderr, "Running CAPTURE mode at %d hz on card #%d\n", 
params.format.rate, incard);
}

void playopen(int nchnls, int dsize, FLOAT esr, int scale)
                                /* open for audio output */
{
        extern int outcard;
        static snd_pcm_channel_params_t params;
        int err;
        char *cardname;

        if ((err = snd_card_get_longname(outcard, &cardname))) {
                sprintf(errorstring, "%s\n", snd_strerror(err));
                die(errorstring);
        }
        fprintf(stderr, "ALSA outcard: %s\n", cardname);

        /* Open ALSA audio driver, card # outcard, device #0 in PLAYBACK mode */
        if((err = snd_pcm_open(&playback_handle, outcard, 0, SND_PCM_OPEN_PLAYBACK))){
                sprintf(errorstring, "Opening PLAYBACK channel: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        //snd_pcm_channel_flush(playback_handle, SND_PCM_CHANNEL_PLAYBACK); /* be in 
right state */

        memset(&params, 0, sizeof(snd_pcm_channel_params_t));
        
        params.channel = SND_PCM_CHANNEL_PLAYBACK;
        params.mode = SND_PCM_MODE_STREAM;
        
        params.format.interleave = 1;
        params.format.format     = getformat();
        params.format.rate       = (int)esr;
        params.format.voices     = nchnls;

        /* digital */
        params.start_mode = SND_PCM_START_GO;
        params.stop_mode  = SND_PCM_STOP_ROLLOVER;
                
        params.buf.stream.queue_size = 1024*1024; /* see recopen */ 
        params.buf.stream.fill = SND_PCM_FILL_SILENCE_WHOLE;
        params.buf.stream.max_fill = 1024;
        
        if ((err = snd_pcm_plugin_params(playback_handle, &params))) {
                sprintf(errorstring, "PLAYBACK channel parameterizing error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        if ((err = snd_pcm_plugin_prepare(playback_handle, SND_PCM_CHANNEL_PLAYBACK))) 
{
                sprintf(errorstring, "PLAYBACK channel prepare error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        if ((err = snd_pcm_channel_go(playback_handle, SND_PCM_CHANNEL_PLAYBACK))) {
                sprintf(errorstring, "PLAYBACK channel go error: %s\n", 
snd_strerror(err));
                die(errorstring);
        }
        
        fprintf(stderr, "Running PLAYBACK mode at %d hz on card #%d\n", 
params.format.rate, outcard);

#ifdef HIPRI
        setscheduler();
#endif
}

int rtrecord(char *inbuf, int nbytes)
{
        int count;
        while (1) {
                if ((count = snd_pcm_plugin_read(capture_handle, (void *)inbuf, 
(size_t)nbytes)) < 0) {
                        if (count == -EAGAIN) {
                                usleep(10000);
                                continue;
                        }
                        sprintf(errorstring, "Capture error: %s", snd_strerror(count));
                        die(errorstring);
                }
                break;
        }
        return(count);
}

void rtplay(char *outbuf, int nbytes)
{
        int count, pos = 0;
        do {
                if ((count = snd_pcm_plugin_write(playback_handle, (void 
*)(&outbuf[pos]), (size_t)nbytes)) < 0) {
                        if (count == -EAGAIN) {
                                usleep(10000);
                                continue;
                        }
                        sprintf(errorstring, "Playback error: %s\n", 
snd_strerror(count));
                        die(errorstring);
                }
                nbytes -= count;
                pos += count;
                //fprintf(stderr, "bytes = %d, count written = %d\n", nbytes, count);
        } while (nbytes);
        nrecs++;
}

void rtclose(void)              /* close the I/O device entirely  */
{                               /* called only when both complete */
        int err;
        if(capture_handle) {
                snd_pcm_channel_flush(capture_handle, SND_PCM_CHANNEL_CAPTURE);
                if ((err = snd_pcm_close(capture_handle))) {
                        sprintf(errorstring, "CAPTURE channel close error: %s\n", 
snd_strerror(err));
                        die(errorstring);
                }
        }
        if(playback_handle) {
                if ((err = snd_pcm_plugin_playback_drain(playback_handle))) {
                        sprintf(errorstring, "PLAYBACK channel drain error: %s\n", 
snd_strerror(err));
                        die(errorstring);
                }
                snd_pcm_channel_flush(capture_handle, SND_PCM_CHANNEL_CAPTURE);
                if ((err = snd_pcm_close(playback_handle))) {
                        sprintf(errorstring, "PLAYBACK channel close error: %s\n", 
snd_strerror(err));
                        die(errorstring);
                }
        }
        if (O.Linein) {
#ifdef PIPES
          if (O.Linename[0]=='|') _pclose(Linepipe);
#endif
        }
}

PGP signature

Reply via email to