[Etoys] Patch to fix sound delay issue
Takashi Yamamiya
tak at metatoys.org
Fri Dec 8 09:14:28 EST 2006
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
-------------- next part --------------
A non-text attachment was scrubbed...
Name: vm-sound-ALSA.gz
Type: application/gzip
Size: 12575 bytes
Desc: not available
Url : http://mailman.laptop.org/pipermail/etoys/attachments/20061208/862a3ee6/vm-sound-ALSA.bin
-------------- next part --------------
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)
More information about the Etoys
mailing list