Hello Yoshiki,
I fixed this problem. The reason of this issue was the delay buffer was overflowed if under run happened repeatedly. I tested it on my machine. Please test it again.
Thank you, - Takashi
Yoshiki Ohshima wrote:
Takashi,
The attached vm-sound-ALSA does shorten the delay when I play sound from PianoKeyboard, but for a longer sound, it doesn't work as expected. The buffer underrun seems to be happening a lot, and also I might guess that the index to fill the buffer may be wrong.
Now you have one, try
SampledSound stereoBachFugue play
Index: platforms/unix/vm-sound-ALSA/sqUnixSoundALSA.c =================================================================== --- platforms/unix/vm-sound-ALSA/sqUnixSoundALSA.c (revision 1594) +++ platforms/unix/vm-sound-ALSA/sqUnixSoundALSA.c (working copy) @@ -56,6 +56,8 @@ static void sigio_save(void); static void sigio_restore(void);
+#define MIN(x,y) ((x) < (y)) ? (x) : (y) +#define MAX(x,y) ((x) > (y)) ? (x) : (y)
/* output */
@@ -67,8 +69,10 @@ static snd_async_handler_t *output_handler= 0; static int output_semaphore= 0; static int output_channels= 0; -static int output_buffer_frames_size= 0; static int output_buffer_frames_available= 0; +static snd_pcm_uframes_t output_buffer_period_size= 0; +static snd_pcm_uframes_t output_buffer_size= 0; +static double max_delay_frames= 0;
static void output_callback(snd_async_handler_t *handler) { @@ -92,7 +96,6 @@ int err; snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; - snd_pcm_uframes_t frames; unsigned int uval; int dir;
@@ -109,8 +112,8 @@ snd_pcm_hw_params_set_channels(output_handle, hwparams, output_channels); uval= samplesPerSec; snd_pcm_hw_params_set_rate_near(output_handle, hwparams, &uval, &dir); - frames= frameCount; - snd_pcm_hw_params_set_period_size_near(output_handle, hwparams, &frames, &dir); + output_buffer_period_size= frameCount; + snd_pcm_hw_params_set_period_size_near(output_handle, hwparams, &output_buffer_period_size, &dir); snd(pcm_hw_params(output_handle, hwparams), "sound_Start: snd_pcm_hw_params");
snd_pcm_sw_params_alloca(&swparams); @@ -120,8 +123,9 @@ snd(pcm_sw_params_set_xfer_align(output_handle, swparams, 1), "sound_Start: snd_pcm_sw_params_set_xfer_align"); snd(pcm_sw_params(output_handle, swparams), "sound_Start: snd_pcm_sw_params");
- output_buffer_frames_size= frameCount; + snd(pcm_hw_params_get_buffer_size(hwparams, &output_buffer_size), "sound_Start: pcm_hw_params_get_buffer_size"); output_buffer_frames_available= 1; + max_delay_frames= output_buffer_period_size * 2; /* set initial delay frames */
snd(pcm_nonblock(output_handle, 1), "sound_Start: snd_pcm_nonblock"); snd(async_add_pcm_handler(&output_handler, output_handle, output_callback, 0), "soundStart: snd_add_pcm_handler"); @@ -152,17 +156,34 @@ return 1; }
+/* Answers periods frame size, or zero if the delay is over. */ + static sqInt sound_AvailableSpace(void) { - if (output_handle) - { - int count = snd_pcm_avail_update(output_handle); - if (count >= 0) - return count; - fprintf(stderr, "sound_AvailableSpace: snd_pcm_avail_update: %s\n", snd_strerror(count)); - snd_pcm_prepare(output_handle); - } - return 0; + snd_pcm_sframes_t delay; /* distance to playback point (in frames) */ + snd_pcm_state_t state; /* current state of the stream */ + sqInt avail= 0; /* available space for the answer (in bytes) */ + + if (!output_handle) return 0; + + snd_pcm_delay(output_handle, &delay); + state= snd_pcm_state (output_handle); + + /* if underrun causes, max delay is loosened */ + if (state == SND_PCM_STATE_XRUN) { + max_delay_frames= + MIN(max_delay_frames * 1.5, output_buffer_size - output_buffer_period_size); + } + + /* if the state is not running, new sound is needed bacause nobody can + signal the semaphore. */ + if (delay <= max_delay_frames || state != SND_PCM_STATE_RUNNING) { + avail= output_buffer_period_size; + max_delay_frames= MAX(max_delay_frames * 0.9995, output_buffer_period_size); + } + fprintf(stderr, "delay=%i, ans_avail=%i, state=%i, real_delay=%.1fms\n", + (int) delay, avail, state, 1000 * max_delay_frames / 22050); + return avail * output_channels * 2; /* bytes */ }
static sqInt sound_InsertSamplesFromLeadTime(sqInt frameCount, sqInt srcBufPtr, sqInt samplesOfLeadTime) FAIL(frameCount) @@ -231,7 +252,6 @@ snd_pcm_hw_params_t *hwparams; snd_pcm_sw_params_t *swparams; snd_pcm_uframes_t frames; - unsigned int uval; int dir;
if (input_handle) sound_StopRecording(); @@ -261,6 +281,7 @@ snd(pcm_nonblock(input_handle, 1), "sound_StartRecording: snd_pcm_nonblock"); snd(async_add_pcm_handler(&input_handler, input_handle, input_callback, 0), "sound_StartRecording: snd_add_pcm_handler"); snd(pcm_start(input_handle), "sound_StartRecording: snd_pcm_start"); + return 1; }
static double sound_GetRecordingSampleRate(void)