- /* Maybe apply gain */
- if (_fs->audio_gain != 0) {
- float const linear_gain = pow (10, _fs->audio_gain / 20);
- uint8_t* p = data;
- switch (_fs->audio_sample_format) {
- case AV_SAMPLE_FMT_S16:
- for (int i = 0; i < samples; ++i) {
- /* XXX: assumes little-endian; also we should probably be dithering here */
-
- /* unsigned sample */
- int const ou = p[0] | (p[1] << 8);
-
- /* signed sample */
- int const os = ou >= 0x8000 ? (- 0x10000 + ou) : ou;
-
- /* signed sample with altered gain */
- int const gs = int (os * linear_gain);
-
- /* unsigned sample with altered gain */
- int const gu = gs > 0 ? gs : (0x10000 + gs);
-
- /* write it back */
- p[0] = gu & 0xff;
- p[1] = (gu & 0xff00) >> 8;
- p += 2;
+void
+Decoder::emit_audio (uint8_t* data, int size)
+{
+ /* Deinterleave and convert to float */
+
+ assert ((size % (bytes_per_audio_sample() * _fs->audio_channels())) == 0);
+
+ int const total_samples = size / bytes_per_audio_sample();
+ int const frames = total_samples / _fs->audio_channels();
+ shared_ptr<AudioBuffers> audio (new AudioBuffers (_fs->audio_channels(), frames));
+
+ switch (audio_sample_format()) {
+ case AV_SAMPLE_FMT_S16:
+ {
+ int16_t* p = (int16_t *) data;
+ int sample = 0;
+ int channel = 0;
+ for (int i = 0; i < total_samples; ++i) {
+ audio->data(channel)[sample] = float(*p++) / (1 << 15);
+
+ ++channel;
+ if (channel == _fs->audio_channels()) {
+ channel = 0;
+ ++sample;
+ }
+ }
+ }
+ break;
+
+ case AV_SAMPLE_FMT_S32:
+ {
+ int32_t* p = (int32_t *) data;
+ int sample = 0;
+ int channel = 0;
+ for (int i = 0; i < total_samples; ++i) {
+ audio->data(channel)[sample] = float(*p++) / (1 << 31);
+
+ ++channel;
+ if (channel == _fs->audio_channels()) {
+ channel = 0;
+ ++sample;