Apply volume before inserting into circular buffer

- Apply the volume specified with the audio data packet before
   inserting the audio data into the circular buffer.  Added functions
   for multiplying the volume with all the different audio bit depths.
   (Could probably be greatly optmimized later)
master
jp9000 2014-01-08 16:41:40 -07:00
parent aac09ca31a
commit f3dc5227e9
1 changed files with 110 additions and 5 deletions

View File

@ -27,6 +27,7 @@
struct audio_line {
struct audio_output *audio;
struct circlebuf buffer;
DARRAY(uint8_t) volume_buffer;
uint64_t base_timestamp;
uint64_t last_timestamp;
@ -38,12 +39,14 @@ struct audio_line {
static inline void audio_line_destroy_data(struct audio_line *line)
{
circlebuf_free(&line->buffer);
da_free(line->volume_buffer);
bfree(line);
}
struct audio_output {
struct audio_info info;
size_t block_size;
size_t channels;
media_t media;
media_output_t output;
@ -116,7 +119,8 @@ int audio_output_open(audio_t *audio, media_t media, struct audio_info *info)
memcpy(&out->info, info, sizeof(struct audio_info));
pthread_mutex_init_value(&out->line_mutex);
out->media = media;
out->block_size = get_audio_channels(info->speakers) *
out->channels = get_audio_channels(info->speakers);
out->block_size = out->channels *
get_audio_bytes_per_channel(info->format);
if (pthread_mutex_init(&out->line_mutex, NULL) != 0)
@ -198,19 +202,120 @@ static inline uint64_t convert_to_sample_offset(audio_t audio, uint64_t offset)
(1000000000.0 / (double)audio->info.samples_per_sec));
}
static inline void mul_vol_u8bit(struct audio_line *line, float volume,
size_t total_num)
{
uint8_t *vals = line->volume_buffer.array;
int16_t vol = (int16_t)(volume * 127.0f);
for (size_t i = 0; i < total_num; i++) {
int16_t val = (int16_t)(vals[i] ^ 0x80) << 8;
vals[i] = (uint8_t)((val * vol / 127) + 128);
}
}
static inline void mul_vol_16bit(struct audio_line *line, float volume,
size_t total_num)
{
uint16_t *vals = (uint16_t*)line->volume_buffer.array;
int32_t vol = (int32_t)(volume * 32767.0f);
for (size_t i = 0; i < total_num; i++)
vals[i] = (int32_t)((int32_t)vals[i] * vol / 32767);
}
static inline float conv_24bit_to_float(uint8_t *vals)
{
int32_t val = ((int32_t)vals[0]) |
((int32_t)vals[1] << 8) |
((int32_t)vals[2] << 16);
if ((val & 0x800000) != 0)
val |= 0xFF000000;
return (float)val / 8388607.0f;
}
static inline void conv_float_to_24bit(float fval, uint8_t *vals)
{
int32_t val = (int32_t)(fval * 8388607.0f);
vals[0] = (val) & 0xFF;
vals[1] = (val >> 8) & 0xFF;
vals[2] = (val >> 16) & 0xFF;
}
static inline void mul_vol_24bit(struct audio_line *line, float volume,
size_t total_num)
{
uint8_t *vals = line->volume_buffer.array;
for (size_t i = 0; i < total_num; i++) {
float val = conv_24bit_to_float(vals) * volume;
conv_float_to_24bit(val, vals);
vals += 3;
}
}
static inline void mul_vol_32bit(struct audio_line *line, float volume,
size_t total_num)
{
int32_t *vals = (int32_t*)line->volume_buffer.array;
for (size_t i = 0; i < total_num; i++) {
float val = (float)vals[i] / 2147483647.0f;
vals[i] = (int32_t)(val * volume / 2147483647.0f);
}
}
static inline void mul_vol_float(struct audio_line *line, float volume,
size_t total_num)
{
float *vals = (float*)line->volume_buffer.array;
for (size_t i = 0; i < total_num; i++)
vals[i] *= volume;
}
static void audio_line_place_data(struct audio_line *line,
const struct audio_data *data, size_t position)
{
size_t total_size = data->frames * line->audio->block_size;
size_t total_num = data->frames * line->audio->channels;
da_copy_array(line->volume_buffer, data->data, total_size);
switch (line->audio->info.format) {
case AUDIO_FORMAT_U8BIT:
mul_vol_u8bit(line, data->volume, total_num);
break;
case AUDIO_FORMAT_16BIT:
mul_vol_16bit(line, data->volume, total_num);
break;
case AUDIO_FORMAT_32BIT:
mul_vol_32bit(line, data->volume, total_num);
break;
case AUDIO_FORMAT_FLOAT:
mul_vol_float(line, data->volume, total_num);
break;
case AUDIO_FORMAT_UNKNOWN:
break;
}
circlebuf_place(&line->buffer, position, line->volume_buffer.array,
total_size);
}
void audio_line_output(audio_line_t line, const struct audio_data *data)
{
if (!line->buffer.size) {
line->base_timestamp = data->timestamp;
circlebuf_push_back(&line->buffer, data->data,
data->frames * line->audio->block_size);
audio_line_place_data(line, data, 0);
} else {
uint64_t position = data->timestamp - line->base_timestamp;
position = convert_to_sample_offset(line->audio, position);
position *= line->audio->block_size;
circlebuf_place(&line->buffer, (size_t)position, data->data,
data->frames * line->audio->block_size);
audio_line_place_data(line, data, (size_t)position);
}
}