audio: replace shift in audio_pcm_info with bytes_per_frame

The bit shifting trick worked because the number of bytes per frame was
always a power-of-two (since QEMU only supports mono, stereo and 8, 16
and 32 bit samples).  But if we want to add support for surround sound,
this no longer holds true.

Signed-off-by: Kővágó, Zoltán <DirtY.iCE.hu@gmail.com>
Message-id: 1351fd9bcce0ff20d81850c5292722194329de02.1570996490.git.DirtY.iCE.hu@gmail.com
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This commit is contained in:
Kővágó, Zoltán 2019-10-13 21:58:02 +02:00 committed by Gerd Hoffmann
parent cecc1e79bf
commit 2b9cce8c8c
10 changed files with 66 additions and 65 deletions

View File

@ -602,7 +602,7 @@ static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
{ {
ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw; ALSAVoiceOut *alsa = (ALSAVoiceOut *) hw;
size_t pos = 0; size_t pos = 0;
size_t len_frames = len >> hw->info.shift; size_t len_frames = len / hw->info.bytes_per_frame;
while (len_frames) { while (len_frames) {
char *src = advance(buf, pos); char *src = advance(buf, pos);
@ -648,7 +648,7 @@ static size_t alsa_write(HWVoiceOut *hw, void *buf, size_t len)
} }
} }
pos += written << hw->info.shift; pos += written * hw->info.bytes_per_frame;
if (written < len_frames) { if (written < len_frames) {
break; break;
} }
@ -802,7 +802,8 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len)
void *dst = advance(buf, pos); void *dst = advance(buf, pos);
snd_pcm_sframes_t nread; snd_pcm_sframes_t nread;
nread = snd_pcm_readi(alsa->handle, dst, len >> hw->info.shift); nread = snd_pcm_readi(
alsa->handle, dst, len / hw->info.bytes_per_frame);
if (nread <= 0) { if (nread <= 0) {
switch (nread) { switch (nread) {
@ -828,8 +829,8 @@ static size_t alsa_read(HWVoiceIn *hw, void *buf, size_t len)
} }
} }
pos += nread << hw->info.shift; pos += nread * hw->info.bytes_per_frame;
len -= nread << hw->info.shift; len -= nread * hw->info.bytes_per_frame;
} }
return pos; return pos;

View File

@ -299,12 +299,13 @@ static int audio_pcm_info_eq (struct audio_pcm_info *info, struct audsettings *a
void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as) void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
{ {
int bits = 8, sign = 0, shift = 0; int bits = 8, sign = 0, mul;
switch (as->fmt) { switch (as->fmt) {
case AUDIO_FORMAT_S8: case AUDIO_FORMAT_S8:
sign = 1; sign = 1;
case AUDIO_FORMAT_U8: case AUDIO_FORMAT_U8:
mul = 1;
break; break;
case AUDIO_FORMAT_S16: case AUDIO_FORMAT_S16:
@ -312,7 +313,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
/* fall through */ /* fall through */
case AUDIO_FORMAT_U16: case AUDIO_FORMAT_U16:
bits = 16; bits = 16;
shift = 1; mul = 2;
break; break;
case AUDIO_FORMAT_S32: case AUDIO_FORMAT_S32:
@ -320,7 +321,7 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
/* fall through */ /* fall through */
case AUDIO_FORMAT_U32: case AUDIO_FORMAT_U32:
bits = 32; bits = 32;
shift = 2; mul = 4;
break; break;
default: default:
@ -331,9 +332,8 @@ void audio_pcm_init_info (struct audio_pcm_info *info, struct audsettings *as)
info->bits = bits; info->bits = bits;
info->sign = sign; info->sign = sign;
info->nchannels = as->nchannels; info->nchannels = as->nchannels;
info->shift = (as->nchannels == 2) + shift; info->bytes_per_frame = as->nchannels * mul;
info->align = (1 << info->shift) - 1; info->bytes_per_second = info->freq * info->bytes_per_frame;
info->bytes_per_second = info->freq << info->shift;
info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS); info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
} }
@ -344,26 +344,25 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
} }
if (info->sign) { if (info->sign) {
memset (buf, 0x00, len << info->shift); memset(buf, 0x00, len * info->bytes_per_frame);
} }
else { else {
switch (info->bits) { switch (info->bits) {
case 8: case 8:
memset (buf, 0x80, len << info->shift); memset(buf, 0x80, len * info->bytes_per_frame);
break; break;
case 16: case 16:
{ {
int i; int i;
uint16_t *p = buf; uint16_t *p = buf;
int shift = info->nchannels - 1;
short s = INT16_MAX; short s = INT16_MAX;
if (info->swap_endianness) { if (info->swap_endianness) {
s = bswap16 (s); s = bswap16 (s);
} }
for (i = 0; i < len << shift; i++) { for (i = 0; i < len * info->nchannels; i++) {
p[i] = s; p[i] = s;
} }
} }
@ -373,14 +372,13 @@ void audio_pcm_info_clear_buf (struct audio_pcm_info *info, void *buf, int len)
{ {
int i; int i;
uint32_t *p = buf; uint32_t *p = buf;
int shift = info->nchannels - 1;
int32_t s = INT32_MAX; int32_t s = INT32_MAX;
if (info->swap_endianness) { if (info->swap_endianness) {
s = bswap32 (s); s = bswap32 (s);
} }
for (i = 0; i < len << shift; i++) { for (i = 0; i < len * info->nchannels; i++) {
p[i] = s; p[i] = s;
} }
} }
@ -558,7 +556,7 @@ static void audio_pcm_hw_clip_out(HWVoiceOut *hw, void *pcm_buf, size_t len)
while (len) { while (len) {
st_sample *src = hw->mix_buf->samples + pos; st_sample *src = hw->mix_buf->samples + pos;
uint8_t *dst = advance(pcm_buf, clipped << hw->info.shift); uint8_t *dst = advance(pcm_buf, clipped * hw->info.bytes_per_frame);
size_t samples_till_end_of_buf = hw->mix_buf->size - pos; size_t samples_till_end_of_buf = hw->mix_buf->size - pos;
size_t samples_to_clip = MIN(len, samples_till_end_of_buf); size_t samples_to_clip = MIN(len, samples_till_end_of_buf);
@ -607,7 +605,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
return 0; return 0;
} }
samples = size >> sw->info.shift; samples = size / sw->info.bytes_per_frame;
if (!live) { if (!live) {
return 0; return 0;
} }
@ -642,7 +640,7 @@ static size_t audio_pcm_sw_read(SWVoiceIn *sw, void *buf, size_t size)
sw->clip (buf, sw->buf, ret); sw->clip (buf, sw->buf, ret);
sw->total_hw_samples_acquired += total; sw->total_hw_samples_acquired += total;
return ret << sw->info.shift; return ret * sw->info.bytes_per_frame;
} }
/* /*
@ -715,7 +713,7 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
} }
wpos = (sw->hw->mix_buf->pos + live) % hwsamples; wpos = (sw->hw->mix_buf->pos + live) % hwsamples;
samples = size >> sw->info.shift; samples = size / sw->info.bytes_per_frame;
dead = hwsamples - live; dead = hwsamples - live;
swlim = ((int64_t) dead << 32) / sw->ratio; swlim = ((int64_t) dead << 32) / sw->ratio;
@ -759,13 +757,13 @@ static size_t audio_pcm_sw_write(SWVoiceOut *sw, void *buf, size_t size)
dolog ( dolog (
"%s: write size %zu ret %zu total sw %zu\n", "%s: write size %zu ret %zu total sw %zu\n",
SW_NAME (sw), SW_NAME (sw),
size >> sw->info.shift, size / sw->info.bytes_per_frame,
ret, ret,
sw->total_hw_samples_mixed sw->total_hw_samples_mixed
); );
#endif #endif
return ret << sw->info.shift; return ret * sw->info.bytes_per_frame;
} }
#ifdef DEBUG_AUDIO #ifdef DEBUG_AUDIO
@ -882,7 +880,7 @@ size_t AUD_read(SWVoiceIn *sw, void *buf, size_t size)
int AUD_get_buffer_size_out (SWVoiceOut *sw) int AUD_get_buffer_size_out (SWVoiceOut *sw)
{ {
return sw->hw->mix_buf->size << sw->hw->info.shift; return sw->hw->mix_buf->size * sw->hw->info.bytes_per_frame;
} }
void AUD_set_active_out (SWVoiceOut *sw, int on) void AUD_set_active_out (SWVoiceOut *sw, int on)
@ -998,10 +996,10 @@ static size_t audio_get_avail (SWVoiceIn *sw)
ldebug ( ldebug (
"%s: get_avail live %d ret %" PRId64 "\n", "%s: get_avail live %d ret %" PRId64 "\n",
SW_NAME (sw), SW_NAME (sw),
live, (((int64_t) live << 32) / sw->ratio) << sw->info.shift live, (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame
); );
return (((int64_t) live << 32) / sw->ratio) << sw->info.shift; return (((int64_t) live << 32) / sw->ratio) * sw->info.bytes_per_frame;
} }
static size_t audio_get_free(SWVoiceOut *sw) static size_t audio_get_free(SWVoiceOut *sw)
@ -1025,10 +1023,11 @@ static size_t audio_get_free(SWVoiceOut *sw)
#ifdef DEBUG_OUT #ifdef DEBUG_OUT
dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n", dolog ("%s: get_free live %d dead %d ret %" PRId64 "\n",
SW_NAME (sw), SW_NAME (sw),
live, dead, (((int64_t) dead << 32) / sw->ratio) << sw->info.shift); live, dead, (((int64_t) dead << 32) / sw->ratio) *
sw->info.bytes_per_frame);
#endif #endif
return (((int64_t) dead << 32) / sw->ratio) << sw->info.shift; return (((int64_t) dead << 32) / sw->ratio) * sw->info.bytes_per_frame;
} }
static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos, static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
@ -1047,7 +1046,7 @@ static void audio_capture_mix_and_clear(HWVoiceOut *hw, size_t rpos,
while (n) { while (n) {
size_t till_end_of_hw = hw->mix_buf->size - rpos2; size_t till_end_of_hw = hw->mix_buf->size - rpos2;
size_t to_write = MIN(till_end_of_hw, n); size_t to_write = MIN(till_end_of_hw, n);
size_t bytes = to_write << hw->info.shift; size_t bytes = to_write * hw->info.bytes_per_frame;
size_t written; size_t written;
sw->buf = hw->mix_buf->samples + rpos2; sw->buf = hw->mix_buf->samples + rpos2;
@ -1082,10 +1081,11 @@ static size_t audio_pcm_hw_run_out(HWVoiceOut *hw, size_t live)
return clipped + live; return clipped + live;
} }
decr = MIN(size >> hw->info.shift, live); decr = MIN(size / hw->info.bytes_per_frame, live);
audio_pcm_hw_clip_out(hw, buf, decr); audio_pcm_hw_clip_out(hw, buf, decr);
proc = hw->pcm_ops->put_buffer_out(hw, buf, decr << hw->info.shift) >> proc = hw->pcm_ops->put_buffer_out(hw, buf,
hw->info.shift; decr * hw->info.bytes_per_frame) /
hw->info.bytes_per_frame;
live -= proc; live -= proc;
clipped += proc; clipped += proc;
@ -1234,16 +1234,16 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
while (samples) { while (samples) {
size_t proc; size_t proc;
size_t size = samples << hw->info.shift; size_t size = samples * hw->info.bytes_per_frame;
void *buf = hw->pcm_ops->get_buffer_in(hw, &size); void *buf = hw->pcm_ops->get_buffer_in(hw, &size);
assert((size & hw->info.align) == 0); assert(size % hw->info.bytes_per_frame == 0);
if (size == 0) { if (size == 0) {
hw->pcm_ops->put_buffer_in(hw, buf, size); hw->pcm_ops->put_buffer_in(hw, buf, size);
break; break;
} }
proc = MIN(size >> hw->info.shift, proc = MIN(size / hw->info.bytes_per_frame,
conv_buf->size - conv_buf->pos); conv_buf->size - conv_buf->pos);
hw->conv(conv_buf->samples + conv_buf->pos, buf, proc); hw->conv(conv_buf->samples + conv_buf->pos, buf, proc);
@ -1251,7 +1251,7 @@ static size_t audio_pcm_hw_run_in(HWVoiceIn *hw, size_t samples)
samples -= proc; samples -= proc;
conv += proc; conv += proc;
hw->pcm_ops->put_buffer_in(hw, buf, proc << hw->info.shift); hw->pcm_ops->put_buffer_in(hw, buf, proc * hw->info.bytes_per_frame);
} }
return conv; return conv;
@ -1325,7 +1325,7 @@ static void audio_run_capture (AudioState *s)
for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) { for (cb = cap->cb_head.lh_first; cb; cb = cb->entries.le_next) {
cb->ops.capture (cb->opaque, cap->buf, cb->ops.capture (cb->opaque, cap->buf,
to_capture << hw->info.shift); to_capture * hw->info.bytes_per_frame);
} }
rpos = (rpos + to_capture) % hw->mix_buf->size; rpos = (rpos + to_capture) % hw->mix_buf->size;
live -= to_capture; live -= to_capture;
@ -1378,7 +1378,7 @@ void *audio_generic_get_buffer_in(HWVoiceIn *hw, size_t *size)
ssize_t start; ssize_t start;
if (unlikely(!hw->buf_emul)) { if (unlikely(!hw->buf_emul)) {
size_t calc_size = hw->conv_buf->size << hw->info.shift; size_t calc_size = hw->conv_buf->size * hw->info.bytes_per_frame;
hw->buf_emul = g_malloc(calc_size); hw->buf_emul = g_malloc(calc_size);
hw->size_emul = calc_size; hw->size_emul = calc_size;
hw->pos_emul = hw->pending_emul = 0; hw->pos_emul = hw->pending_emul = 0;
@ -1414,7 +1414,7 @@ void audio_generic_put_buffer_in(HWVoiceIn *hw, void *buf, size_t size)
void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size) void *audio_generic_get_buffer_out(HWVoiceOut *hw, size_t *size)
{ {
if (unlikely(!hw->buf_emul)) { if (unlikely(!hw->buf_emul)) {
size_t calc_size = hw->mix_buf->size << hw->info.shift; size_t calc_size = hw->mix_buf->size * hw->info.bytes_per_frame;
hw->buf_emul = g_malloc(calc_size); hw->buf_emul = g_malloc(calc_size);
hw->size_emul = calc_size; hw->size_emul = calc_size;
@ -1833,7 +1833,7 @@ CaptureVoiceOut *AUD_add_capture(
audio_pcm_init_info (&hw->info, as); audio_pcm_init_info (&hw->info, as);
cap->buf = g_malloc0_n(hw->mix_buf->size, 1 << hw->info.shift); cap->buf = g_malloc0_n(hw->mix_buf->size, hw->info.bytes_per_frame);
hw->clip = mixeng_clip hw->clip = mixeng_clip
[hw->info.nchannels == 2] [hw->info.nchannels == 2]
@ -2153,14 +2153,14 @@ size_t audio_rate_get_bytes(struct audio_pcm_info *info, RateCtl *rate,
now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ticks = now - rate->start_ticks; ticks = now - rate->start_ticks;
bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND); bytes = muldiv64(ticks, info->bytes_per_second, NANOSECONDS_PER_SECOND);
samples = (bytes - rate->bytes_sent) >> info->shift; samples = (bytes - rate->bytes_sent) / info->bytes_per_frame;
if (samples < 0 || samples > 65536) { if (samples < 0 || samples > 65536) {
AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples); AUD_log(NULL, "Resetting rate control (%" PRId64 " samples)\n", samples);
audio_rate_start(rate); audio_rate_start(rate);
samples = 0; samples = 0;
} }
ret = MIN(samples << info->shift, bytes_avail); ret = MIN(samples * info->bytes_per_frame, bytes_avail);
rate->bytes_sent += ret; rate->bytes_sent += ret;
return ret; return ret;
} }

View File

@ -43,8 +43,7 @@ struct audio_pcm_info {
int sign; int sign;
int freq; int freq;
int nchannels; int nchannels;
int align; int bytes_per_frame;
int shift;
int bytes_per_second; int bytes_per_second;
int swap_endianness; int swap_endianness;
}; };

View File

@ -440,7 +440,7 @@ static OSStatus audioDeviceIOProc(
} }
frameCount = core->audioDevicePropertyBufferFrameSize; frameCount = core->audioDevicePropertyBufferFrameSize;
pending_frames = hw->pending_emul >> hw->info.shift; pending_frames = hw->pending_emul / hw->info.bytes_per_frame;
/* if there are not enough samples, set signal and return */ /* if there are not enough samples, set signal and return */
if (pending_frames < frameCount) { if (pending_frames < frameCount) {
@ -449,7 +449,7 @@ static OSStatus audioDeviceIOProc(
return 0; return 0;
} }
len = frameCount << hw->info.shift; len = frameCount * hw->info.bytes_per_frame;
while (len) { while (len) {
size_t write_len; size_t write_len;
ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul; ssize_t start = ((ssize_t) hw->pos_emul) - hw->pending_emul;

View File

@ -98,8 +98,8 @@ static int glue (dsound_lock_, TYPE) (
goto fail; goto fail;
} }
if ((p1p && *p1p && (*blen1p & info->align)) || if ((p1p && *p1p && (*blen1p % info->bytes_per_frame)) ||
(p2p && *p2p && (*blen2p & info->align))) { (p2p && *p2p && (*blen2p % info->bytes_per_frame))) {
dolog("DirectSound returned misaligned buffer %ld %ld\n", dolog("DirectSound returned misaligned buffer %ld %ld\n",
*blen1p, *blen2p); *blen1p, *blen2p);
glue(dsound_unlock_, TYPE)(buf, *p1p, p2p ? *p2p : NULL, *blen1p, glue(dsound_unlock_, TYPE)(buf, *p1p, p2p ? *p2p : NULL, *blen1p,
@ -247,14 +247,14 @@ static int dsound_init_out(HWVoiceOut *hw, struct audsettings *as,
obt_as.endianness = 0; obt_as.endianness = 0;
audio_pcm_init_info (&hw->info, &obt_as); audio_pcm_init_info (&hw->info, &obt_as);
if (bc.dwBufferBytes & hw->info.align) { if (bc.dwBufferBytes % hw->info.bytes_per_frame) {
dolog ( dolog (
"GetCaps returned misaligned buffer size %ld, alignment %d\n", "GetCaps returned misaligned buffer size %ld, alignment %d\n",
bc.dwBufferBytes, hw->info.align + 1 bc.dwBufferBytes, hw->info.bytes_per_frame
); );
} }
hw->size_emul = bc.dwBufferBytes; hw->size_emul = bc.dwBufferBytes;
hw->samples = bc.dwBufferBytes >> hw->info.shift; hw->samples = bc.dwBufferBytes / hw->info.bytes_per_frame;
ds->s = s; ds->s = s;
#ifdef DEBUG_DSOUND #ifdef DEBUG_DSOUND

View File

@ -320,8 +320,8 @@ static void dsound_clear_sample (HWVoiceOut *hw, LPDIRECTSOUNDBUFFER dsb,
return; return;
} }
len1 = blen1 >> hw->info.shift; len1 = blen1 / hw->info.bytes_per_frame;
len2 = blen2 >> hw->info.shift; len2 = blen2 / hw->info.bytes_per_frame;
#ifdef DEBUG_DSOUND #ifdef DEBUG_DSOUND
dolog ("clear %p,%ld,%ld %p,%ld,%ld\n", dolog ("clear %p,%ld,%ld %p,%ld,%ld\n",

View File

@ -91,7 +91,7 @@ static size_t no_read(HWVoiceIn *hw, void *buf, size_t size)
NoVoiceIn *no = (NoVoiceIn *) hw; NoVoiceIn *no = (NoVoiceIn *) hw;
int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size); int64_t bytes = audio_rate_get_bytes(&hw->info, &no->rate, size);
audio_pcm_info_clear_buf(&hw->info, buf, bytes >> hw->info.shift); audio_pcm_info_clear_buf(&hw->info, buf, bytes / hw->info.bytes_per_frame);
return bytes; return bytes;
} }

View File

@ -506,16 +506,16 @@ static int oss_init_out(HWVoiceOut *hw, struct audsettings *as,
oss->nfrags = obt.nfrags; oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize; oss->fragsize = obt.fragsize;
if (obt.nfrags * obt.fragsize & hw->info.align) { if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) {
dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n", dolog ("warning: Misaligned DAC buffer, size %d, alignment %d\n",
obt.nfrags * obt.fragsize, hw->info.align + 1); obt.nfrags * obt.fragsize, hw->info.bytes_per_frame);
} }
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame;
oss->mmapped = 0; oss->mmapped = 0;
if (oopts->has_try_mmap && oopts->try_mmap) { if (oopts->has_try_mmap && oopts->try_mmap) {
hw->size_emul = hw->samples << hw->info.shift; hw->size_emul = hw->samples * hw->info.bytes_per_frame;
hw->buf_emul = mmap( hw->buf_emul = mmap(
NULL, NULL,
hw->size_emul, hw->size_emul,
@ -644,12 +644,12 @@ static int oss_init_in(HWVoiceIn *hw, struct audsettings *as, void *drv_opaque)
oss->nfrags = obt.nfrags; oss->nfrags = obt.nfrags;
oss->fragsize = obt.fragsize; oss->fragsize = obt.fragsize;
if (obt.nfrags * obt.fragsize & hw->info.align) { if (obt.nfrags * obt.fragsize % hw->info.bytes_per_frame) {
dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n", dolog ("warning: Misaligned ADC buffer, size %d, alignment %d\n",
obt.nfrags * obt.fragsize, hw->info.align + 1); obt.nfrags * obt.fragsize, hw->info.bytes_per_frame);
} }
hw->samples = (obt.nfrags * obt.fragsize) >> hw->info.shift; hw->samples = (obt.nfrags * obt.fragsize) / hw->info.bytes_per_frame;
oss->fd = fd; oss->fd = fd;
oss->dev = dev; oss->dev = dev;

View File

@ -131,7 +131,8 @@ static void *line_out_get_buffer(HWVoiceOut *hw, size_t *size)
if (out->frame) { if (out->frame) {
*size = audio_rate_get_bytes( *size = audio_rate_get_bytes(
&hw->info, &out->rate, (out->fsize - out->fpos) << hw->info.shift); &hw->info, &out->rate,
(out->fsize - out->fpos) * hw->info.bytes_per_frame);
} else { } else {
audio_rate_start(&out->rate); audio_rate_start(&out->rate);
} }

View File

@ -43,14 +43,14 @@ static size_t wav_write_out(HWVoiceOut *hw, void *buf, size_t len)
{ {
WAVVoiceOut *wav = (WAVVoiceOut *) hw; WAVVoiceOut *wav = (WAVVoiceOut *) hw;
int64_t bytes = audio_rate_get_bytes(&hw->info, &wav->rate, len); int64_t bytes = audio_rate_get_bytes(&hw->info, &wav->rate, len);
assert(bytes >> hw->info.shift << hw->info.shift == bytes); assert(bytes % hw->info.bytes_per_frame == 0);
if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) { if (bytes && fwrite(buf, bytes, 1, wav->f) != 1) {
dolog("wav_write_out: fwrite of %" PRId64 " bytes failed\nReason: %s\n", dolog("wav_write_out: fwrite of %" PRId64 " bytes failed\nReason: %s\n",
bytes, strerror(errno)); bytes, strerror(errno));
} }
wav->total_samples += bytes >> hw->info.shift; wav->total_samples += bytes / hw->info.bytes_per_frame;
return bytes; return bytes;
} }
@ -134,7 +134,7 @@ static void wav_fini_out (HWVoiceOut *hw)
WAVVoiceOut *wav = (WAVVoiceOut *) hw; WAVVoiceOut *wav = (WAVVoiceOut *) hw;
uint8_t rlen[4]; uint8_t rlen[4];
uint8_t dlen[4]; uint8_t dlen[4];
uint32_t datalen = wav->total_samples << hw->info.shift; uint32_t datalen = wav->total_samples * hw->info.bytes_per_frame;
uint32_t rifflen = datalen + 36; uint32_t rifflen = datalen + 36;
if (!wav->f) { if (!wav->f) {