/* 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 */ #include #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]; int playback_go = 1; int capture_go = 1; 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(¶ms, 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_GO; 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, ¶ms))) { 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(¶ms, 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_GO; 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, ¶ms))) { 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, err; 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 (capture_go) { 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); } capture_go = 0; } 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 nbytes) { buf = (char *)alloca(fragsize); memset(buf, 0, fragsize); for (i=0; i