From 40d1ad3315f9414e2995dbc9378c45df59d16fbd Mon Sep 17 00:00:00 2001 From: sletz Date: Wed, 8 Nov 2006 13:39:47 +0000 Subject: [PATCH] Synchronize ALSA backend with jack one git-svn-id: http://subversion.jackaudio.org/jack/jack2/trunk/jackmp@1276 0c269be4-1314-0410-8aa9-9f06e86f4224 --- ChangeLog | 4 + linux/alsa/JackAlsaDriver.cpp | 2705 +++++++++++++------------- linux/alsa/hammerfall.c | 14 +- linux/alsa/hdsp.c | 8 +- linux/alsa/ice1712.c | 10 +- linux/alsa/ice1712.h | 85 +- linux/alsa/memops.c | 555 +++++- linux/alsa/memops.h | 124 +- linux/alsa/usx2y.c | 216 +- linux/alsa/usx2y.h | 89 +- macosx/Jackdmp.xcode/project.pbxproj | 31 +- 11 files changed, 2201 insertions(+), 1640 deletions(-) diff --git a/ChangeLog b/ChangeLog index fc371b90..1e1ac66a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ Jackdmp changes log --------------------------- +2006-11-08 Stephane Letz + + * Synchronize ALSA backend with jack one. + 2006-11-04 Stephane Letz * Use -D to setup ADDON_DIR on OSX and Linux. diff --git a/linux/alsa/JackAlsaDriver.cpp b/linux/alsa/JackAlsaDriver.cpp index 0423e949..dc92c8a8 100644 --- a/linux/alsa/JackAlsaDriver.cpp +++ b/linux/alsa/JackAlsaDriver.cpp @@ -47,9 +47,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. #include "generic.h" #include "memops.h" -//#include "generic_hw.c" -//#include "hdsp.c" -//#include "hammerfall.c" namespace Jack { @@ -252,28 +249,34 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) } switch (driver->dither) { - case Rectangular: - printf("Rectangular dithering at 16 bits\n"); - driver->write_via_copy = sample_move_dither_rect_d16_sS; - break; - - case Triangular: - printf("Triangular dithering at 16 bits\n"); - driver->write_via_copy = sample_move_dither_tri_d16_sS; - break; - - case Shaped: - printf("Noise-shaped dithering at 16 bits\n"); - driver->write_via_copy = - sample_move_dither_shaped_d16_sS; - break; - - default: - driver->write_via_copy = sample_move_d16_sS; - break; - } - break; - + case Rectangular: + printf("Rectangular dithering at 16 bits\n"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_rect_d16_sSs: + sample_move_dither_rect_d16_sS; + break; + + case Triangular: + printf("Triangular dithering at 16 bits\n"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_tri_d16_sSs: + sample_move_dither_tri_d16_sS; + break; + + case Shaped: + printf("Noise-shaped dithering at 16 bits\n"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_shaped_d16_sSs: + sample_move_dither_shaped_d16_sS; + break; + + default: + driver->write_via_copy = driver->quirk_bswap? + sample_move_d16_sSs : sample_move_d16_sS; + break; + } + break; + case 3: if (driver->playback_interleaved) { driver->channel_copy = memcpy_interleave_d24_s24; @@ -282,28 +285,34 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) } switch (driver->dither) { - case Rectangular: - printf("Rectangular dithering at 16 bits\n"); - driver->write_via_copy = sample_move_dither_rect_d24_sS; - break; - - case Triangular: - printf("Triangular dithering at 16 bits\n"); - driver->write_via_copy = sample_move_dither_tri_d24_sS; - break; - - case Shaped: - printf("Noise-shaped dithering at 16 bits\n"); - driver->write_via_copy = - sample_move_dither_shaped_d24_sS; - break; - - default: - driver->write_via_copy = sample_move_d24_sS; - break; - } - break; - + case Rectangular: + printf("Rectangular dithering at 16 bits\n"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_rect_d24_sSs: + sample_move_dither_rect_d24_sS; + break; + + case Triangular: + printf("Triangular dithering at 16 bits\n"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_tri_d24_sSs: + sample_move_dither_tri_d24_sS; + break; + + case Shaped: + printf("Noise-shaped dithering at 16 bits\n"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_shaped_d24_sSs: + sample_move_dither_shaped_d24_sS; + break; + + default: + driver->write_via_copy = driver->quirk_bswap? + sample_move_d24_sSs : sample_move_d24_sS; + break; + } + break; + case 4: if (driver->playback_interleaved) { driver->channel_copy = memcpy_interleave_d32_s32; @@ -312,41 +321,49 @@ JackAlsaDriver::alsa_driver_setup_io_function_pointers (alsa_driver_t *driver) } switch (driver->dither) { - case Rectangular: - printf("Rectangular dithering at 16 bits\n"); - driver->write_via_copy = - sample_move_dither_rect_d32u24_sS; - break; - - case Triangular: - printf("Triangular dithering at 16 bits\n"); - driver->write_via_copy = - sample_move_dither_tri_d32u24_sS; - break; - - case Shaped: - printf("Noise-shaped dithering at 16 bits\n"); - driver->write_via_copy = - sample_move_dither_shaped_d32u24_sS; - break; - - default: - driver->write_via_copy = sample_move_d32u24_sS; - break; - } - break; - } + case Rectangular: + printf("Rectangular dithering at 16 bits\n"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_rect_d32u24_sSs: + sample_move_dither_rect_d32u24_sS; + break; + + case Triangular: + printf("Triangular dithering at 16 bits\n"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_tri_d32u24_sSs: + sample_move_dither_tri_d32u24_sS; + break; + + case Shaped: + printf("Noise-shaped dithering at 16 bits\n"); + driver->write_via_copy = driver->quirk_bswap? + sample_move_dither_shaped_d32u24_sSs: + sample_move_dither_shaped_d32u24_sS; + break; + + default: + driver->write_via_copy = driver->quirk_bswap? + sample_move_d32u24_sSs : sample_move_d32u24_sS; + break; + } + break; + } switch (driver->capture_sample_bytes) { - case 2: - driver->read_via_copy = sample_move_dS_s16; - break; - case 3: - driver->read_via_copy = sample_move_dS_s24; - break; - case 4: - driver->read_via_copy = sample_move_dS_s32u24; - break; + case 2: + driver->read_via_copy = driver->quirk_bswap? + sample_move_dS_s16s : sample_move_dS_s16; + break; + case 3: + driver->read_via_copy = driver->quirk_bswap? + sample_move_dS_s24s : sample_move_dS_s24; + break; + case 4: + driver->read_via_copy = driver->quirk_bswap? + sample_move_dS_s32u24s : sample_move_dS_s32u24; + break; + } } } @@ -361,241 +378,237 @@ JackAlsaDriver::alsa_driver_configure_stream (alsa_driver_t *driver, char *devic unsigned long sample_width) { int err, format; - unsigned int frame_rate; - snd_pcm_uframes_t stop_th; - static struct { - char Name[16]; - snd_pcm_format_t format; - } - formats[] = { - {"32bit", SND_PCM_FORMAT_S32}, - {"24bit", SND_PCM_FORMAT_S24_3}, - {"16bit", SND_PCM_FORMAT_S16}, - }; -#define NOFORMATS (sizeof(formats)/sizeof(formats[0])) - - if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { - jack_error ("ALSA: no playback configurations available (%s)", - snd_strerror (err)); - return -1; - } - - if ((err = snd_pcm_hw_params_set_periods_integer (handle, hw_params)) - < 0) { - jack_error ("ALSA: cannot restrict period size to integral" - " value."); - return -1; - } - - if ((err = snd_pcm_hw_params_set_access ( - handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) - < 0) { - if ((err = snd_pcm_hw_params_set_access ( - handle, hw_params, - SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { - if ((err = snd_pcm_hw_params_set_access ( - handle, hw_params, - SND_PCM_ACCESS_MMAP_COMPLEX)) < 0) { - - jack_error ("ALSA: mmap-based access is not possible" - " for the %s " - "stream of this audio interface", - stream_name); - return -1; - } - } - } - - format = sample_width == 4 ? 0 : NOFORMATS - 1; - while (1) { - if ((err = snd_pcm_hw_params_set_format ( - handle, hw_params, formats[format].format)) < 0) { - int failed_format = format; - if ((sample_width == 4 - ? format++ < NOFORMATS - 1 - : format-- > 0)) { - jack_error ("Note: audio device %s doesn't support a %s sample format" - " so JACK will try a %s format instead", device_name, - formats[failed_format].Name, - formats[format].Name); - } else { - jack_error ("Sorry. The audio interface \"%s\"" - " doesn't support any of the" - " hardware sample formats that" - " JACK's alsa-driver can use.", - device_name); - return -1; - } - } else - break; - } - - frame_rate = driver->frame_rate ; - err = snd_pcm_hw_params_set_rate_near (handle, hw_params, - &frame_rate, NULL) ; - driver->frame_rate = frame_rate ; - if (err < 0) { - //jack_error ("ALSA: cannot set sample/frame rate to %" - // PRIu32 " for %s", driver->frame_rate, - // stream_name); - return -1; - } - if (!*nchns) { - /*if not user-specified, try to find the maximum - * number of channels */ - unsigned int channels_max ; - err = snd_pcm_hw_params_get_channels_max (hw_params, - &channels_max); - *nchns = channels_max ; - - if (*nchns > 1024) { - - /* the hapless user is an unwitting victim of - the "default" ALSA PCM device, which can - support up to 16 million channels. since - they can't be bothered to set up a proper - default device, limit the number of - channels for them to a sane default. - */ - - jack_error ( - "You appear to be using the ALSA software \"plug\" layer, probably\n" - "a result of using the \"default\" ALSA device. This is less\n" - "efficient than it could be. Consider using a hardware device\n" - "instead rather than using the plug layer. Usually the name of the\n" - "hardware device that corresponds to the first sound card is hw:0\n" - ); - *nchns = 2; - } - } - - if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, - *nchns)) < 0) { - jack_error ("ALSA: cannot set channel count to %u for %s", - *nchns, stream_name); - return -1; - } + unsigned int frame_rate; + snd_pcm_uframes_t stop_th; + static struct { + char Name[32]; + snd_pcm_format_t format; + int swapped; + } formats[] = { + {"32bit little-endian", SND_PCM_FORMAT_S32_LE, IS_LE}, + {"32bit big-endian", SND_PCM_FORMAT_S32_BE, IS_BE}, + {"24bit little-endian", SND_PCM_FORMAT_S24_3LE, IS_LE}, + {"24bit big-endian", SND_PCM_FORMAT_S24_3BE, IS_BE}, + {"16bit little-endian", SND_PCM_FORMAT_S16_LE, IS_LE}, + {"16bit big-endian", SND_PCM_FORMAT_S16_BE, IS_BE}, + }; +#define NUMFORMATS (sizeof(formats)/sizeof(formats[0])) +#define FIRST_16BIT_FORMAT 4 + + if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) { + jack_error ("ALSA: no playback configurations available (%s)", + snd_strerror (err)); + return -1; + } - if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params, - driver->frames_per_cycle, - 0)) - < 0) { - // steph - //jack_error ("ALSA: cannot set period size to %" PRIu32 - // " frames for %s", driver->frames_per_cycle, - // stream_name); - return -1; - } + if ((err = snd_pcm_hw_params_set_periods_integer (handle, hw_params)) + < 0) { + jack_error ("ALSA: cannot restrict period size to integral" + " value."); + return -1; + } - *nperiodsp = driver->user_nperiods; - snd_pcm_hw_params_set_periods_min (handle, hw_params, nperiodsp, NULL); - if (*nperiodsp < driver->user_nperiods) - *nperiodsp = driver->user_nperiods; - if (snd_pcm_hw_params_set_periods_near (handle, hw_params, - nperiodsp, NULL) < 0) { - jack_error ("ALSA: cannot set number of periods to %u for %s", - *nperiodsp, stream_name); - return -1; - } + if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_MMAP_NONINTERLEAVED)) < 0) { + if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_MMAP_INTERLEAVED)) < 0) { + if ((err = snd_pcm_hw_params_set_access ( + handle, hw_params, + SND_PCM_ACCESS_MMAP_COMPLEX)) < 0) { + jack_error ("ALSA: mmap-based access is not possible" + " for the %s " + "stream of this audio interface", + stream_name); + return -1; + } + } + } + + format = (sample_width == 4) ? 0 : FIRST_16BIT_FORMAT; + + while (1) { + if ((err = snd_pcm_hw_params_set_format ( + handle, hw_params, formats[format].format)) < 0) { + + if ((sample_width == 4 + ? format++ >= FIRST_16BIT_FORMAT + : format-- <= 0)) { + jack_error ("Sorry. The audio interface \"%s\"" + " doesn't support any of the" + " hardware sample formats that" + " JACK's alsa-driver can use.", + device_name); + return -1; + } + } else { + if (formats[format].swapped) { + driver->quirk_bswap = 1; + } else { + driver->quirk_bswap = 0; + } + jack_error ("ALSA: final selected sample format for %s: %s", stream_name, formats[format].Name); + break; + } + } + + frame_rate = driver->frame_rate ; + err = snd_pcm_hw_params_set_rate_near (handle, hw_params, + &frame_rate, NULL) ; + driver->frame_rate = frame_rate ; + if (err < 0) { + jack_error ("ALSA: cannot set sample/frame rate to %" + PRIu32 " for %s", driver->frame_rate, + stream_name); + return -1; + } + if (!*nchns) { + /*if not user-specified, try to find the maximum + * number of channels */ + unsigned int channels_max ; + err = snd_pcm_hw_params_get_channels_max (hw_params, + &channels_max); + *nchns = channels_max ; + + if (*nchns > 1024) { + + /* the hapless user is an unwitting victim of + the "default" ALSA PCM device, which can + support up to 16 million channels. since + they can't be bothered to set up a proper + default device, limit the number of + channels for them to a sane default. + */ + + jack_error ( +"You appear to be using the ALSA software \"plug\" layer, probably\n" +"a result of using the \"default\" ALSA device. This is less\n" +"efficient than it could be. Consider using a hardware device\n" +"instead rather than using the plug layer. Usually the name of the\n" +"hardware device that corresponds to the first sound card is hw:0\n" + ); + *nchns = 2; + } + } - if (*nperiodsp < driver->user_nperiods) { - jack_error ("ALSA: got smaller periods %u than %u for %s", - *nperiodsp, (unsigned int) driver->user_nperiods, - stream_name); - return -1; - } - fprintf(stderr, "nperiods = %d for %s\n", *nperiodsp, stream_name); + if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, + *nchns)) < 0) { + jack_error ("ALSA: cannot set channel count to %u for %s", + *nchns, stream_name); + return -1; + } + + if ((err = snd_pcm_hw_params_set_period_size (handle, hw_params, + driver->frames_per_cycle, + 0)) + < 0) { + jack_error ("ALSA: cannot set period size to %" PRIu32 + " frames for %s", driver->frames_per_cycle, + stream_name); + return -1; + } - // steph - /* - if (!jack_power_of_two(driver->frames_per_cycle)) { - jack_error("JACK: frames must be a power of two " - "(64, 512, 1024, ...)\n"); - return -1; - } - */ + *nperiodsp = driver->user_nperiods; + snd_pcm_hw_params_set_periods_min (handle, hw_params, nperiodsp, NULL); + if (*nperiodsp < driver->user_nperiods) + *nperiodsp = driver->user_nperiods; + if (snd_pcm_hw_params_set_periods_near (handle, hw_params, + nperiodsp, NULL) < 0) { + jack_error ("ALSA: cannot set number of periods to %u for %s", + *nperiodsp, stream_name); + return -1; + } - if ((err = snd_pcm_hw_params_set_buffer_size (handle, hw_params, - *nperiodsp * - driver->frames_per_cycle)) - < 0) { - /* - jack_error ("ALSA: cannot set buffer length to %" PRIu32 - " for %s", - *nperiodsp * driver->frames_per_cycle, - stream_name); - */ - return -1; - } + if (*nperiodsp < driver->user_nperiods) { + jack_error ("ALSA: got smaller periods %u than %u for %s", + *nperiodsp, (unsigned int) driver->user_nperiods, + stream_name); + return -1; + } + jack_error ("ALSA: use %d periods for %s", *nperiodsp, stream_name); + + if (!jack_power_of_two(driver->frames_per_cycle)) { + jack_error("JACK: frames must be a power of two " + "(64, 512, 1024, ...)\n"); + return -1; + } - if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) { - jack_error ("ALSA: cannot set hardware parameters for %s", - stream_name); - return -1; - } + if ((err = snd_pcm_hw_params_set_buffer_size (handle, hw_params, + *nperiodsp * + driver->frames_per_cycle)) + < 0) { + jack_error ("ALSA: cannot set buffer length to %" PRIu32 + " for %s", + *nperiodsp * driver->frames_per_cycle, + stream_name); + return -1; + } - snd_pcm_sw_params_current (handle, sw_params); + if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) { + jack_error ("ALSA: cannot set hardware parameters for %s", + stream_name); + return -1; + } - if ((err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, - 0U)) < 0) { - jack_error ("ALSA: cannot set start mode for %s", stream_name); - return -1; - } + snd_pcm_sw_params_current (handle, sw_params); - stop_th = *nperiodsp * driver->frames_per_cycle; - if (driver->soft_mode) { - stop_th = (snd_pcm_uframes_t) - 1; - } + if ((err = snd_pcm_sw_params_set_start_threshold (handle, sw_params, + 0U)) < 0) { + jack_error ("ALSA: cannot set start mode for %s", stream_name); + return -1; + } - if ((err = snd_pcm_sw_params_set_stop_threshold ( - handle, sw_params, stop_th)) < 0) { - jack_error ("ALSA: cannot set stop mode for %s", - stream_name); - return -1; - } + stop_th = *nperiodsp * driver->frames_per_cycle; + if (driver->soft_mode) { + stop_th = (snd_pcm_uframes_t)-1; + } + + if ((err = snd_pcm_sw_params_set_stop_threshold ( + handle, sw_params, stop_th)) < 0) { + jack_error ("ALSA: cannot set stop mode for %s", + stream_name); + return -1; + } - if ((err = snd_pcm_sw_params_set_silence_threshold ( - handle, sw_params, 0)) < 0) { - jack_error ("ALSA: cannot set silence threshold for %s", - stream_name); - return -1; - } + if ((err = snd_pcm_sw_params_set_silence_threshold ( + handle, sw_params, 0)) < 0) { + jack_error ("ALSA: cannot set silence threshold for %s", + stream_name); + return -1; + } #if 0 - fprintf (stderr, "set silence size to %lu * %lu = %lu\n", - driver->frames_per_cycle, *nperiodsp, - driver->frames_per_cycle * *nperiodsp); - - if ((err = snd_pcm_sw_params_set_silence_size ( - handle, sw_params, - driver->frames_per_cycle * *nperiodsp)) < 0) { - jack_error ("ALSA: cannot set silence size for %s", - stream_name); - return -1; - } + fprintf (stderr, "set silence size to %lu * %lu = %lu\n", + driver->frames_per_cycle, *nperiodsp, + driver->frames_per_cycle * *nperiodsp); + + if ((err = snd_pcm_sw_params_set_silence_size ( + handle, sw_params, + driver->frames_per_cycle * *nperiodsp)) < 0) { + jack_error ("ALSA: cannot set silence size for %s", + stream_name); + return -1; + } #endif - if (handle == driver->playback_handle) - err = snd_pcm_sw_params_set_avail_min ( - handle, sw_params, - driver->frames_per_cycle - * (*nperiodsp - driver->user_nperiods + 1)); - else - err = snd_pcm_sw_params_set_avail_min ( - handle, sw_params, driver->frames_per_cycle); - - if (err < 0) { - jack_error ("ALSA: cannot set avail min for %s", stream_name); - return -1; - } + if (handle == driver->playback_handle) + err = snd_pcm_sw_params_set_avail_min ( + handle, sw_params, + driver->frames_per_cycle + * (*nperiodsp - driver->user_nperiods + 1)); + else + err = snd_pcm_sw_params_set_avail_min ( + handle, sw_params, driver->frames_per_cycle); + + if (err < 0) { + jack_error ("ALSA: cannot set avail min for %s", stream_name); + return -1; + } - if ((err = snd_pcm_sw_params (handle, sw_params)) < 0) { - jack_error ("ALSA: cannot set software parameters for %s\n", - stream_name); - return -1; - } + if ((err = snd_pcm_sw_params (handle, sw_params)) < 0) { + jack_error ("ALSA: cannot set software parameters for %s\n", + stream_name); + return -1; + } - return 0; + return 0; } int @@ -760,10 +773,11 @@ JackAlsaDriver::alsa_driver_set_parameters (alsa_driver_t *driver, if (driver->playback_handle) { switch (driver->playback_sample_format) { case SND_PCM_FORMAT_S32_LE: - case SND_PCM_FORMAT_S24_3: - case SND_PCM_FORMAT_S16_LE: - case SND_PCM_FORMAT_S32_BE: - case SND_PCM_FORMAT_S16_BE: + case SND_PCM_FORMAT_S24_3LE: + case SND_PCM_FORMAT_S24_3BE: + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S32_BE: + case SND_PCM_FORMAT_S16_BE: break; default: @@ -776,10 +790,11 @@ JackAlsaDriver::alsa_driver_set_parameters (alsa_driver_t *driver, if (driver->capture_handle) { switch (driver->capture_sample_format) { case SND_PCM_FORMAT_S32_LE: - case SND_PCM_FORMAT_S24_3: - case SND_PCM_FORMAT_S16_LE: - case SND_PCM_FORMAT_S32_BE: - case SND_PCM_FORMAT_S16_BE: + case SND_PCM_FORMAT_S24_3LE: + case SND_PCM_FORMAT_S24_3BE: + case SND_PCM_FORMAT_S16_LE: + case SND_PCM_FORMAT_S32_BE: + case SND_PCM_FORMAT_S16_BE: break; default: @@ -798,15 +813,11 @@ JackAlsaDriver::alsa_driver_set_parameters (alsa_driver_t *driver, driver->alsa_name_playback); return -1; } - //driver->playback_interleave_skip = my_areas[0].step / 8; steph driver->interleave_unit = snd_pcm_format_physical_width ( driver->playback_sample_format) / 8; } else { driver->interleave_unit = 0; /* NOT USED */ - //driver->playback_interleave_skip = steph - // snd_pcm_format_physical_width ( - // driver->playback_sample_format) / 8; } if (driver->capture_interleaved) { @@ -818,13 +829,8 @@ JackAlsaDriver::alsa_driver_set_parameters (alsa_driver_t *driver, driver->alsa_name_capture); return -1; } - //driver->capture_interleave_skip = my_areas[0].step / 8; steph - } else { - //driver->capture_interleave_skip = - // snd_pcm_format_physical_width ( - // driver->capture_sample_format) / 8; - } - + } + if (driver->playback_nchannels > driver->capture_nchannels) { driver->max_nchannels = driver->playback_nchannels; driver->user_nchannels = driver->capture_nchannels; @@ -922,170 +928,170 @@ JackAlsaDriver::alsa_driver_get_channel_addresses (alsa_driver_t *driver, snd_pcm_uframes_t *capture_offset, snd_pcm_uframes_t *playback_offset) { - unsigned long err; - channel_t chn; - - if (capture_avail) { - if ((err = snd_pcm_mmap_begin ( - driver->capture_handle, &driver->capture_areas, - (snd_pcm_uframes_t *) capture_offset, - (snd_pcm_uframes_t *) capture_avail)) < 0) { - jack_error ("ALSA: %s: mmap areas info error", - driver->alsa_name_capture); - return -1; - } - - for (chn = 0; chn < driver->capture_nchannels; chn++) { - const snd_pcm_channel_area_t *a = - &driver->capture_areas[chn]; - driver->capture_addr[chn] = (char *) a->addr - + ((a->first + a->step * *capture_offset) / 8); - driver->capture_interleave_skip[chn] = (unsigned long ) (a->step / 8); // steph - } - } - - if (playback_avail) { - if ((err = snd_pcm_mmap_begin ( - driver->playback_handle, &driver->playback_areas, - (snd_pcm_uframes_t *) playback_offset, - (snd_pcm_uframes_t *) playback_avail)) < 0) { - jack_error ("ALSA: %s: mmap areas info error ", - driver->alsa_name_playback); - return -1; - } - - for (chn = 0; chn < driver->playback_nchannels; chn++) { - const snd_pcm_channel_area_t *a = - &driver->playback_areas[chn]; - driver->playback_addr[chn] = (char *) a->addr - + ((a->first + a->step * *playback_offset) / 8); - driver->playback_interleave_skip[chn] = (unsigned long ) (a->step / 8); // steph - } - } - - return 0; + unsigned long err; + channel_t chn; + + if (capture_avail) { + if ((err = snd_pcm_mmap_begin ( + driver->capture_handle, &driver->capture_areas, + (snd_pcm_uframes_t *) capture_offset, + (snd_pcm_uframes_t *) capture_avail)) < 0) { + jack_error ("ALSA: %s: mmap areas info error", + driver->alsa_name_capture); + return -1; + } + + for (chn = 0; chn < driver->capture_nchannels; chn++) { + const snd_pcm_channel_area_t *a = + &driver->capture_areas[chn]; + driver->capture_addr[chn] = (char *) a->addr + + ((a->first + a->step * *capture_offset) / 8); + driver->capture_interleave_skip[chn] = (unsigned long ) (a->step / 8); + } + } + + if (playback_avail) { + if ((err = snd_pcm_mmap_begin ( + driver->playback_handle, &driver->playback_areas, + (snd_pcm_uframes_t *) playback_offset, + (snd_pcm_uframes_t *) playback_avail)) < 0) { + jack_error ("ALSA: %s: mmap areas info error ", + driver->alsa_name_playback); + return -1; + } + + for (chn = 0; chn < driver->playback_nchannels; chn++) { + const snd_pcm_channel_area_t *a = + &driver->playback_areas[chn]; + driver->playback_addr[chn] = (char *) a->addr + + ((a->first + a->step * *playback_offset) / 8); + driver->playback_interleave_skip[chn] = (unsigned long ) (a->step / 8); + } + } + + return 0; } int JackAlsaDriver::alsa_driver_start (alsa_driver_t *driver) { int err; - snd_pcm_uframes_t poffset, pavail; - channel_t chn; - - driver->poll_last = 0; - driver->poll_next = 0; - - if (driver->playback_handle) { - if ((err = snd_pcm_prepare (driver->playback_handle)) < 0) { - jack_error ("ALSA: prepare error for playback on " - "\"%s\" (%s)", driver->alsa_name_playback, - snd_strerror(err)); - return -1; - } - } - - if ((driver->capture_handle && driver->capture_and_playback_not_synced) - || !driver->playback_handle) { - if ((err = snd_pcm_prepare (driver->capture_handle)) < 0) { - jack_error ("ALSA: prepare error for capture on \"%s\"" - " (%s)", driver->alsa_name_capture, - snd_strerror(err)); - return -1; - } - } - - if (driver->hw_monitoring) { - if (driver->input_monitor_mask || driver->all_monitor_in) { - if (driver->all_monitor_in) { - driver->hw->set_input_monitor_mask (driver->hw, ~0U); - } else { - driver->hw->set_input_monitor_mask ( - driver->hw, driver->input_monitor_mask); - } - } else { - driver->hw->set_input_monitor_mask (driver->hw, - driver->input_monitor_mask); - } - } - - if (driver->playback_handle) { - driver->playback_nfds = - snd_pcm_poll_descriptors_count (driver->playback_handle); - } else { - driver->playback_nfds = 0; - } - - if (driver->capture_handle) { - driver->capture_nfds = - snd_pcm_poll_descriptors_count (driver->capture_handle); - } else { - driver->capture_nfds = 0; - } - - if (driver->pfd) { - free (driver->pfd); - } - - driver->pfd = (struct pollfd *) - malloc (sizeof (struct pollfd) * - (driver->playback_nfds + driver->capture_nfds + 2)); + snd_pcm_uframes_t poffset, pavail; + channel_t chn; + + driver->poll_last = 0; + driver->poll_next = 0; + + if (driver->playback_handle) { + if ((err = snd_pcm_prepare (driver->playback_handle)) < 0) { + jack_error ("ALSA: prepare error for playback on " + "\"%s\" (%s)", driver->alsa_name_playback, + snd_strerror(err)); + return -1; + } + } - if (driver->playback_handle) { - /* fill playback buffer with zeroes, and mark - all fragments as having data. - */ + if ((driver->capture_handle && driver->capture_and_playback_not_synced) + || !driver->playback_handle) { + if ((err = snd_pcm_prepare (driver->capture_handle)) < 0) { + jack_error ("ALSA: prepare error for capture on \"%s\"" + " (%s)", driver->alsa_name_capture, + snd_strerror(err)); + return -1; + } + } - pavail = snd_pcm_avail_update (driver->playback_handle); + if (driver->hw_monitoring) { + if (driver->input_monitor_mask || driver->all_monitor_in) { + if (driver->all_monitor_in) { + driver->hw->set_input_monitor_mask (driver->hw, ~0U); + } else { + driver->hw->set_input_monitor_mask ( + driver->hw, driver->input_monitor_mask); + } + } else { + driver->hw->set_input_monitor_mask (driver->hw, + driver->input_monitor_mask); + } + } - if (pavail != - driver->frames_per_cycle * driver->playback_nperiods) { - jack_error ("ALSA: full buffer not available at start"); - return -1; - } + if (driver->playback_handle) { + driver->playback_nfds = + snd_pcm_poll_descriptors_count (driver->playback_handle); + } else { + driver->playback_nfds = 0; + } - if (alsa_driver_get_channel_addresses (driver, - 0, &pavail, 0, &poffset)) { - return -1; - } + if (driver->capture_handle) { + driver->capture_nfds = + snd_pcm_poll_descriptors_count (driver->capture_handle); + } else { + driver->capture_nfds = 0; + } - /* XXX this is cheating. ALSA offers no guarantee that - we can access the entire buffer at any one time. It - works on most hardware tested so far, however, buts - its a liability in the long run. I think that - alsa-lib may have a better function for doing this - here, where the goal is to silence the entire - buffer. - */ + if (driver->pfd) { + free (driver->pfd); + } - for (chn = 0; chn < driver->playback_nchannels; chn++) { - alsa_driver_silence_on_channel ( - driver, chn, - driver->user_nperiods - * driver->frames_per_cycle); - } + driver->pfd = (struct pollfd *) + malloc (sizeof (struct pollfd) * + (driver->playback_nfds + driver->capture_nfds + 2)); - snd_pcm_mmap_commit (driver->playback_handle, poffset, - driver->user_nperiods - * driver->frames_per_cycle); + if (driver->playback_handle) { + /* fill playback buffer with zeroes, and mark + all fragments as having data. + */ + + pavail = snd_pcm_avail_update (driver->playback_handle); - if ((err = snd_pcm_start (driver->playback_handle)) < 0) { - jack_error ("ALSA: could not start playback (%s)", - snd_strerror (err)); - return -1; - } - } + if (pavail != + driver->frames_per_cycle * driver->playback_nperiods) { + jack_error ("ALSA: full buffer not available at start"); + return -1; + } + + if (alsa_driver_get_channel_addresses (driver, + 0, &pavail, 0, &poffset)) { + return -1; + } - if ((driver->capture_handle && driver->capture_and_playback_not_synced) - || !driver->playback_handle) { - if ((err = snd_pcm_start (driver->capture_handle)) < 0) { - jack_error ("ALSA: could not start capture (%s)", - snd_strerror (err)); - return -1; - } - } + /* XXX this is cheating. ALSA offers no guarantee that + we can access the entire buffer at any one time. It + works on most hardware tested so far, however, buts + its a liability in the long run. I think that + alsa-lib may have a better function for doing this + here, where the goal is to silence the entire + buffer. + */ + + for (chn = 0; chn < driver->playback_nchannels; chn++) { + alsa_driver_silence_on_channel ( + driver, chn, + driver->user_nperiods + * driver->frames_per_cycle); + } + + snd_pcm_mmap_commit (driver->playback_handle, poffset, + driver->user_nperiods + * driver->frames_per_cycle); + + if ((err = snd_pcm_start (driver->playback_handle)) < 0) { + jack_error ("ALSA: could not start playback (%s)", + snd_strerror (err)); + return -1; + } + } - return 0; + if ((driver->capture_handle && driver->capture_and_playback_not_synced) + || !driver->playback_handle) { + if ((err = snd_pcm_start (driver->capture_handle)) < 0) { + jack_error ("ALSA: could not start capture (%s)", + snd_strerror (err)); + return -1; + } + } + + return 0; } int @@ -1148,1120 +1154,1121 @@ JackAlsaDriver::alsa_driver_stop (alsa_driver_t *driver) } int -JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) +JackAlsaDriver::alsa_driver_restart (alsa_driver_t *driver) { - snd_pcm_sframes_t contiguous; - snd_pcm_sframes_t nread; - snd_pcm_sframes_t offset; - jack_nframes_t orig_nframes; - jack_default_audio_sample_t* buf; - //channel_t chn; - //JSList *node; - //jack_port_t* port; - int err; - // steph /* - if (!driver->capture_handle || driver->engine->freewheeling) { - return 0; - } + if (driver->nt_stop((struct _jack_driver_nt *) driver)) + return -1; + return driver->nt_start((struct _jack_driver_nt *) driver); */ - if (!driver->capture_handle) { - return 0; - } - if (nframes > driver->frames_per_cycle) { + + if (Stop()) return -1; - } + return Start(); +} - nread = 0; - contiguous = 0; - orig_nframes = nframes; +int +JackAlsaDriver::alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed_usecs) +{ + snd_pcm_status_t *status; + int res; - while (nframes) { + jack_error("alsa_driver_xrun_recovery "); - contiguous = nframes; + snd_pcm_status_alloca(&status); - if (alsa_driver_get_channel_addresses ( - driver, - (snd_pcm_uframes_t *) &contiguous, - (snd_pcm_uframes_t *) 0, - (snd_pcm_uframes_t *)&offset, 0) < 0) { - return -1; - } - - // steph - for (int i = 0; i < fCaptureChannels; i++) { - if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) { - buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[i], orig_nframes); - alsa_driver_read_from_channel (driver, i, buf + nread, contiguous); - } + if (driver->capture_handle) { + if ((res = snd_pcm_status(driver->capture_handle, status)) + < 0) { + jack_error("status error: %s", snd_strerror(res)); } - - /* // steph - for (chn = 0, node = driver->capture_ports; node; - node = jack_slist_next (node), chn++) { - - port = (jack_port_t *) node->data; - - if (!jack_port_connected (port)) { - // no-copy optimization - continue; - } - buf = jack_port_get_buffer (port, orig_nframes); - alsa_driver_read_from_channel (driver, chn, - buf + nread, contiguous); + } else { + if ((res = snd_pcm_status(driver->playback_handle, status)) + < 0) { + jack_error("status error: %s", snd_strerror(res)); } - */ + } - if ((err = snd_pcm_mmap_commit (driver->capture_handle, - offset, contiguous)) < 0) { - // steph - // jack_error ("ALSA: could not complete read of %" - // PRIu32 " frames: error = %d\n", contiguous, err); - jack_error ("ALSA: could not complete read of %d frames: error = %d", contiguous, err); - return -1; - } + if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN + // && driver->process_count > XRUN_REPORT_DELAY) { // steph + && driver->process_count > 10) { + struct timeval now, diff, tstamp; + driver->xrun_count++; + gettimeofday(&now, 0); + snd_pcm_status_get_trigger_tstamp(status, &tstamp); + timersub(&now, &tstamp, &diff); + *delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec; - nframes -= contiguous; - nread += contiguous; + // steph: utiliser une version TR + jack_error("\n\n**** alsa_pcm: xrun of at least %.3f msecs\n\n", *delayed_usecs / 1000.0); } + if (alsa_driver_restart (driver)) { + return -1; + } return 0; } -int -JackAlsaDriver::alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) +void +JackAlsaDriver::alsa_driver_silence_untouched_channels (alsa_driver_t *driver, + jack_nframes_t nframes) { - //channel_t chn; - //JSList *node; - //JSList *mon_node; - jack_default_audio_sample_t* buf; - jack_default_audio_sample_t* monbuf; - jack_nframes_t orig_nframes; - snd_pcm_sframes_t nwritten; - snd_pcm_sframes_t contiguous; - snd_pcm_sframes_t offset; - JackPort* port; - //jack_port_t *port; - int err; - - driver->process_count++; + channel_t chn; + jack_nframes_t buffer_frames = + driver->frames_per_cycle * driver->playback_nperiods; - // steph - /* - if (!driver->playback_handle || driver->engine->freewheeling) { - return 0; - } - */ - if (!driver->playback_handle) { - return 0; + for (chn = 0; chn < driver->playback_nchannels; chn++) { + if (bitset_contains (driver->channels_not_done, chn)) { + if (driver->silent[chn] < buffer_frames) { + alsa_driver_silence_on_channel_no_mark ( + driver, chn, nframes); + driver->silent[chn] += nframes; + } + } } +} - if (nframes > driver->frames_per_cycle) { - return -1; - } +jack_nframes_t +JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float + *delayed_usecs) +{ + snd_pcm_sframes_t avail = 0; + snd_pcm_sframes_t capture_avail = 0; + snd_pcm_sframes_t playback_avail = 0; + int xrun_detected = FALSE; + int need_capture; + int need_playback; + unsigned int i; + jack_time_t poll_enter; + jack_time_t poll_ret = 0; - nwritten = 0; - contiguous = 0; - orig_nframes = nframes; + *status = -1; + *delayed_usecs = 0; - /* check current input monitor request status */ + need_capture = driver->capture_handle ? 1 : 0; - driver->input_monitor_mask = 0; + if (extra_fd >= 0) { + need_playback = 0; + } else { + need_playback = driver->playback_handle ? 1 : 0; + } // steph - /* - for (chn = 0, node = driver->capture_ports; node; - node = jack_slist_next (node), chn++) { - if (((jack_port_t *) node->data)->shared->monitor_requests) { - driver->input_monitor_mask |= (1<GetPort(fCapturePortList[i]); - if (port->MonitoringInput()) { - driver->input_monitor_mask |= (1<hw_monitoring) { - if ((driver->hw->input_monitor_mask - != driver->input_monitor_mask) - && !driver->all_monitor_in) { - driver->hw->set_input_monitor_mask ( - driver->hw, driver->input_monitor_mask); - } - } + while (need_playback || need_capture) { - while (nframes) { + unsigned int p_timed_out, c_timed_out; + unsigned int ci = 0; + unsigned int nfds; - contiguous = nframes; + nfds = 0; - if (alsa_driver_get_channel_addresses ( - driver, - (snd_pcm_uframes_t *) 0, - (snd_pcm_uframes_t *) &contiguous, - 0, (snd_pcm_uframes_t *)&offset) < 0) { - return -1; + if (need_playback) { + snd_pcm_poll_descriptors (driver->playback_handle, + &driver->pfd[0], + driver->playback_nfds); + nfds += driver->playback_nfds; } - // steph - for (int i = 0; i < fPlaybackChannels; i++) { - // Ouput ports - if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { - buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[i], orig_nframes); - alsa_driver_write_to_channel (driver, i, buf + nwritten, contiguous); - // Monitor ports - if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0) { - monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[i], orig_nframes); - memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); - } - } - } - - /* - for (chn = 0, node = driver->playback_ports, mon_node=driver->monitor_ports; - node; - node = jack_slist_next (node), chn++) { - - port = (jack_port_t *) node->data; + if (need_capture) { + snd_pcm_poll_descriptors (driver->capture_handle, + &driver->pfd[nfds], + driver->capture_nfds); + ci = nfds; + nfds += driver->capture_nfds; + } - if (!jack_port_connected (port)) { - continue; - } - buf = jack_port_get_buffer (port, orig_nframes); - alsa_driver_write_to_channel (driver, chn, - buf + nwritten, contiguous); + /* ALSA doesn't set POLLERR in some versions of 0.9.X */ - if (mon_node) { - port = (jack_port_t *) mon_node->data; - if (!jack_port_connected (port)) { - continue; - } - monbuf = jack_port_get_buffer (port, orig_nframes); - memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); - mon_node = jack_slist_next (mon_node); - } + for (i = 0; i < nfds; i++) { + driver->pfd[i].events |= POLLERR; } - */ - if (!bitset_empty (driver->channels_not_done)) { - alsa_driver_silence_untouched_channels (driver, - contiguous); + if (extra_fd >= 0) { + driver->pfd[nfds].fd = extra_fd; + driver->pfd[nfds].events = + POLLIN | POLLERR | POLLHUP | POLLNVAL; + nfds++; } - if ((err = snd_pcm_mmap_commit (driver->playback_handle, - offset, contiguous)) < 0) { - // steph - // jack_error ("ALSA: could not complete playback of %" - // PRIu32 " frames: error = %d", contiguous, err); - jack_error ("ALSA: could not complete playback of %d frames: error = %d", contiguous, err); - if (err != EPIPE && err != ESTRPIPE) - return -1; - } + poll_enter = jack_get_microseconds (); - nframes -= contiguous; - nwritten += contiguous; - } - return 0; -} + if (poll_enter > driver->poll_next) { + /* + * This processing cycle was delayed past the + * next due interrupt! Do not account this as + * a wakeup delay: + */ + driver->poll_next = 0; + driver->poll_late++; + } -void -JackAlsaDriver::alsa_driver_delete (alsa_driver_t *driver) -{ - JSList *node; + if (poll (driver->pfd, nfds, driver->poll_timeout) < 0) { - for (node = driver->clock_sync_listeners; node; - node = jack_slist_next (node)) { - free (node->data); - } - jack_slist_free (driver->clock_sync_listeners); + if (errno == EINTR) { + printf ("poll interrupt\n"); + // this happens mostly when run + // under gdb, or when exiting due to a signal + // steph + /* + if (under_gdb) { + goto again; + } + */ + *status = -2; + return 0; + } - if (driver->capture_handle) { - snd_pcm_close (driver->capture_handle); - driver->capture_handle = 0; - } + jack_error ("ALSA: poll call failed (%s)", + strerror (errno)); + *status = -3; + return 0; - if (driver->playback_handle) { - snd_pcm_close (driver->playback_handle); - driver->capture_handle = 0; - } + } - if (driver->capture_hw_params) { - snd_pcm_hw_params_free (driver->capture_hw_params); - driver->capture_hw_params = 0; - } + poll_ret = jack_get_microseconds (); + // steph + fLastWaitUst = poll_ret; - if (driver->playback_hw_params) { - snd_pcm_hw_params_free (driver->playback_hw_params); - driver->playback_hw_params = 0; - } + if (extra_fd < 0) { + if (driver->poll_next && poll_ret > driver->poll_next) { + *delayed_usecs = poll_ret - driver->poll_next; + } + driver->poll_last = poll_ret; + driver->poll_next = poll_ret + driver->period_usecs; - if (driver->capture_sw_params) { - snd_pcm_sw_params_free (driver->capture_sw_params); - driver->capture_sw_params = 0; - } + // steph + /* + driver->engine->transport_cycle_start (driver->engine, + poll_ret); + */ - if (driver->playback_sw_params) { - snd_pcm_sw_params_free (driver->playback_sw_params); - driver->playback_sw_params = 0; - } + } - if (driver->pfd) { - free (driver->pfd); - } +#ifdef DEBUG_WAKEUP + fprintf (stderr, "%" PRIu64 ": checked %d fds, %" PRIu64 + " usecs since poll entered\n", poll_ret, nfds, + poll_ret - poll_enter); +#endif - if (driver->hw) { - driver->hw->release (driver->hw); - driver->hw = 0; - } - free(driver->alsa_name_playback); - free(driver->alsa_name_capture); - free(driver->alsa_driver); + /* check to see if it was the extra FD that caused us + * to return from poll */ - alsa_driver_release_channel_dependent_memory (driver); - jack_driver_nt_finish ((jack_driver_nt_t *) driver); - free (driver); -} + if (extra_fd >= 0) { -jack_driver_t * -JackAlsaDriver::alsa_driver_new (char *name, char *playback_alsa_device, - char *capture_alsa_device, - jack_client_t *client, - jack_nframes_t frames_per_cycle, - jack_nframes_t user_nperiods, - jack_nframes_t rate, - int hw_monitoring, - int hw_metering, - int capturing, - int playing, - DitherAlgorithm dither, - int soft_mode, - int monitor, - int user_capture_nchnls, - int user_playback_nchnls, - int shorts_first, - jack_nframes_t capture_latency, - jack_nframes_t playback_latency - ) -{ - int err; + if (driver->pfd[nfds - 1].revents == 0) { + /* we timed out on the extra fd */ - alsa_driver_t *driver; + *status = -4; - /* - printf ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32 - "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s\n", - playing ? playback_alsa_device : "-", - capturing ? capture_alsa_device : "-", - frames_per_cycle, user_nperiods, rate, - user_capture_nchnls,user_playback_nchnls, - hw_monitoring ? "hwmon": "nomon", - hw_metering ? "hwmeter":"swmeter", - soft_mode ? "soft-mode":"-", - shorts_first ? "16bit":"32bit"); - */ + // steph (cannot return negative value....) + // return -1; + return 0; + } - driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); + /* if POLLIN was the only bit set, we're OK */ - jack_driver_nt_init ((jack_driver_nt_t *) driver); + *status = 0; + return (driver->pfd[nfds - 1].revents == POLLIN) ? 0 : -1; + } - //driver->nt_attach = (JackDriverNTAttachFunction) alsa_driver_attach; - //driver->nt_detach = (JackDriverNTDetachFunction) alsa_driver_detach; - //driver->read = (JackDriverReadFunction) alsa_driver_read; - //driver->write = (JackDriverReadFunction) alsa_driver_write; - //driver->null_cycle = (JackDriverNullCycleFunction) alsa_driver_null_cycle; - //driver->nt_bufsize = (JackDriverNTBufSizeFunction) alsa_driver_bufsize; - //driver->nt_start = (JackDriverNTStartFunction) alsa_driver_start; - //driver->nt_stop = (JackDriverNTStopFunction) alsa_driver_stop; - //driver->nt_run_cycle = (JackDriverNTRunCycleFunction) alsa_driver_run_cycle; + p_timed_out = 0; - driver->playback_handle = NULL; - driver->capture_handle = NULL; - driver->ctl_handle = 0; - driver->hw = 0; - driver->capture_and_playback_not_synced = FALSE; - driver->max_nchannels = 0; - driver->user_nchannels = 0; - driver->playback_nchannels = user_playback_nchnls; - driver->capture_nchannels = user_capture_nchnls; - driver->playback_sample_bytes = (shorts_first ? 2 : 4); - driver->capture_sample_bytes = (shorts_first ? 2 : 4); - driver->capture_frame_latency = capture_latency; - driver->playback_frame_latency = playback_latency; + if (need_playback) { + for (i = 0; i < driver->playback_nfds; i++) { + if (driver->pfd[i].revents & POLLERR) { + xrun_detected = TRUE; + } - driver->playback_addr = 0; - driver->capture_addr = 0; - driver->playback_interleave_skip = NULL; // steph - driver->capture_interleave_skip = NULL; // steph + if (driver->pfd[i].revents == 0) { + p_timed_out++; +#ifdef DEBUG_WAKEUP - driver->silent = 0; - driver->all_monitor_in = FALSE; - driver->with_monitor_ports = monitor; + fprintf (stderr, "%" PRIu64 + " playback stream timed out\n", + poll_ret); +#endif - driver->clock_mode = ClockMaster; /* XXX is it? */ - driver->input_monitor_mask = 0; /* XXX is it? */ + } + } - driver->capture_ports = 0; - driver->playback_ports = 0; - driver->monitor_ports = 0; + if (p_timed_out == 0) { + need_playback = 0; +#ifdef DEBUG_WAKEUP - driver->pfd = 0; - driver->playback_nfds = 0; - driver->capture_nfds = 0; + fprintf (stderr, "%" PRIu64 + " playback stream ready\n", + poll_ret); +#endif - driver->dither = dither; - driver->soft_mode = soft_mode; + } + } - pthread_mutex_init (&driver->clock_sync_lock, 0); - driver->clock_sync_listeners = 0; + c_timed_out = 0; - driver->poll_late = 0; - driver->xrun_count = 0; - driver->process_count = 0; + if (need_capture) { + for (i = ci; i < nfds; i++) { + if (driver->pfd[i].revents & POLLERR) { + xrun_detected = TRUE; + } - driver->alsa_name_playback = strdup (playback_alsa_device); - driver->alsa_name_capture = strdup (capture_alsa_device); + if (driver->pfd[i].revents == 0) { + c_timed_out++; +#ifdef DEBUG_WAKEUP - if (alsa_driver_check_card_type (driver)) { - alsa_driver_delete (driver); - return NULL; - } + fprintf (stderr, "%" PRIu64 + " capture stream timed out\n", + poll_ret); +#endif - alsa_driver_hw_specific (driver, hw_monitoring, hw_metering); + } + } - if (playing) { - if (snd_pcm_open (&driver->playback_handle, - playback_alsa_device, - SND_PCM_STREAM_PLAYBACK, - SND_PCM_NONBLOCK) < 0) { - switch (errno) { - case EBUSY: - jack_error ("the playback device \"%s\" is " - "already in use. Please stop the" - " application using it and " - "run JACK again", - playback_alsa_device); - alsa_driver_delete (driver); - return NULL; - break; + if (c_timed_out == 0) { + need_capture = 0; +#ifdef DEBUG_WAKEUP - case EPERM: - jack_error ("you do not have permission to open " - "the audio device \"%s\" for playback", - playback_alsa_device); - alsa_driver_delete (driver); - return NULL; - break; - } + fprintf (stderr, "%" PRIu64 + " capture stream ready\n", + poll_ret); +#endif - driver->playback_handle = NULL; + } } - if (driver->playback_handle) { - snd_pcm_nonblock (driver->playback_handle, 0); - } - } + if ((p_timed_out && (p_timed_out == driver->playback_nfds)) && + (c_timed_out && (c_timed_out == driver->capture_nfds))) { + // steph + /* + jack_error ("ALSA: poll time out, polled for %" PRIu64 + " usecs", + poll_ret - poll_enter); + */ + *status = -5; + return 0; + } - if (capturing) { - if (snd_pcm_open (&driver->capture_handle, - capture_alsa_device, - SND_PCM_STREAM_CAPTURE, - SND_PCM_NONBLOCK) < 0) { - switch (errno) { - case EBUSY: - jack_error ("the capture device \"%s\" is " - "already in use. Please stop the" - " application using it and " - "run JACK again", - capture_alsa_device); - alsa_driver_delete (driver); - return NULL; - break; + } - case EPERM: - jack_error ("you do not have permission to open " - "the audio device \"%s\" for capture", - capture_alsa_device); - alsa_driver_delete (driver); - return NULL; - break; + if (driver->capture_handle) { + if ((capture_avail = snd_pcm_avail_update ( + driver->capture_handle)) < 0) { + if (capture_avail == -EPIPE) { + xrun_detected = TRUE; + } else { + jack_error ("unknown ALSA avail_update return" + " value (%u)", capture_avail); } - - driver->capture_handle = NULL; } + } else { + /* odd, but see min() computation below */ + capture_avail = INT_MAX; + } - if (driver->capture_handle) { - snd_pcm_nonblock (driver->capture_handle, 0); + if (driver->playback_handle) { + if ((playback_avail = snd_pcm_avail_update ( + driver->playback_handle)) < 0) { + if (playback_avail == -EPIPE) { + xrun_detected = TRUE; + } else { + jack_error ("unknown ALSA avail_update return" + " value (%u)", playback_avail); + } } + } else { + /* odd, but see min() computation below */ + playback_avail = INT_MAX; } - if (driver->playback_handle == NULL) { - if (playing) { + if (xrun_detected) { + *status = alsa_driver_xrun_recovery (driver, delayed_usecs); + return 0; + } - /* they asked for playback, but we can't do it */ + *status = 0; + driver->last_wait_ust = poll_ret; - jack_error ("ALSA: Cannot open PCM device %s for " - "playback. Falling back to capture-only" - " mode", name); + avail = capture_avail < playback_avail ? capture_avail : playback_avail; - if (driver->capture_handle == NULL) { - /* can't do anything */ - alsa_driver_delete (driver); - return NULL; - } +#ifdef DEBUG_WAKEUP - playing = FALSE; - } - } + fprintf (stderr, "wakeup complete, avail = %lu, pavail = %lu " + "cavail = %lu\n", + avail, playback_avail, capture_avail); +#endif - if (driver->capture_handle == NULL) { - if (capturing) { + /* mark all channels not done for now. read/write will change this */ - /* they asked for capture, but we can't do it */ + bitset_copy (driver->channels_not_done, driver->channels_done); - jack_error ("ALSA: Cannot open PCM device %s for " - "capture. Falling back to playback-only" - " mode", name); + /* constrain the available count to the nearest (round down) number of + periods. + */ - if (driver->playback_handle == NULL) { - /* can't do anything */ - alsa_driver_delete (driver); - return NULL; - } + return avail - (avail % driver->frames_per_cycle); +} - capturing = FALSE; - } +int JackAlsaDriver::SetBufferSize(jack_nframes_t nframes) +{ + JackLog("JackAlsaDriver::SetBufferSize %ld\n", nframes); + fEngineControl->fBufferSize = nframes; + fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize); // in microsec + + return alsa_driver_reset_parameters ((alsa_driver_t *)fDriver, nframes, + ((alsa_driver_t *)fDriver)->user_nperiods, + ((alsa_driver_t *)fDriver)->frame_rate); +} + +int +JackAlsaDriver::alsa_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) +{ + snd_pcm_sframes_t contiguous; + snd_pcm_sframes_t nread; + snd_pcm_sframes_t offset; + jack_nframes_t orig_nframes; + jack_default_audio_sample_t* buf; + //channel_t chn; + //JSList *node; + //jack_port_t* port; + int err; + + // steph + /* + if (!driver->capture_handle || driver->engine->freewheeling) { + return 0; + } + */ + if (!driver->capture_handle) { + return 0; + } + if (nframes > driver->frames_per_cycle) { + return -1; } - driver->playback_hw_params = 0; - driver->capture_hw_params = 0; - driver->playback_sw_params = 0; - driver->capture_sw_params = 0; + nread = 0; + contiguous = 0; + orig_nframes = nframes; - if (driver->playback_handle) { - if ((err = snd_pcm_hw_params_malloc ( - &driver->playback_hw_params)) < 0) { - jack_error ("ALSA: could not allocate playback hw" - " params structure"); - alsa_driver_delete (driver); - return NULL; + while (nframes) { + + contiguous = nframes; + + if (alsa_driver_get_channel_addresses ( + driver, + (snd_pcm_uframes_t *) &contiguous, + (snd_pcm_uframes_t *) 0, + (snd_pcm_uframes_t *)&offset, 0) < 0) { + return -1; } - if ((err = snd_pcm_sw_params_malloc ( - &driver->playback_sw_params)) < 0) { - jack_error ("ALSA: could not allocate playback sw" - " params structure"); - alsa_driver_delete (driver); - return NULL; + // steph + for (int i = 0; i < fCaptureChannels; i++) { + if (fGraphManager->GetConnectionsNum(fCapturePortList[i]) > 0) { + buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fCapturePortList[i], orig_nframes); + alsa_driver_read_from_channel (driver, i, buf + nread, contiguous); + } } - } - if (driver->capture_handle) { - if ((err = snd_pcm_hw_params_malloc ( - &driver->capture_hw_params)) < 0) { - jack_error ("ALSA: could not allocate capture hw" - " params structure"); - alsa_driver_delete (driver); - return NULL; + /* // steph + for (chn = 0, node = driver->capture_ports; node; + node = jack_slist_next (node), chn++) { + + port = (jack_port_t *) node->data; + + if (!jack_port_connected (port)) { + // no-copy optimization + continue; + } + buf = jack_port_get_buffer (port, orig_nframes); + alsa_driver_read_from_channel (driver, chn, + buf + nread, contiguous); } + */ - if ((err = snd_pcm_sw_params_malloc ( - &driver->capture_sw_params)) < 0) { - jack_error ("ALSA: could not allocate capture sw" - " params structure"); - alsa_driver_delete (driver); - return NULL; + if ((err = snd_pcm_mmap_commit (driver->capture_handle, + offset, contiguous)) < 0) { + // steph + // jack_error ("ALSA: could not complete read of %" + // PRIu32 " frames: error = %d\n", contiguous, err); + jack_error ("ALSA: could not complete read of %d frames: error = %d", contiguous, err); + return -1; } - } - if (alsa_driver_set_parameters (driver, frames_per_cycle, - user_nperiods, rate)) { - alsa_driver_delete (driver); - return NULL; + nframes -= contiguous; + nread += contiguous; } - driver->capture_and_playback_not_synced = FALSE; + return 0; +} - if (driver->capture_handle && driver->playback_handle) { - if (snd_pcm_link (driver->capture_handle, - driver->playback_handle) != 0) { - driver->capture_and_playback_not_synced = TRUE; - } - } +int +JackAlsaDriver::alsa_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) +{ + //channel_t chn; + //JSList *node; + //JSList *mon_node; + jack_default_audio_sample_t* buf; + jack_default_audio_sample_t* monbuf; + jack_nframes_t orig_nframes; + snd_pcm_sframes_t nwritten; + snd_pcm_sframes_t contiguous; + snd_pcm_sframes_t offset; + JackPort* port; + //jack_port_t *port; + int err; - driver->client = client; + driver->process_count++; - return (jack_driver_t *) driver; -} + // steph + /* + if (!driver->playback_handle || driver->engine->freewheeling) { + return 0; + } + */ + if (!driver->playback_handle) { + return 0; + } -int JackAlsaDriver::Attach() -{ - JackPort* port; - int port_index; - unsigned long port_flags; + if (nframes > driver->frames_per_cycle) { + return -1; + } - char buf[JACK_PORT_NAME_SIZE]; + nwritten = 0; + contiguous = 0; + orig_nframes = nframes; - port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; + /* check current input monitor request status */ - assert(fCaptureChannels < PORT_NUM); - assert(fPlaybackChannels < PORT_NUM); - - alsa_driver_t* alsa_driver = (alsa_driver_t*)fDriver; + driver->input_monitor_mask = 0; - JackLog("JackAudioDriver::Attach fBufferSize %ld fSampleRate %ld\n", fEngineControl->fBufferSize, fEngineControl->fSampleRate); + // steph + /* + for (chn = 0, node = driver->capture_ports; node; + node = jack_slist_next (node), chn++) { + if (((jack_port_t *) node->data)->shared->monitor_requests) { + driver->input_monitor_mask |= (1<GetPort(fCapturePortList[i]); + if (port->MonitoringInput()) { + driver->input_monitor_mask |= (1<fName, i + 1); - if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, buf, (JackPortFlags)port_flags)) == NO_PORT) { - jack_error("driver: cannot register port for %s", buf); - return -1; + if (driver->hw_monitoring) { + if ((driver->hw->input_monitor_mask + != driver->input_monitor_mask) + && !driver->all_monitor_in) { + driver->hw->set_input_monitor_mask ( + driver->hw, driver->input_monitor_mask); } - port = fGraphManager->GetPort(port_index); - port->SetLatency(alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency); - fCapturePortList[i] = port_index; - JackLog("JackAudioDriver::Attach fCapturePortList[i] %ld \n", port_index); } - port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal; + while (nframes) { - for (int i = 0; i < fPlaybackChannels; i++) { - snprintf(buf, sizeof(buf) - 1, "%s:playback_%u", fClientControl->fName, i + 1); - if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, buf, (JackPortFlags)port_flags)) == NO_PORT) { - jack_error("driver: cannot register port for %s", buf); + contiguous = nframes; + + if (alsa_driver_get_channel_addresses ( + driver, + (snd_pcm_uframes_t *) 0, + (snd_pcm_uframes_t *) &contiguous, + 0, (snd_pcm_uframes_t *)&offset) < 0) { return -1; } - port = fGraphManager->GetPort(port_index); - port->SetLatency((alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) + alsa_driver->playback_frame_latency); - fPlaybackPortList[i] = port_index; - JackLog("JackAudioDriver::Attach fPlaybackPortList[i] %ld \n", port_index); - - // Monitor ports - if (fWithMonitorPorts) { - JackLog("Create monitor port \n"); - snprintf(buf, sizeof(buf) - 1, "%s:monitor_%lu",fClientControl->fName, i + 1); - if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, buf, JackPortIsOutput)) == NO_PORT) { - jack_error ("ALSA: cannot register monitor port for %s", buf); - } else { - port = fGraphManager->GetPort(port_index); - port->SetLatency(alsa_driver->frames_per_cycle); - fMonitorPortList[i] = port_index; - } - } - } - return 0; -} + // steph + for (int i = 0; i < fPlaybackChannels; i++) { + // Ouput ports + if (fGraphManager->GetConnectionsNum(fPlaybackPortList[i]) > 0) { + buf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fPlaybackPortList[i], orig_nframes); + alsa_driver_write_to_channel (driver, i, buf + nwritten, contiguous); + // Monitor ports + if (fWithMonitorPorts && fGraphManager->GetConnectionsNum(fMonitorPortList[i]) > 0) { + monbuf = (jack_default_audio_sample_t*)fGraphManager->GetBuffer(fMonitorPortList[i], orig_nframes); + memcpy(monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); + } + } + } -int JackAlsaDriver::Detach() -{ - JackLog("JackAlsaDriver::Detach\n"); + /* + for (chn = 0, node = driver->playback_ports, mon_node=driver->monitor_ports; + node; + node = jack_slist_next (node), chn++) { - for (int i = 0; i < fCaptureChannels; i++) { - fGraphManager->RemovePort(fClientControl->fRefNum, fCapturePortList[i]); - } + port = (jack_port_t *) node->data; - for (int i = 0; i < fPlaybackChannels; i++) { - fGraphManager->RemovePort(fClientControl->fRefNum, fPlaybackPortList[i]); - if (fWithMonitorPorts) - fGraphManager->RemovePort(fClientControl->fRefNum, fMonitorPortList[i]); - } + if (!jack_port_connected (port)) { + continue; + } + buf = jack_port_get_buffer (port, orig_nframes); + alsa_driver_write_to_channel (driver, chn, + buf + nwritten, contiguous); - return 0; -} + if (mon_node) { + port = (jack_port_t *) mon_node->data; + if (!jack_port_connected (port)) { + continue; + } + monbuf = jack_port_get_buffer (port, orig_nframes); + memcpy (monbuf + nwritten, buf + nwritten, contiguous * sizeof(jack_default_audio_sample_t)); + mon_node = jack_slist_next (mon_node); + } + } + */ -int JackAlsaDriver::Open(jack_nframes_t nframes, - jack_nframes_t user_nperiods, - jack_nframes_t samplerate, - int hw_monitoring, - int hw_metering, - int capturing, - int playing, - DitherAlgorithm dither, - int soft_mode, - int monitor, - int inchannels, - int outchannels, - int shorts_first, - const char* capture_driver_name, - const char* playback_driver_name, - jack_nframes_t capture_latency, - jack_nframes_t playback_latency) -{ - // Generic JackAudioDriver Open - if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, - inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, - capture_latency, playback_latency) != 0) { - return -1; - } + if (!bitset_empty (driver->channels_not_done)) { + alsa_driver_silence_untouched_channels (driver, + contiguous); + } - fDriver = alsa_driver_new ("alsa_pcm", (char*)capture_driver_name, (char*)playback_driver_name, - NULL, - nframes, - user_nperiods, - samplerate, - hw_monitoring, - hw_metering, - capturing, - playing, - dither, - soft_mode, - monitor, - inchannels, - outchannels, - shorts_first, - capture_latency, - playback_latency); - if (fDriver) { - // ALSA driver may have changed the in/out values - fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels; - fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels; - return 0; - } else { - return -1; - } -} + if ((err = snd_pcm_mmap_commit (driver->playback_handle, + offset, contiguous)) < 0) { + // steph + // jack_error ("ALSA: could not complete playback of %" + // PRIu32 " frames: error = %d", contiguous, err); + jack_error ("ALSA: could not complete playback of %d frames: error = %d", contiguous, err); + if (err != EPIPE && err != ESTRPIPE) + return -1; + } -int JackAlsaDriver::Close() -{ - JackAudioDriver::Close(); - alsa_driver_delete((alsa_driver_t*)fDriver); + nframes -= contiguous; + nwritten += contiguous; + } return 0; } -int JackAlsaDriver::Start() -{ - return alsa_driver_start((alsa_driver_t *)fDriver); -} - -int JackAlsaDriver::Stop() -{ - return alsa_driver_stop((alsa_driver_t *)fDriver); -} - -int JackAlsaDriver::Read() +void +JackAlsaDriver::alsa_driver_delete (alsa_driver_t *driver) { - /* Taken from alsa_driver_run_cycle */ - - //jack_engine_t *engine = driver->engine; - int wait_status; - float delayed_usecs; - jack_nframes_t nframes; + JSList *node; - //DEBUG ("alsa run cycle wait\n"); - nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &delayed_usecs); - //DEBUG ("alsaback from wait, nframes = %lu", nframes); + for (node = driver->clock_sync_listeners; node; + node = jack_slist_next (node)) { + free (node->data); + } + jack_slist_free (driver->clock_sync_listeners); - if (wait_status < 0) - return -1; /* driver failed */ + if (driver->capture_handle) { + snd_pcm_close (driver->capture_handle); + driver->capture_handle = 0; + } - if (nframes == 0) { + if (driver->playback_handle) { + snd_pcm_close (driver->playback_handle); + driver->capture_handle = 0; + } - /* we detected an xrun and restarted: notify - * clients about the delay. - */ - //engine->delay (engine, delayed_usecs); - JackLog("ALSA XRun \n"); - //NotifyXRun(jack_get_microseconds()); - NotifyXRun(fLastWaitUst); - //return 0; - return -1; + if (driver->capture_hw_params) { + snd_pcm_hw_params_free (driver->capture_hw_params); + driver->capture_hw_params = 0; } - //fLastWaitUst = GetMicroSeconds(); // Take callback date here - if (nframes != fEngineControl->fBufferSize) - JackLog("JackAlsaDriver::Read nframes = %ld\n", nframes); + if (driver->playback_hw_params) { + snd_pcm_hw_params_free (driver->playback_hw_params); + driver->playback_hw_params = 0; + } - //return engine->run_cycle (engine, nframes, delayed_usecs); - fDelayedUst = (jack_time_t)delayed_usecs; - return alsa_driver_read((alsa_driver_t *)fDriver, fEngineControl->fBufferSize); -} + if (driver->capture_sw_params) { + snd_pcm_sw_params_free (driver->capture_sw_params); + driver->capture_sw_params = 0; + } -int JackAlsaDriver::Write() -{ - //JackLog("write\n"); - int res = alsa_driver_write((alsa_driver_t *)fDriver, fEngineControl->fBufferSize); - jack_time_t write_time = GetMicroSeconds(); + if (driver->playback_sw_params) { + snd_pcm_sw_params_free (driver->playback_sw_params); + driver->playback_sw_params = 0; + } - /* - if (write_time > (fLastWaitUst - fDelayedUst) + fEngineControl->fPeriodUsecs) { - JackLog("ALSA write XRun \n"); - NotifyXRun(write_time); + if (driver->pfd) { + free (driver->pfd); } - */ - return res; -} -int JackAlsaDriver::SetBufferSize(jack_nframes_t nframes) -{ - JackLog("JackAlsaDriver::SetBufferSize %ld\n", nframes); - fEngineControl->fBufferSize = nframes; - fEngineControl->fPeriodUsecs = jack_time_t(1000000.f / fEngineControl->fSampleRate * fEngineControl->fBufferSize); // in microsec + if (driver->hw) { + driver->hw->release (driver->hw); + driver->hw = 0; + } + free(driver->alsa_name_playback); + free(driver->alsa_name_capture); + free(driver->alsa_driver); - return alsa_driver_reset_parameters ((alsa_driver_t *)fDriver, nframes, - ((alsa_driver_t *)fDriver)->user_nperiods, - ((alsa_driver_t *)fDriver)->frame_rate); + alsa_driver_release_channel_dependent_memory (driver); + jack_driver_nt_finish ((jack_driver_nt_t *) driver); + free (driver); } -void -JackAlsaDriver::alsa_driver_silence_untouched_channels (alsa_driver_t *driver, - jack_nframes_t nframes) +jack_driver_t * +JackAlsaDriver::alsa_driver_new (char *name, char *playback_alsa_device, + char *capture_alsa_device, + jack_client_t *client, + jack_nframes_t frames_per_cycle, + jack_nframes_t user_nperiods, + jack_nframes_t rate, + int hw_monitoring, + int hw_metering, + int capturing, + int playing, + DitherAlgorithm dither, + int soft_mode, + int monitor, + int user_capture_nchnls, + int user_playback_nchnls, + int shorts_first, + jack_nframes_t capture_latency, + jack_nframes_t playback_latency + ) { - channel_t chn; - jack_nframes_t buffer_frames = - driver->frames_per_cycle * driver->playback_nperiods; - - for (chn = 0; chn < driver->playback_nchannels; chn++) { - if (bitset_contains (driver->channels_not_done, chn)) { - if (driver->silent[chn] < buffer_frames) { - alsa_driver_silence_on_channel_no_mark ( - driver, chn, nframes); - driver->silent[chn] += nframes; - } - } - } -} + int err; -jack_nframes_t -JackAlsaDriver::alsa_driver_wait (alsa_driver_t *driver, int extra_fd, int *status, float - *delayed_usecs) -{ - snd_pcm_sframes_t avail = 0; - snd_pcm_sframes_t capture_avail = 0; - snd_pcm_sframes_t playback_avail = 0; - int xrun_detected = FALSE; - int need_capture; - int need_playback; - unsigned int i; - jack_time_t poll_enter; - jack_time_t poll_ret = 0; + alsa_driver_t *driver; - *status = -1; - *delayed_usecs = 0; + /* + printf ("creating alsa driver ... %s|%s|%" PRIu32 "|%" PRIu32 + "|%" PRIu32"|%" PRIu32"|%" PRIu32 "|%s|%s|%s|%s\n", + playing ? playback_alsa_device : "-", + capturing ? capture_alsa_device : "-", + frames_per_cycle, user_nperiods, rate, + user_capture_nchnls,user_playback_nchnls, + hw_monitoring ? "hwmon": "nomon", + hw_metering ? "hwmeter":"swmeter", + soft_mode ? "soft-mode":"-", + shorts_first ? "16bit":"32bit"); + */ - need_capture = driver->capture_handle ? 1 : 0; + driver = (alsa_driver_t *) calloc (1, sizeof (alsa_driver_t)); - if (extra_fd >= 0) { - need_playback = 0; - } else { - need_playback = driver->playback_handle ? 1 : 0; - } + jack_driver_nt_init ((jack_driver_nt_t *) driver); - // steph - // again: + //driver->nt_attach = (JackDriverNTAttachFunction) alsa_driver_attach; + //driver->nt_detach = (JackDriverNTDetachFunction) alsa_driver_detach; + //driver->read = (JackDriverReadFunction) alsa_driver_read; + //driver->write = (JackDriverReadFunction) alsa_driver_write; + //driver->null_cycle = (JackDriverNullCycleFunction) alsa_driver_null_cycle; + //driver->nt_bufsize = (JackDriverNTBufSizeFunction) alsa_driver_bufsize; + //driver->nt_start = (JackDriverNTStartFunction) alsa_driver_start; + //driver->nt_stop = (JackDriverNTStopFunction) alsa_driver_stop; + //driver->nt_run_cycle = (JackDriverNTRunCycleFunction) alsa_driver_run_cycle; - while (need_playback || need_capture) { + driver->playback_handle = NULL; + driver->capture_handle = NULL; + driver->ctl_handle = 0; + driver->hw = 0; + driver->capture_and_playback_not_synced = FALSE; + driver->max_nchannels = 0; + driver->user_nchannels = 0; + driver->playback_nchannels = user_playback_nchnls; + driver->capture_nchannels = user_capture_nchnls; + driver->playback_sample_bytes = (shorts_first ? 2 : 4); + driver->capture_sample_bytes = (shorts_first ? 2 : 4); + driver->capture_frame_latency = capture_latency; + driver->playback_frame_latency = playback_latency; - unsigned int p_timed_out, c_timed_out; - unsigned int ci = 0; - unsigned int nfds; + driver->playback_addr = 0; + driver->capture_addr = 0; + driver->playback_interleave_skip = NULL; // steph + driver->capture_interleave_skip = NULL; // steph - nfds = 0; + driver->silent = 0; + driver->all_monitor_in = FALSE; + driver->with_monitor_ports = monitor; - if (need_playback) { - snd_pcm_poll_descriptors (driver->playback_handle, - &driver->pfd[0], - driver->playback_nfds); - nfds += driver->playback_nfds; - } + driver->clock_mode = ClockMaster; /* XXX is it? */ + driver->input_monitor_mask = 0; /* XXX is it? */ - if (need_capture) { - snd_pcm_poll_descriptors (driver->capture_handle, - &driver->pfd[nfds], - driver->capture_nfds); - ci = nfds; - nfds += driver->capture_nfds; - } + driver->capture_ports = 0; + driver->playback_ports = 0; + driver->monitor_ports = 0; - /* ALSA doesn't set POLLERR in some versions of 0.9.X */ + driver->pfd = 0; + driver->playback_nfds = 0; + driver->capture_nfds = 0; - for (i = 0; i < nfds; i++) { - driver->pfd[i].events |= POLLERR; - } + driver->dither = dither; + driver->soft_mode = soft_mode; - if (extra_fd >= 0) { - driver->pfd[nfds].fd = extra_fd; - driver->pfd[nfds].events = - POLLIN | POLLERR | POLLHUP | POLLNVAL; - nfds++; - } + pthread_mutex_init (&driver->clock_sync_lock, 0); + driver->clock_sync_listeners = 0; - poll_enter = jack_get_microseconds (); + driver->poll_late = 0; + driver->xrun_count = 0; + driver->process_count = 0; - if (poll_enter > driver->poll_next) { - /* - * This processing cycle was delayed past the - * next due interrupt! Do not account this as - * a wakeup delay: - */ - driver->poll_next = 0; - driver->poll_late++; - } + driver->alsa_name_playback = strdup (playback_alsa_device); + driver->alsa_name_capture = strdup (capture_alsa_device); - if (poll (driver->pfd, nfds, driver->poll_timeout) < 0) { + if (alsa_driver_check_card_type (driver)) { + alsa_driver_delete (driver); + return NULL; + } - if (errno == EINTR) { - printf ("poll interrupt\n"); - // this happens mostly when run - // under gdb, or when exiting due to a signal - // steph - /* - if (under_gdb) { - goto again; - } - */ - *status = -2; - return 0; + alsa_driver_hw_specific (driver, hw_monitoring, hw_metering); + + if (playing) { + if (snd_pcm_open (&driver->playback_handle, + playback_alsa_device, + SND_PCM_STREAM_PLAYBACK, + SND_PCM_NONBLOCK) < 0) { + switch (errno) { + case EBUSY: + jack_error ("the playback device \"%s\" is " + "already in use. Please stop the" + " application using it and " + "run JACK again", + playback_alsa_device); + alsa_driver_delete (driver); + return NULL; + break; + + case EPERM: + jack_error ("you do not have permission to open " + "the audio device \"%s\" for playback", + playback_alsa_device); + alsa_driver_delete (driver); + return NULL; + break; } - jack_error ("ALSA: poll call failed (%s)", - strerror (errno)); - *status = -3; - return 0; + driver->playback_handle = NULL; + } + if (driver->playback_handle) { + snd_pcm_nonblock (driver->playback_handle, 0); } + } - poll_ret = jack_get_microseconds (); - // steph - fLastWaitUst = poll_ret; + if (capturing) { + if (snd_pcm_open (&driver->capture_handle, + capture_alsa_device, + SND_PCM_STREAM_CAPTURE, + SND_PCM_NONBLOCK) < 0) { + switch (errno) { + case EBUSY: + jack_error ("the capture device \"%s\" is " + "already in use. Please stop the" + " application using it and " + "run JACK again", + capture_alsa_device); + alsa_driver_delete (driver); + return NULL; + break; - if (extra_fd < 0) { - if (driver->poll_next && poll_ret > driver->poll_next) { - *delayed_usecs = poll_ret - driver->poll_next; + case EPERM: + jack_error ("you do not have permission to open " + "the audio device \"%s\" for capture", + capture_alsa_device); + alsa_driver_delete (driver); + return NULL; + break; } - driver->poll_last = poll_ret; - driver->poll_next = poll_ret + driver->period_usecs; - - // steph - /* - driver->engine->transport_cycle_start (driver->engine, - poll_ret); - */ + driver->capture_handle = NULL; } -#ifdef DEBUG_WAKEUP - fprintf (stderr, "%" PRIu64 ": checked %d fds, %" PRIu64 - " usecs since poll entered\n", poll_ret, nfds, - poll_ret - poll_enter); -#endif - - /* check to see if it was the extra FD that caused us - * to return from poll */ + if (driver->capture_handle) { + snd_pcm_nonblock (driver->capture_handle, 0); + } + } - if (extra_fd >= 0) { + if (driver->playback_handle == NULL) { + if (playing) { - if (driver->pfd[nfds - 1].revents == 0) { - /* we timed out on the extra fd */ + /* they asked for playback, but we can't do it */ - *status = -4; + jack_error ("ALSA: Cannot open PCM device %s for " + "playback. Falling back to capture-only" + " mode", name); - // steph (cannot return negative value....) - // return -1; - return 0; + if (driver->capture_handle == NULL) { + /* can't do anything */ + alsa_driver_delete (driver); + return NULL; } - /* if POLLIN was the only bit set, we're OK */ - - *status = 0; - return (driver->pfd[nfds - 1].revents == POLLIN) ? 0 : -1; + playing = FALSE; } + } - p_timed_out = 0; - - if (need_playback) { - for (i = 0; i < driver->playback_nfds; i++) { - if (driver->pfd[i].revents & POLLERR) { - xrun_detected = TRUE; - } + if (driver->capture_handle == NULL) { + if (capturing) { - if (driver->pfd[i].revents == 0) { - p_timed_out++; -#ifdef DEBUG_WAKEUP + /* they asked for capture, but we can't do it */ - fprintf (stderr, "%" PRIu64 - " playback stream timed out\n", - poll_ret); -#endif + jack_error ("ALSA: Cannot open PCM device %s for " + "capture. Falling back to playback-only" + " mode", name); - } + if (driver->playback_handle == NULL) { + /* can't do anything */ + alsa_driver_delete (driver); + return NULL; } - if (p_timed_out == 0) { - need_playback = 0; -#ifdef DEBUG_WAKEUP + capturing = FALSE; + } + } - fprintf (stderr, "%" PRIu64 - " playback stream ready\n", - poll_ret); -#endif + driver->playback_hw_params = 0; + driver->capture_hw_params = 0; + driver->playback_sw_params = 0; + driver->capture_sw_params = 0; - } + if (driver->playback_handle) { + if ((err = snd_pcm_hw_params_malloc ( + &driver->playback_hw_params)) < 0) { + jack_error ("ALSA: could not allocate playback hw" + " params structure"); + alsa_driver_delete (driver); + return NULL; } - c_timed_out = 0; + if ((err = snd_pcm_sw_params_malloc ( + &driver->playback_sw_params)) < 0) { + jack_error ("ALSA: could not allocate playback sw" + " params structure"); + alsa_driver_delete (driver); + return NULL; + } + } - if (need_capture) { - for (i = ci; i < nfds; i++) { - if (driver->pfd[i].revents & POLLERR) { - xrun_detected = TRUE; - } + if (driver->capture_handle) { + if ((err = snd_pcm_hw_params_malloc ( + &driver->capture_hw_params)) < 0) { + jack_error ("ALSA: could not allocate capture hw" + " params structure"); + alsa_driver_delete (driver); + return NULL; + } - if (driver->pfd[i].revents == 0) { - c_timed_out++; -#ifdef DEBUG_WAKEUP + if ((err = snd_pcm_sw_params_malloc ( + &driver->capture_sw_params)) < 0) { + jack_error ("ALSA: could not allocate capture sw" + " params structure"); + alsa_driver_delete (driver); + return NULL; + } + } - fprintf (stderr, "%" PRIu64 - " capture stream timed out\n", - poll_ret); -#endif + if (alsa_driver_set_parameters (driver, frames_per_cycle, + user_nperiods, rate)) { + alsa_driver_delete (driver); + return NULL; + } - } - } + driver->capture_and_playback_not_synced = FALSE; - if (c_timed_out == 0) { - need_capture = 0; -#ifdef DEBUG_WAKEUP + if (driver->capture_handle && driver->playback_handle) { + if (snd_pcm_link (driver->capture_handle, + driver->playback_handle) != 0) { + driver->capture_and_playback_not_synced = TRUE; + } + } - fprintf (stderr, "%" PRIu64 - " capture stream ready\n", - poll_ret); -#endif + driver->client = client; - } - } + return (jack_driver_t *) driver; +} + +int JackAlsaDriver::Attach() +{ + JackPort* port; + int port_index; + unsigned long port_flags; + + char buf[JACK_PORT_NAME_SIZE]; - if ((p_timed_out && (p_timed_out == driver->playback_nfds)) && - (c_timed_out && (c_timed_out == driver->capture_nfds))) { - // steph - /* - jack_error ("ALSA: poll time out, polled for %" PRIu64 - " usecs", - poll_ret - poll_enter); - */ - *status = -5; - return 0; - } + port_flags = JackPortIsOutput | JackPortIsPhysical | JackPortIsTerminal; - } + assert(fCaptureChannels < PORT_NUM); + assert(fPlaybackChannels < PORT_NUM); + + alsa_driver_t* alsa_driver = (alsa_driver_t*)fDriver; - if (driver->capture_handle) { - if ((capture_avail = snd_pcm_avail_update ( - driver->capture_handle)) < 0) { - if (capture_avail == -EPIPE) { - xrun_detected = TRUE; - } else { - jack_error ("unknown ALSA avail_update return" - " value (%u)", capture_avail); - } - } - } else { - /* odd, but see min() computation below */ - capture_avail = INT_MAX; - } + JackLog("JackAudioDriver::Attach fBufferSize %ld fSampleRate %ld\n", fEngineControl->fBufferSize, fEngineControl->fSampleRate); - if (driver->playback_handle) { - if ((playback_avail = snd_pcm_avail_update ( - driver->playback_handle)) < 0) { - if (playback_avail == -EPIPE) { - xrun_detected = TRUE; - } else { - jack_error ("unknown ALSA avail_update return" - " value (%u)", playback_avail); - } + for (int i = 0; i < fCaptureChannels; i++) { + snprintf(buf, sizeof(buf) - 1, "%s:capture_%u", fClientControl->fName, i + 1); + if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, buf, (JackPortFlags)port_flags)) == NO_PORT) { + jack_error("driver: cannot register port for %s", buf); + return -1; } - } else { - /* odd, but see min() computation below */ - playback_avail = INT_MAX; + port = fGraphManager->GetPort(port_index); + port->SetLatency(alsa_driver->frames_per_cycle + alsa_driver->capture_frame_latency); + fCapturePortList[i] = port_index; + JackLog("JackAudioDriver::Attach fCapturePortList[i] %ld \n", port_index); } - if (xrun_detected) { - *status = alsa_driver_xrun_recovery (driver, delayed_usecs); - return 0; + port_flags = JackPortIsInput | JackPortIsPhysical | JackPortIsTerminal; + + for (int i = 0; i < fPlaybackChannels; i++) { + snprintf(buf, sizeof(buf) - 1, "%s:playback_%u", fClientControl->fName, i + 1); + if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, buf, (JackPortFlags)port_flags)) == NO_PORT) { + jack_error("driver: cannot register port for %s", buf); + return -1; + } + port = fGraphManager->GetPort(port_index); + port->SetLatency((alsa_driver->frames_per_cycle * (alsa_driver->user_nperiods - 1)) + alsa_driver->playback_frame_latency); + fPlaybackPortList[i] = port_index; + JackLog("JackAudioDriver::Attach fPlaybackPortList[i] %ld \n", port_index); + + // Monitor ports + if (fWithMonitorPorts) { + JackLog("Create monitor port \n"); + snprintf(buf, sizeof(buf) - 1, "%s:monitor_%lu",fClientControl->fName, i + 1); + if ((port_index = fGraphManager->AllocatePort(fClientControl->fRefNum, buf, JackPortIsOutput)) == NO_PORT) { + jack_error ("ALSA: cannot register monitor port for %s", buf); + } else { + port = fGraphManager->GetPort(port_index); + port->SetLatency(alsa_driver->frames_per_cycle); + fMonitorPortList[i] = port_index; + } + } } - *status = 0; - driver->last_wait_ust = poll_ret; + return 0; +} - avail = capture_avail < playback_avail ? capture_avail : playback_avail; +int JackAlsaDriver::Detach() +{ + JackLog("JackAlsaDriver::Detach\n"); -#ifdef DEBUG_WAKEUP + for (int i = 0; i < fCaptureChannels; i++) { + fGraphManager->RemovePort(fClientControl->fRefNum, fCapturePortList[i]); + } - fprintf (stderr, "wakeup complete, avail = %lu, pavail = %lu " - "cavail = %lu\n", - avail, playback_avail, capture_avail); -#endif + for (int i = 0; i < fPlaybackChannels; i++) { + fGraphManager->RemovePort(fClientControl->fRefNum, fPlaybackPortList[i]); + if (fWithMonitorPorts) + fGraphManager->RemovePort(fClientControl->fRefNum, fMonitorPortList[i]); + } - /* mark all channels not done for now. read/write will change this */ + return 0; +} - bitset_copy (driver->channels_not_done, driver->channels_done); +int JackAlsaDriver::Open(jack_nframes_t nframes, + jack_nframes_t user_nperiods, + jack_nframes_t samplerate, + int hw_monitoring, + int hw_metering, + int capturing, + int playing, + DitherAlgorithm dither, + int soft_mode, + int monitor, + int inchannels, + int outchannels, + int shorts_first, + const char* capture_driver_name, + const char* playback_driver_name, + jack_nframes_t capture_latency, + jack_nframes_t playback_latency) +{ + // Generic JackAudioDriver Open + if (JackAudioDriver::Open(nframes, samplerate, capturing, playing, + inchannels, outchannels, monitor, capture_driver_name, playback_driver_name, + capture_latency, playback_latency) != 0) { + return -1; + } - /* constrain the available count to the nearest (round down) number of - periods. - */ + fDriver = alsa_driver_new ("alsa_pcm", (char*)capture_driver_name, (char*)playback_driver_name, + NULL, + nframes, + user_nperiods, + samplerate, + hw_monitoring, + hw_metering, + capturing, + playing, + dither, + soft_mode, + monitor, + inchannels, + outchannels, + shorts_first, + capture_latency, + playback_latency); + if (fDriver) { + // ALSA driver may have changed the in/out values + fCaptureChannels = ((alsa_driver_t *)fDriver)->capture_nchannels; + fPlaybackChannels = ((alsa_driver_t *)fDriver)->playback_nchannels; + return 0; + } else { + return -1; + } +} - return avail - (avail % driver->frames_per_cycle); +int JackAlsaDriver::Close() +{ + JackAudioDriver::Close(); + alsa_driver_delete((alsa_driver_t*)fDriver); + return 0; } -int -JackAlsaDriver::alsa_driver_restart (alsa_driver_t *driver) +int JackAlsaDriver::Start() { - // steph - /* - if (driver->nt_stop((struct _jack_driver_nt *) driver)) - return -1; - return driver->nt_start((struct _jack_driver_nt *) driver); - */ + return alsa_driver_start((alsa_driver_t *)fDriver); +} - if (Stop()) - return -1; - return Start(); +int JackAlsaDriver::Stop() +{ + return alsa_driver_stop((alsa_driver_t *)fDriver); } -int -JackAlsaDriver::alsa_driver_xrun_recovery (alsa_driver_t *driver, float *delayed_usecs) +int JackAlsaDriver::Read() { - snd_pcm_status_t *status; - int res; + /* Taken from alsa_driver_run_cycle */ - jack_error("alsa_driver_xrun_recovery "); + //jack_engine_t *engine = driver->engine; + int wait_status; + float delayed_usecs; + jack_nframes_t nframes; - snd_pcm_status_alloca(&status); + //DEBUG ("alsa run cycle wait\n"); + nframes = alsa_driver_wait((alsa_driver_t *)fDriver, -1, &wait_status, &delayed_usecs); + //DEBUG ("alsaback from wait, nframes = %lu", nframes); - if (driver->capture_handle) { - if ((res = snd_pcm_status(driver->capture_handle, status)) - < 0) { - jack_error("status error: %s", snd_strerror(res)); - } - } else { - if ((res = snd_pcm_status(driver->playback_handle, status)) - < 0) { - jack_error("status error: %s", snd_strerror(res)); - } - } + if (wait_status < 0) + return -1; /* driver failed */ - if (snd_pcm_status_get_state(status) == SND_PCM_STATE_XRUN - // && driver->process_count > XRUN_REPORT_DELAY) { // steph - && driver->process_count > 10) { - struct timeval now, diff, tstamp; - driver->xrun_count++; - gettimeofday(&now, 0); - snd_pcm_status_get_trigger_tstamp(status, &tstamp); - timersub(&now, &tstamp, &diff); - *delayed_usecs = diff.tv_sec * 1000000.0 + diff.tv_usec; + if (nframes == 0) { - // steph: utiliser une version TR - jack_error("\n\n**** alsa_pcm: xrun of at least %.3f msecs\n\n", *delayed_usecs / 1000.0); + /* we detected an xrun and restarted: notify + * clients about the delay. + */ + //engine->delay (engine, delayed_usecs); + JackLog("ALSA XRun \n"); + //NotifyXRun(jack_get_microseconds()); + NotifyXRun(fLastWaitUst); + //return 0; + return -1; } - if (alsa_driver_restart (driver)) { - return -1; + //fLastWaitUst = GetMicroSeconds(); // Take callback date here + if (nframes != fEngineControl->fBufferSize) + JackLog("JackAlsaDriver::Read nframes = %ld\n", nframes); + + //return engine->run_cycle (engine, nframes, delayed_usecs); + fDelayedUst = (jack_time_t)delayed_usecs; + return alsa_driver_read((alsa_driver_t *)fDriver, fEngineControl->fBufferSize); +} + +int JackAlsaDriver::Write() +{ + //JackLog("write\n"); + int res = alsa_driver_write((alsa_driver_t *)fDriver, fEngineControl->fBufferSize); + jack_time_t write_time = GetMicroSeconds(); + + /* + if (write_time > (fLastWaitUst - fDelayedUst) + fEngineControl->fPeriodUsecs) { + JackLog("ALSA write XRun \n"); + NotifyXRun(write_time); } - return 0; + */ + return res; } + void JackAlsaDriver::jack_driver_init (jack_driver_t *driver) { diff --git a/linux/alsa/hammerfall.c b/linux/alsa/hammerfall.c index 55e189e9..3adeb74c 100644 --- a/linux/alsa/hammerfall.c +++ b/linux/alsa/hammerfall.c @@ -39,7 +39,7 @@ set_control_id (snd_ctl_elem_id_t *ctl, const char *name) { snd_ctl_elem_id_set_name (ctl, name); snd_ctl_elem_id_set_numid (ctl, 0); - snd_ctl_elem_id_set_interface (ctl, SND_CTL_ELEM_IFACE_PCM); + snd_ctl_elem_id_set_interface (ctl, SND_CTL_ELEM_IFACE_MIXER); snd_ctl_elem_id_set_device (ctl, 0); snd_ctl_elem_id_set_subdevice (ctl, 0); snd_ctl_elem_id_set_index (ctl, 0); @@ -142,7 +142,7 @@ hammerfall_check_sync (hammerfall_t *h, snd_ctl_elem_value_t *ctl) static int hammerfall_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) { - hammerfall_t *h = (hammerfall_t *) hw->private_hw; + hammerfall_t *h = (hammerfall_t *) hw->private; snd_ctl_elem_value_t *ctl; snd_ctl_elem_id_t *ctl_id; int err; @@ -170,7 +170,7 @@ hammerfall_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) static int hammerfall_change_sample_clock (jack_hardware_t *hw, SampleClockMode mode) { - hammerfall_t *h = (hammerfall_t *) hw->private_hw; + hammerfall_t *h = (hammerfall_t *) hw->private; snd_ctl_elem_value_t *ctl; snd_ctl_elem_id_t *ctl_id; int err; @@ -203,7 +203,7 @@ static void hammerfall_release (jack_hardware_t *hw) { - hammerfall_t *h = (hammerfall_t *) hw->private_hw; + hammerfall_t *h = (hammerfall_t *) hw->private; void *status; if (h == 0) { @@ -221,7 +221,7 @@ static void * hammerfall_monitor_controls (void *arg) { jack_hardware_t *hw = (jack_hardware_t *) arg; - hammerfall_t *h = (hammerfall_t *) hw->private_hw; + hammerfall_t *h = (hammerfall_t *) hw->private; snd_ctl_elem_id_t *switch_id[3]; snd_ctl_elem_value_t *sw[3]; @@ -279,7 +279,7 @@ jack_alsa_hammerfall_hw_new (alsa_driver_t *driver) hw->capabilities = Cap_HardwareMonitoring|Cap_AutoSync|Cap_WordClock|Cap_ClockMaster|Cap_ClockLockReporting; hw->input_monitor_mask = 0; - hw->private_hw = 0; + hw->private = 0; hw->set_input_monitor_mask = hammerfall_set_input_monitor_mask; hw->change_sample_clock = hammerfall_change_sample_clock; @@ -299,7 +299,7 @@ jack_alsa_hammerfall_hw_new (alsa_driver_t *driver) h->monitor_interval.tv_sec = 1; h->monitor_interval.tv_nsec = 0; - hw->private_hw = h; + hw->private = h; #if 0 if (pthread_create (&h->monitor_thread, 0, hammerfall_monitor_controls, hw)) { diff --git a/linux/alsa/hdsp.c b/linux/alsa/hdsp.c index 91ce856e..51c4b290 100644 --- a/linux/alsa/hdsp.c +++ b/linux/alsa/hdsp.c @@ -89,7 +89,7 @@ set_control_id (snd_ctl_elem_id_t *ctl, const char *name) static int hdsp_set_mixer_gain(jack_hardware_t *hw, int input_channel, int output_channel, int gain) { - hdsp_t *h = (hdsp_t *) hw->private_hw; + hdsp_t *h = (hdsp_t *) hw->private; snd_ctl_elem_value_t *ctl; snd_ctl_elem_id_t *ctl_id; int err; @@ -194,7 +194,7 @@ static double hdsp_get_hardware_power (jack_port_t *port, jack_nframes_t frame) static void hdsp_release (jack_hardware_t *hw) { - hdsp_t *h = (hdsp_t *) hw->private_hw; + hdsp_t *h = (hdsp_t *) hw->private; if (h != 0) { free (h); @@ -216,7 +216,7 @@ jack_alsa_hdsp_hw_new (alsa_driver_t *driver) /* hw->capabilities = Cap_HardwareMonitoring|Cap_AutoSync|Cap_WordClock|Cap_ClockMaster|Cap_ClockLockReporting; */ hw->capabilities = Cap_HardwareMonitoring | Cap_HardwareMetering; hw->input_monitor_mask = 0; - hw->private_hw = 0; + hw->private = 0; hw->set_input_monitor_mask = hdsp_set_input_monitor_mask; hw->change_sample_clock = hdsp_change_sample_clock; @@ -226,7 +226,7 @@ jack_alsa_hdsp_hw_new (alsa_driver_t *driver) h = (hdsp_t *) malloc (sizeof (hdsp_t)); h->driver = driver; - hw->private_hw = h; + hw->private = h; return hw; } diff --git a/linux/alsa/ice1712.c b/linux/alsa/ice1712.c index 500bce00..ffa3ee71 100644 --- a/linux/alsa/ice1712.c +++ b/linux/alsa/ice1712.c @@ -34,7 +34,7 @@ static int ice1712_hw_monitor_toggle(jack_hardware_t *hw, int idx, int onoff) { - ice1712_t *h = (ice1712_t *) hw->private_hw; + ice1712_t *h = (ice1712_t *) hw->private; snd_ctl_elem_value_t *val; int err; @@ -66,7 +66,7 @@ ice1712_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) { int idx; - ice1712_t *h = (ice1712_t *) hw->private_hw; + ice1712_t *h = (ice1712_t *) hw->private; for (idx = 0; idx < 10; idx++) { if (h->active_channels & (1<private_hw; + ice1712_t *h = (ice1712_t *) hw->private; if (h == 0) return; @@ -113,7 +113,7 @@ jack_alsa_ice1712_hw_new (alsa_driver_t *driver) hw->capabilities = Cap_HardwareMonitoring; hw->input_monitor_mask = 0; - hw->private_hw = 0; + hw->private = 0; hw->set_input_monitor_mask = ice1712_set_input_monitor_mask; hw->change_sample_clock = ice1712_change_sample_clock; @@ -155,7 +155,7 @@ jack_alsa_ice1712_hw_new (alsa_driver_t *driver) h->active_channels |= 0x300U; } - hw->private_hw = h; + hw->private = h; return hw; } diff --git a/linux/alsa/ice1712.h b/linux/alsa/ice1712.h index e32804e1..2e04c93c 100644 --- a/linux/alsa/ice1712.h +++ b/linux/alsa/ice1712.h @@ -1,24 +1,24 @@ /* - Copyright (C) 2002 Anthony Van Groningen + Copyright (C) 2002 Anthony Van Groningen - Parts based on source code taken from the - "Env24 chipset (ICE1712) control utility" that is + Parts based on source code taken from the + "Env24 chipset (ICE1712) control utility" that is - Copyright (C) 2000 by Jaroslav Kysela - - 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. + Copyright (C) 2000 by Jaroslav Kysela + + 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. + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ @@ -35,36 +35,31 @@ #define ANALOG_PLAYBACK_ROUTE_NAME "H/W Playback Route" #define MULTITRACK_PEAK_NAME "Multi Track Peak" -typedef struct -{ - unsigned int subvendor; /* PCI[2c-2f] */ - unsigned char size; /* size of EEPROM image in bytes */ - unsigned char version; /* must be 1 */ - unsigned char codec; /* codec configuration PCI[60] */ - unsigned char aclink; /* ACLink configuration PCI[61] */ - unsigned char i2sID; /* PCI[62] */ - unsigned char spdif; /* S/PDIF configuration PCI[63] */ - unsigned char gpiomask; /* GPIO initial mask, 0 = write, 1 = don't */ - unsigned char gpiostate; /* GPIO initial state */ - unsigned char gpiodir; /* GPIO direction state */ - unsigned short ac97main; - unsigned short ac97pcm; - unsigned short ac97rec; - unsigned char ac97recsrc; - unsigned char dacID[4]; /* I2S IDs for DACs */ - unsigned char adcID[4]; /* I2S IDs for ADCs */ - unsigned char extra[4]; -} -ice1712_eeprom_t; - -typedef struct -{ - alsa_driver_t *driver; - ice1712_eeprom_t *eeprom; - unsigned long active_channels; -} -ice1712_t; +typedef struct { + unsigned int subvendor; /* PCI[2c-2f] */ + unsigned char size; /* size of EEPROM image in bytes */ + unsigned char version; /* must be 1 */ + unsigned char codec; /* codec configuration PCI[60] */ + unsigned char aclink; /* ACLink configuration PCI[61] */ + unsigned char i2sID; /* PCI[62] */ + unsigned char spdif; /* S/PDIF configuration PCI[63] */ + unsigned char gpiomask; /* GPIO initial mask, 0 = write, 1 = don't */ + unsigned char gpiostate; /* GPIO initial state */ + unsigned char gpiodir; /* GPIO direction state */ + unsigned short ac97main; + unsigned short ac97pcm; + unsigned short ac97rec; + unsigned char ac97recsrc; + unsigned char dacID[4]; /* I2S IDs for DACs */ + unsigned char adcID[4]; /* I2S IDs for ADCs */ + unsigned char extra[4]; +} ice1712_eeprom_t; +typedef struct { + alsa_driver_t *driver; + ice1712_eeprom_t *eeprom; + unsigned long active_channels; +} ice1712_t; #ifdef __cplusplus extern "C" diff --git a/linux/alsa/memops.c b/linux/alsa/memops.c index 694df6d2..799c8e9b 100644 --- a/linux/alsa/memops.c +++ b/linux/alsa/memops.c @@ -30,7 +30,7 @@ #include #include #include - +#include #include "memops.h" @@ -50,6 +50,37 @@ inline unsigned int fast_rand() { return seed; } +void sample_move_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + long long y; + int z; + + while (nsamples--) { + y = (long long)(*src * SAMPLE_MAX_24BIT) << 8; + if (y > INT_MAX) { + z = INT_MAX; + } else if (y < INT_MIN) { + z = INT_MIN; + } else { + z = (int)y; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>24); + dst[1]=(char)(z>>16); + dst[2]=(char)(z>>8); + dst[3]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); + dst[3]=(char)(z>>24); +#endif + dst += dst_skip; + src++; + } +} + void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -69,6 +100,35 @@ void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigne } } +void sample_move_dS_s32u24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) +{ + /* ALERT: signed sign-extension portability !!! */ + + while (nsamples--) { + int x; +#if __BYTE_ORDER == __LITTLE_ENDIAN + x = (unsigned char)(src[0]); + x <<= 8; + x |= (unsigned char)(src[1]); + x <<= 8; + x |= (unsigned char)(src[2]); + x <<= 8; + x |= (unsigned char)(src[3]); +#elif __BYTE_ORDER == __BIG_ENDIAN + x = (unsigned char)(src[3]); + x <<= 8; + x |= (unsigned char)(src[2]); + x <<= 8; + x |= (unsigned char)(src[1]); + x <<= 8; + x |= (unsigned char)(src[0]); +#endif + *dst = (x >> 8) / SAMPLE_MAX_24BIT; + dst++; + src += src_skip; + } +} + void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { /* ALERT: signed sign-extension portability !!! */ @@ -80,6 +140,42 @@ void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigne } } +void sample_move_dither_rect_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + /* ALERT: signed sign-extension portability !!! */ + jack_default_audio_sample_t x; + long long y; + int z; + + while (nsamples--) { + x = *src * SAMPLE_MAX_16BIT; + x -= (float)fast_rand() / (float)INT_MAX; + y = (long long)f_round(x); + y <<= 16; + if (y > INT_MAX) { + z = INT_MAX; + } else if (y < INT_MIN) { + z = INT_MIN; + } else { + z = (int)y; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>24); + dst[1]=(char)(z>>16); + dst[2]=(char)(z>>8); + dst[3]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); + dst[3]=(char)(z>>24); +#endif + dst += dst_skip; + src++; + } +} + void sample_move_dither_rect_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -104,6 +200,47 @@ void sample_move_dither_rect_d32u24_sS (char *dst, jack_default_audio_sample_t * } } +void sample_move_dither_tri_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + jack_default_audio_sample_t x; + float r; + float rm1 = state->rm1; + long long y; + int z; + + while (nsamples--) { + x = *src * (float)SAMPLE_MAX_16BIT; + r = 2.0f * (float)fast_rand() / (float)INT_MAX - 1.0f; + x += r - rm1; + rm1 = r; + y = (long long)f_round(x); + y <<= 16; + + if (y > INT_MAX) { + z = INT_MAX; + } else if (y < INT_MIN) { + z = INT_MIN; + } else { + z = (int)y; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>24); + dst[1]=(char)(z>>16); + dst[2]=(char)(z>>8); + dst[3]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); + dst[3]=(char)(z>>24); +#endif + dst += dst_skip; + src++; + } + state->rm1 = rm1; +} + void sample_move_dither_tri_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -134,6 +271,66 @@ void sample_move_dither_tri_d32u24_sS (char *dst, jack_default_audio_sample_t * state->rm1 = rm1; } +void sample_move_dither_shaped_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + jack_default_audio_sample_t x; + jack_default_audio_sample_t xe; /* the innput sample - filtered error */ + jack_default_audio_sample_t xp; /* x' */ + float r; + float rm1 = state->rm1; + unsigned int idx = state->idx; + long long y; + int z; + + while (nsamples--) { + x = *src * (float)SAMPLE_MAX_16BIT; + r = 2.0f * (float)fast_rand() / (float)INT_MAX - 1.0f; + /* Filter the error with Lipshitz's minimally audible FIR: + [2.033 -2.165 1.959 -1.590 0.6149] */ + xe = x + - state->e[idx] * 2.033f + + state->e[(idx - 1) & DITHER_BUF_MASK] * 2.165f + - state->e[(idx - 2) & DITHER_BUF_MASK] * 1.959f + + state->e[(idx - 3) & DITHER_BUF_MASK] * 1.590f + - state->e[(idx - 4) & DITHER_BUF_MASK] * 0.6149f; + xp = xe + r - rm1; + rm1 = r; + + /* This could be some inline asm on x86 */ + y = (long long)f_round(xp); + + /* Intrinsic z^-1 delay */ + idx = (idx + 1) & DITHER_BUF_MASK; + state->e[idx] = y - xe; + + y <<= 16; + + if (y > INT_MAX) { + z = INT_MAX; + } else if (y < INT_MIN) { + z = INT_MIN; + } else { + z = (int)y; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>24); + dst[1]=(char)(z>>16); + dst[2]=(char)(z>>8); + dst[3]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); + dst[3]=(char)(z>>24); +#endif + dst += dst_skip; + src++; + } + state->rm1 = rm1; + state->idx = idx; +} + void sample_move_dither_shaped_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -182,6 +379,36 @@ void sample_move_dither_shaped_d32u24_sS (char *dst, jack_default_audio_sample_ state->idx = idx; } +void sample_move_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + long long y; + int z; + + while (nsamples--) { + y = (long long)(*src * SAMPLE_MAX_24BIT); + + if (y > (INT_MAX >> 8 )) { + z = (INT_MAX >> 8); + } else if (y < (INT_MIN >> 8 )) { + z = (INT_MIN >> 8 ); + } else { + z = (int)y; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>16); + dst[1]=(char)(z>>8); + dst[2]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); +#endif + dst += dst_skip; + src++; + } +} + void sample_move_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -205,6 +432,39 @@ void sample_move_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned l } } +void sample_move_dS_s24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) +{ + /* ALERT: signed sign-extension portability !!! */ + + while (nsamples--) { + int x; +#if __BYTE_ORDER == __LITTLE_ENDIAN + x = (unsigned char)(src[0]); + x <<= 8; + x |= (unsigned char)(src[1]); + x <<= 8; + x |= (unsigned char)(src[2]); + /* correct sign bit and the rest of the top byte */ + if (src[0] & 0x80) { + x |= 0xff << 24; + } +#elif __BYTE_ORDER == __BIG_ENDIAN + x = (unsigned char)(src[2]); + x <<= 8; + x |= (unsigned char)(src[1]); + x <<= 8; + x |= (unsigned char)(src[0]); + /* correct sign bit and the rest of the top byte */ + if (src[0] & 0x80) { + x |= 0xff << 24; + } +#endif + *dst = x / SAMPLE_MAX_24BIT; + dst++; + src += src_skip; + } +} + void sample_move_dS_s24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { /* ALERT: signed sign-extension portability !!! */ @@ -223,6 +483,42 @@ void sample_move_dS_s24 (jack_default_audio_sample_t *dst, char *src, unsigned l } } +void sample_move_dither_rect_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + /* ALERT: signed sign-extension portability !!! */ + jack_default_audio_sample_t x; + long long y; + int z; + + while (nsamples--) { + x = *src * SAMPLE_MAX_16BIT; + x -= (float)fast_rand() / (float)INT_MAX; + y = (long long)f_round(x); + + y <<= 8; + + if (y > (INT_MAX >> 8)) { + z = (INT_MAX >> 8); + } else if (y < (INT_MIN >> 8)) { + z = (INT_MIN >> 8); + } else { + z = (int)y; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>16); + dst[1]=(char)(z>>8); + dst[2]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); +#endif + dst += dst_skip; + src++; + } +} + void sample_move_dither_rect_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -253,6 +549,46 @@ void sample_move_dither_rect_d24_sS (char *dst, jack_default_audio_sample_t *src } } +void sample_move_dither_tri_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + jack_default_audio_sample_t x; + float r; + float rm1 = state->rm1; + long long y; + int z; + + while (nsamples--) { + x = *src * (float)SAMPLE_MAX_16BIT; + r = 2.0f * (float)fast_rand() / (float)INT_MAX - 1.0f; + x += r - rm1; + rm1 = r; + y = (long long)f_round(x); + + y <<= 8; + + if (y > (INT_MAX >> 8)) { + z = (INT_MAX >> 8); + } else if (y < (INT_MIN >> 8)) { + z = (INT_MIN >> 8); + } else { + z = (int)y; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>16); + dst[1]=(char)(z>>8); + dst[2]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); +#endif + dst += dst_skip; + src++; + } + state->rm1 = rm1; +} + void sample_move_dither_tri_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -287,6 +623,64 @@ void sample_move_dither_tri_d24_sS (char *dst, jack_default_audio_sample_t *src state->rm1 = rm1; } +void sample_move_dither_shaped_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + jack_default_audio_sample_t x; + jack_default_audio_sample_t xe; /* the innput sample - filtered error */ + jack_default_audio_sample_t xp; /* x' */ + float r; + float rm1 = state->rm1; + unsigned int idx = state->idx; + long long y; + int z; + + while (nsamples--) { + x = *src * (float)SAMPLE_MAX_16BIT; + r = 2.0f * (float)fast_rand() / (float)INT_MAX - 1.0f; + /* Filter the error with Lipshitz's minimally audible FIR: + [2.033 -2.165 1.959 -1.590 0.6149] */ + xe = x + - state->e[idx] * 2.033f + + state->e[(idx - 1) & DITHER_BUF_MASK] * 2.165f + - state->e[(idx - 2) & DITHER_BUF_MASK] * 1.959f + + state->e[(idx - 3) & DITHER_BUF_MASK] * 1.590f + - state->e[(idx - 4) & DITHER_BUF_MASK] * 0.6149f; + xp = xe + r - rm1; + rm1 = r; + + /* This could be some inline asm on x86 */ + y = (long long)f_round(xp); + + /* Intrinsic z^-1 delay */ + idx = (idx + 1) & DITHER_BUF_MASK; + state->e[idx] = y - xe; + + y <<= 8; + + if (y > (INT_MAX >> 8)) { + z = (INT_MAX >> 8); + } else if (y < (INT_MIN >> 8)) { + z = (INT_MIN >> 8); + } else { + z = (int)y; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(z>>16); + dst[1]=(char)(z>>8); + dst[2]=(char)(z); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(z); + dst[1]=(char)(z>>8); + dst[2]=(char)(z>>16); +#endif + dst += dst_skip; + src++; + } + state->rm1 = rm1; + state->idx = idx; +} + void sample_move_dither_shaped_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -339,6 +733,32 @@ void sample_move_dither_shaped_d24_sS (char *dst, jack_default_audio_sample_t * state->idx = idx; } +void sample_move_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + int tmp; + + /* ALERT: signed sign-extension portability !!! */ + + while (nsamples--) { + tmp = f_round(*src * SAMPLE_MAX_16BIT); + if (tmp > SHRT_MAX) { + tmp = SHRT_MAX; + } else if (tmp < SHRT_MIN) { + tmp = SHRT_MIN; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(tmp>>8); + dst[1]=(char)(tmp); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(tmp); + dst[1]=(char)(tmp>>8); +#endif + dst += dst_skip; + src++; + } +} + void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -360,6 +780,33 @@ void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned } } +void sample_move_dither_rect_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + jack_default_audio_sample_t val; + int tmp; + + while (nsamples--) { + val = *src * (float)SAMPLE_MAX_16BIT; + val -= (float)fast_rand() / (float)INT_MAX; + tmp = f_round(val); + if (tmp > SHRT_MAX) { + tmp = SHRT_MAX; + } else if (tmp < SHRT_MIN) { + tmp = SHRT_MIN; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(tmp>>8); + dst[1]=(char)(tmp); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(tmp); + dst[1]=(char)(tmp>>8); +#endif + dst += dst_skip; + src++; + } +} + void sample_move_dither_rect_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -382,6 +829,39 @@ void sample_move_dither_rect_d16_sS (char *dst, jack_default_audio_sample_t *sr } } +void sample_move_dither_tri_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + jack_default_audio_sample_t x; + float r; + float rm1 = state->rm1; + int y; + + while (nsamples--) { + x = *src * (float)SAMPLE_MAX_16BIT; + r = 2.0f * (float)fast_rand() / (float)INT_MAX - 1.0f; + x += r - rm1; + rm1 = r; + y = f_round(x); + + if (y > SHRT_MAX) { + y = SHRT_MAX; + } else if (y < SHRT_MIN) { + y = SHRT_MIN; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(y>>8); + dst[1]=(char)(y); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(y); + dst[1]=(char)(y>>8); +#endif + dst += dst_skip; + src++; + } + state->rm1 = rm1; +} + void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -411,6 +891,57 @@ void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_t *src state->rm1 = rm1; } +void sample_move_dither_shaped_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) + +{ + jack_default_audio_sample_t x; + jack_default_audio_sample_t xe; /* the innput sample - filtered error */ + jack_default_audio_sample_t xp; /* x' */ + float r; + float rm1 = state->rm1; + unsigned int idx = state->idx; + int y; + + while (nsamples--) { + x = *src * (float)SAMPLE_MAX_16BIT; + r = 2.0f * (float)fast_rand() / (float)INT_MAX - 1.0f; + /* Filter the error with Lipshitz's minimally audible FIR: + [2.033 -2.165 1.959 -1.590 0.6149] */ + xe = x + - state->e[idx] * 2.033f + + state->e[(idx - 1) & DITHER_BUF_MASK] * 2.165f + - state->e[(idx - 2) & DITHER_BUF_MASK] * 1.959f + + state->e[(idx - 3) & DITHER_BUF_MASK] * 1.590f + - state->e[(idx - 4) & DITHER_BUF_MASK] * 0.6149f; + xp = xe + r - rm1; + rm1 = r; + + /* This could be some inline asm on x86 */ + y = f_round(xp); + + /* Intrinsic z^-1 delay */ + idx = (idx + 1) & DITHER_BUF_MASK; + state->e[idx] = y - xe; + + if (y > SHRT_MAX) { + y = SHRT_MAX; + } else if (y < SHRT_MIN) { + y = SHRT_MIN; + } +#if __BYTE_ORDER == __LITTLE_ENDIAN + dst[0]=(char)(y>>8); + dst[1]=(char)(y); +#elif __BYTE_ORDER == __BIG_ENDIAN + dst[0]=(char)(y); + dst[1]=(char)(y>>8); +#endif + dst += dst_skip; + src++; + } + state->rm1 = rm1; + state->idx = idx; +} + void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state) { @@ -457,6 +988,28 @@ void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t * state->idx = idx; } +void sample_move_dS_s16s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) + +{ + short z; + + /* ALERT: signed sign-extension portability !!! */ + while (nsamples--) { +#if __BYTE_ORDER == __LITTLE_ENDIAN + z = (unsigned char)(src[0]); + z <<= 8; + z |= (unsigned char)(src[1]); +#elif __BYTE_ORDER == __BIG_ENDIAN + z = (unsigned char)(src[1]); + z <<= 8; + z |= (unsigned char)(src[0]); +#endif + *dst = z / SAMPLE_MAX_16BIT; + dst++; + src += src_skip; + } +} + void sample_move_dS_s16 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip) { diff --git a/linux/alsa/memops.h b/linux/alsa/memops.h index d10903c6..b8cdb0dd 100644 --- a/linux/alsa/memops.h +++ b/linux/alsa/memops.h @@ -33,74 +33,88 @@ typedef enum { #define DITHER_BUF_SIZE 8 #define DITHER_BUF_MASK 7 -typedef struct -{ +typedef struct { unsigned int depth; float rm1; unsigned int idx; float e[DITHER_BUF_SIZE]; } -dither_state_t; +} dither_state_t; #ifdef __cplusplus extern "C" { #endif - void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - - void sample_move_dither_rect_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_dither_tri_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_dither_shaped_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_dither_rect_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_dither_tri_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_dither_shaped_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_dither_rect_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - - void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); - void sample_move_dS_s24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); - void sample_move_dS_s16 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); - - void sample_merge_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - void sample_merge_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); - - static __inline__ void - sample_merge (jack_default_audio_sample_t *dst, jack_default_audio_sample_t *src, unsigned long cnt) - { - while (cnt--) { - *dst += *src; - dst++; - src++; - } - } - - static __inline__ void - sample_memcpy (jack_default_audio_sample_t *dst, jack_default_audio_sample_t *src, unsigned long cnt) - { - memcpy (dst, src, cnt * sizeof (jack_default_audio_sample_t)); - } - - void memset_interleave (char *dst, char val, unsigned long bytes, unsigned long unit_bytes, unsigned long skip_bytes); - void memcpy_fake (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); - - void memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); - void memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); - void memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); - - void merge_memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); - void merge_memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); - void merge_memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); - - void merge_memcpy_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); - void merge_memcpy_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); +void sample_move_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); + +void sample_move_dither_rect_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_rect_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_tri_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_tri_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_shaped_d32u24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_shaped_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_rect_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_rect_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_tri_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_tri_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_shaped_d24_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_shaped_d24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_rect_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_rect_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_tri_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_tri_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_shaped_d16_sSs (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_move_dither_shaped_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); + +void sample_move_dS_s32u24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); +void sample_move_dS_s32u24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); +void sample_move_dS_s24s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); +void sample_move_dS_s24 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); +void sample_move_dS_s16s (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); +void sample_move_dS_s16 (jack_default_audio_sample_t *dst, char *src, unsigned long nsamples, unsigned long src_skip); + +void sample_merge_d16_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); +void sample_merge_d32u24_sS (char *dst, jack_default_audio_sample_t *src, unsigned long nsamples, unsigned long dst_skip, dither_state_t *state); + +static __inline__ void +sample_merge (jack_default_audio_sample_t *dst, jack_default_audio_sample_t *src, unsigned long cnt) -#ifdef __cplusplus +{ + while (cnt--) { + *dst += *src; + dst++; + src++; + } } -#endif +static __inline__ void +sample_memcpy (jack_default_audio_sample_t *dst, jack_default_audio_sample_t *src, unsigned long cnt) + +{ + memcpy (dst, src, cnt * sizeof (jack_default_audio_sample_t)); +} + +void memset_interleave (char *dst, char val, unsigned long bytes, unsigned long unit_bytes, unsigned long skip_bytes); +void memcpy_fake (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); + +void memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); +void memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); +void memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); + +void merge_memcpy_interleave_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); +void merge_memcpy_interleave_d24_s24 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); +void merge_memcpy_interleave_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long dst_skip_bytes, unsigned long src_skip_bytes); + +void merge_memcpy_d16_s16 (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); +void merge_memcpy_d32_s32 (char *dst, char *src, unsigned long src_bytes, unsigned long foo, unsigned long bar); +#ifdef __cplusplus +} +#endif #endif /* __jack_memops_h__ */ diff --git a/linux/alsa/usx2y.c b/linux/alsa/usx2y.c index 74dd45c4..7ab128d7 100644 --- a/linux/alsa/usx2y.c +++ b/linux/alsa/usx2y.c @@ -33,7 +33,12 @@ #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) #endif +//#define DBGHWDEP +#ifdef DBGHWDEP +int dbg_offset; +char dbg_buffer[8096]; +#endif static int usx2y_set_input_monitor_mask (jack_hardware_t *hw, unsigned long mask) { @@ -120,7 +125,7 @@ usx2y_driver_get_channel_addresses_playback (alsa_driver_t *driver, if (dbg_offset < (sizeof(dbg_buffer) - 256)) dbg_offset += sprintf(dbg_buffer + dbg_offset, "avail %li@%p\n", *playback_avail, driver->playback_addr[0]); else { - jack_error(dbg_buffer); + printf(dbg_buffer); return -1; } #endif @@ -145,7 +150,7 @@ usx2y_driver_get_channel_addresses_capture (alsa_driver_t *driver, return 0; /* FIXME: return -1; */ h->capture_iso_bytes_done = 0; #ifdef DBGHWDEP - dbg_offset = sprintf(dbg_buffer, "first iso = %i %i@%p:%i\n", + dbg_offset = sprintf(dbg_buffer, "cfirst iso = %i %i@%p:%i\n", iso, h->hwdep_pcm_shm->captured_iso[iso].length, h->hwdep_pcm_shm->capture0x8, h->hwdep_pcm_shm->captured_iso[iso].offset); @@ -154,7 +159,7 @@ usx2y_driver_get_channel_addresses_capture (alsa_driver_t *driver, iso = h->capture_iso_start; } #ifdef DBGHWDEP - dbg_offset += sprintf(dbg_buffer + dbg_offset, "iso = %i(%i;%i); ", iso, + dbg_offset += sprintf(dbg_buffer + dbg_offset, "ciso = %i(%i;%i); ", iso, h->hwdep_pcm_shm->captured_iso[iso].offset, h->hwdep_pcm_shm->captured_iso[iso].frame); #endif @@ -180,10 +185,21 @@ usx2y_driver_get_channel_addresses_capture (alsa_driver_t *driver, ((chn & 1) ? driver->capture_sample_bytes : 0); } #ifdef DBGHWDEP + { + int f = 0; + unsigned *u = driver->capture_addr[0]; + static unsigned last; + dbg_offset += sprintf(dbg_buffer + dbg_offset, "\nvon %6u bis %6u\n", last, u[0]); + while (f < *capture_avail && dbg_offset < (sizeof(dbg_buffer) - 256)) { + if (u[f] != last + 1) + dbg_offset += sprintf(dbg_buffer + dbg_offset, "\nooops %6u %6u\n", last, u[f]); + last = u[f++]; + } + } if (dbg_offset < (sizeof(dbg_buffer) - 256)) dbg_offset += sprintf(dbg_buffer + dbg_offset, "avail %li@%p\n", *capture_avail, driver->capture_addr[0]); else { - jack_error(dbg_buffer); + printf(dbg_buffer); return -1; } #endif @@ -199,6 +215,12 @@ usx2y_driver_start (alsa_driver_t *driver) usx2y_t *h = (usx2y_t *) driver->hw->private; + if (driver->capture_nchannels == 4) { + // US428 channels 3+4 are on a seperate 2 channel stream. + // ALSA thinks its 1 stream with 4 channels, so we have to hack here. + driver->capture_interleave_skip = 2 * driver->capture_sample_bytes; + } + driver->poll_last = 0; driver->poll_next = 0; @@ -445,9 +467,9 @@ usx2y_driver_null_cycle (alsa_driver_t* driver, jack_nframes_t nframes) static int usx2y_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) { - snd_pcm_sframes_t contiguous; + snd_pcm_uframes_t contiguous; snd_pcm_sframes_t nread; - snd_pcm_sframes_t offset; + snd_pcm_uframes_t offset; jack_default_audio_sample_t* buf[4]; channel_t chn; JSList *node; @@ -460,61 +482,55 @@ usx2y_driver_read (alsa_driver_t *driver, jack_nframes_t nframes) } nread = 0; - contiguous = 0; - while (nframes) { + if (snd_pcm_mmap_begin (driver->capture_handle, + &driver->capture_areas, + &offset, &nframes_) < 0) { + jack_error ("ALSA/USX2Y: %s: mmap areas info error", + driver->alsa_name_capture); + return -1; + } - contiguous = (nframes > driver->frames_per_cycle) ? - driver->frames_per_cycle : nframes; + for (chn = 0, node = driver->capture_ports; + node; node = jack_slist_next (node), chn++) { + port = (jack_port_t *) node->data; + if (!jack_port_connected (port)) { + continue; + } + buf[chn] = jack_port_get_buffer (port, nframes_); + } - if (snd_pcm_mmap_begin ( - driver->capture_handle, &driver->capture_areas, - (snd_pcm_uframes_t *) &offset, - (snd_pcm_uframes_t *) &nframes_) < 0) { - jack_error ("ALSA/USX2Y: %s: mmap areas info error", - driver->alsa_name_capture); + while (nframes) { + + contiguous = nframes; + if (usx2y_driver_get_channel_addresses_capture ( + driver, &contiguous) < 0) { return -1; } - for (chn = 0, node = driver->capture_ports; - node && chn < 4; - node = jack_slist_next (node), chn++) { + node; node = jack_slist_next (node), chn++) { port = (jack_port_t *) node->data; if (!jack_port_connected (port)) { + /* no-copy optimization */ continue; } - buf[chn] = jack_port_get_buffer (port, nframes_); - } - - while (nframes) { - contiguous = nframes; - if (usx2y_driver_get_channel_addresses_capture ( - driver, &contiguous) < 0) { - return -1; - } - for (chn = 0, node = driver->capture_ports; - node && chn < 4; - node = jack_slist_next (node), chn++) { - port = (jack_port_t *) node->data; - if (!jack_port_connected (port)) { - /* no-copy optimization */ - continue; - } - alsa_driver_read_from_channel (driver, chn, - buf[chn] + nread, contiguous); - } - nread += contiguous; - nframes -= contiguous; - } - - if ((err = snd_pcm_mmap_commit (driver->capture_handle, - offset, nframes_)) < 0) { - jack_error ("ALSA/USX2Y: could not complete read of %" - PRIu32 " frames: error = %d", nframes_, err); - return -1; + alsa_driver_read_from_channel (driver, chn, + buf[chn] + nread, + contiguous); +/* sample_move_dS_s24(buf[chn] + nread, */ +/* driver->capture_addr[chn], */ +/* contiguous, */ +/* driver->capture_interleave_skip); */ } + nread += contiguous; + nframes -= contiguous; + } -// nframes -= contiguous; + if ((err = snd_pcm_mmap_commit (driver->capture_handle, + offset, nframes_)) < 0) { + jack_error ("ALSA/USX2Y: could not complete read of %" + PRIu32 " frames: error = %d", nframes_, err); + return -1; } return 0; @@ -527,11 +543,10 @@ usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) JSList *node; jack_default_audio_sample_t* buf[2]; snd_pcm_sframes_t nwritten; - snd_pcm_sframes_t contiguous; - snd_pcm_sframes_t offset; + snd_pcm_uframes_t contiguous; + snd_pcm_uframes_t offset; jack_port_t *port; int err; - int dbg_loops = 1; snd_pcm_uframes_t nframes_ = nframes; driver->process_count++; @@ -541,7 +556,6 @@ usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) } nwritten = 0; - contiguous = 0; /* check current input monitor request status */ @@ -563,83 +577,45 @@ usx2y_driver_write (alsa_driver_t* driver, jack_nframes_t nframes) } } - while (nframes) { + if (snd_pcm_mmap_begin(driver->playback_handle, + &driver->playback_areas, + &offset, &nframes_) < 0) { + jack_error ("ALSA/USX2Y: %s: mmap areas info error", + driver->alsa_name_capture); + return -1; + } - if (--dbg_loops) - return dbg_loops; + for (chn = 0, node = driver->playback_ports; + node; node = jack_slist_next (node), chn++) { + port = (jack_port_t *) node->data; + buf[chn] = jack_port_get_buffer (port, nframes_); + } - contiguous = (nframes > driver->frames_per_cycle) ? - driver->frames_per_cycle : nframes; + while (nframes) { - if (snd_pcm_mmap_begin( - driver->playback_handle, &driver->playback_areas, - &offset, &nframes_) < 0) { - jack_error ("ALSA/USX2Y: %s: mmap areas info error", - driver->alsa_name_capture); + contiguous = nframes; + if (usx2y_driver_get_channel_addresses_playback ( + driver, &contiguous) < 0) { return -1; } - for (chn = 0, node = driver->playback_ports; - node && chn < 2; - node = jack_slist_next (node), chn++) { + node; node = jack_slist_next (node), chn++) { port = (jack_port_t *) node->data; - if (!jack_port_connected (port)) { - continue; - } - buf[chn] = jack_port_get_buffer (port, nframes_); - } - - while (nframes) { - contiguous = nframes; - if (usx2y_driver_get_channel_addresses_playback ( - driver, &contiguous) < 0) { - return -1; - } - for (chn = 0, node = driver->playback_ports; - node && chn < 2; - node = jack_slist_next (node), chn++) { - port = (jack_port_t *) node->data; - if (!jack_port_connected (port)) { - continue; - } - alsa_driver_write_to_channel (driver, chn, - buf[chn] + nwritten, - contiguous); - } - nwritten += contiguous; - if (driver->channels_not_done) { - alsa_driver_silence_untouched_channels (driver, - contiguous); - } - nframes -= contiguous; - } - - if ((err = snd_pcm_mmap_commit (driver->playback_handle, - offset, nframes_)) < 0) { - jack_error ("ALSA/USX2Y: could not complete playback of %" - PRIu32 " frames: error = %d", nframes_, err); - if (err != EPIPE && err != ESTRPIPE) - return -1; + alsa_driver_write_to_channel (driver, chn, + buf[chn] + nwritten, + contiguous); } -// nframes -= contiguous; + nwritten += contiguous; + nframes -= contiguous; } -/* { */ -/* usx2y_t *h = (usx2y_t *) driver->hw->private; */ -/* unsigned *pu = (unsigned *)h->hwdep_pcm_shm->playback; */ -/* int i = sizeof(h->hwdep_pcm_shm->playback) / sizeof(*pu); */ - -/* while (i) { */ -/* if (*(pu)) { */ -/* jack_error("%p;error %u(=0x%X)@%p", */ -/* h->hwdep_pcm_shm->playback, */ -/* *pu, *pu, pu); */ -/* return -1; */ -/* } */ -/* --i; */ -/* ++pu; */ -/* } */ -/* } */ + if ((err = snd_pcm_mmap_commit (driver->playback_handle, + offset, nframes_)) < 0) { + jack_error ("ALSA/USX2Y: could not complete playback of %" + PRIu32 " frames: error = %d", nframes_, err); + if (err != EPIPE && err != ESTRPIPE) + return -1; + } return 0; } diff --git a/linux/alsa/usx2y.h b/linux/alsa/usx2y.h index 9fa7594e..f34b9f13 100644 --- a/linux/alsa/usx2y.h +++ b/linux/alsa/usx2y.h @@ -1,22 +1,22 @@ /* - Copyright (C) 2001 Paul Davis - Copyright (C) 2004 Karsten Wiese, Rui Nuno Capela - - 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., 675 Mass Ave, Cambridge, MA 02139, USA. - - $Id: usx2y.h,v 1.2 2005/11/23 11:24:29 letz Exp $ + Copyright (C) 2001 Paul Davis + Copyright (C) 2004 Karsten Wiese, Rui Nuno Capela + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: usx2y.h 855 2004-12-28 05:50:18Z joq $ */ #ifndef __jack_usx2y_h__ @@ -28,38 +28,33 @@ #define USX2Y_SSS (((USX2Y_MAXPACK * USX2Y_MAXBUFFERMS * USX2Y_MAXSTRIDE + 4096) / 4096) * 4096) -struct snd_usX2Y_hwdep_pcm_shm -{ - char playback[USX2Y_SSS]; - char capture0x8[USX2Y_SSS]; - char capture0xA[USX2Y_SSS]; - volatile int playback_iso_head; - int playback_iso_start; - struct - { - int frame, - offset, - length; - } - captured_iso[128]; - volatile int captured_iso_head; - volatile unsigned captured_iso_frames; - int capture_iso_start; +struct snd_usX2Y_hwdep_pcm_shm { + char playback[USX2Y_SSS]; + char capture0x8[USX2Y_SSS]; + char capture0xA[USX2Y_SSS]; + volatile int playback_iso_head; + int playback_iso_start; + struct { + int frame, + offset, + length; + } captured_iso[128]; + volatile int captured_iso_head; + volatile unsigned captured_iso_frames; + int capture_iso_start; }; typedef struct snd_usX2Y_hwdep_pcm_shm snd_usX2Y_hwdep_pcm_shm_t; -typedef struct -{ - alsa_driver_t *driver; - snd_hwdep_t *hwdep_handle; - struct pollfd pfds; - struct snd_usX2Y_hwdep_pcm_shm *hwdep_pcm_shm; - int playback_iso_start; - int playback_iso_bytes_done; - int capture_iso_start; - int capture_iso_bytes_done; -} -usx2y_t; +typedef struct { + alsa_driver_t *driver; + snd_hwdep_t *hwdep_handle; + struct pollfd pfds; + struct snd_usX2Y_hwdep_pcm_shm *hwdep_pcm_shm; + int playback_iso_start; + int playback_iso_bytes_done; + int capture_iso_start; + int capture_iso_bytes_done; +} usx2y_t; jack_hardware_t * jack_alsa_usx2y_hw_new (alsa_driver_t *driver); diff --git a/macosx/Jackdmp.xcode/project.pbxproj b/macosx/Jackdmp.xcode/project.pbxproj index 5e29da75..d5098f9f 100644 --- a/macosx/Jackdmp.xcode/project.pbxproj +++ b/macosx/Jackdmp.xcode/project.pbxproj @@ -1009,7 +1009,6 @@ 4BF8D1CE0834EF2200C94B91, 4BF8D1D60834EF2F00C94B91, 4BF8D1E80834EF6700C94B91, - 4BF8D1EC0834EF7500C94B91, 4BF8D2050834EFD100C94B91, 4BF8D2060834EFD100C94B91, 4BF8D2350834F14400C94B91, @@ -1028,6 +1027,8 @@ 4B003AB408E2B2BA0060EFDC, 4B98AE040931D30C0091932A, 4B1880CB09A1DDF100154099, + 4BCD4CF50B00A0F90091F8E8, + 4BCD4CF90B00A15B0091F8E8, ); isa = PBXSourcesBuildPhase; runOnlyForDeploymentPostprocessing = 0; @@ -2079,6 +2080,7 @@ }; 4BA550F905E241D900569492 = { children = ( + 4BCD4CF40B00A0F90091F8E8, 4B168CA4076A5333005B2802, 4BF8D1FB0834EFD100C94B91, 4BF8D1FC0834EFD100C94B91, @@ -2661,6 +2663,27 @@ refType = 2; sourceTree = SOURCE_ROOT; }; + 4BCD4CF40B00A0F90091F8E8 = { + fileEncoding = 30; + isa = PBXFileReference; + lastKnownFileType = sourcecode.cpp.cpp; + name = JackAPIWrapper.cpp; + path = ../common/JackAPIWrapper.cpp; + refType = 2; + sourceTree = SOURCE_ROOT; + }; + 4BCD4CF50B00A0F90091F8E8 = { + fileRef = 4BCD4CF40B00A0F90091F8E8; + isa = PBXBuildFile; + settings = { + }; + }; + 4BCD4CF90B00A15B0091F8E8 = { + fileRef = 4BF8D1E90834EF7500C94B91; + isa = PBXBuildFile; + settings = { + }; + }; 4BD561C708EEB910006BBC2A = { fileEncoding = 30; isa = PBXFileReference; @@ -4557,12 +4580,6 @@ settings = { }; }; - 4BF8D1EC0834EF7500C94B91 = { - fileRef = 4BF8D1E90834EF7500C94B91; - isa = PBXBuildFile; - settings = { - }; - }; 4BF8D1ED0834EF9200C94B91 = { fileEncoding = 30; isa = PBXFileReference;