1 /*
2 * Copyright 2008 Stephan Aßmus <superstippi@gmx.de>
3 * All rights reserved. Distributed under the terms of the MIT licensce.
4 */
5
6
7 #include "AudioVolumeConverter.h"
8
9 #include <stdio.h>
10 #include <string.h>
11
12 #include <MediaDefs.h>
13
14
15 //#define TRACE_AUDIO_CONVERTER
16 #ifdef TRACE_AUDIO_CONVERTER
17 # define TRACE(x...) printf(x)
18 #else
19 # define TRACE(x...)
20 #endif
21
22
23 template<typename SampleType>
24 static void
convert(SampleType * buffer,const int32 samples,const float volume,const float rounding)25 convert(SampleType* buffer, const int32 samples, const float volume,
26 const float rounding)
27 {
28 for (int32 i = 0; i < samples; i++) {
29 *buffer = (SampleType)(*buffer * volume + rounding);
30 buffer++;
31 }
32 }
33
34
35 template<typename SampleType>
36 static void
convert(SampleType * buffer,const int32 frames,const int32 channels,const float volume1,const float volume2,const float rounding)37 convert(SampleType* buffer, const int32 frames, const int32 channels,
38 const float volume1, const float volume2, const float rounding)
39 {
40 float volumeDiff = volume2 - volume1;
41 for (int32 i = 0; i < frames; i++) {
42 float volume = volume1 + volumeDiff * (i / (frames - 1));
43 for (int32 k = 0; k < channels; k++) {
44 *buffer = (SampleType)(*buffer * volume + rounding);
45 buffer++;
46 }
47 }
48 }
49
50
51 // #pragma mark -
52
53
AudioVolumeConverter(AudioReader * source,float volume)54 AudioVolumeConverter::AudioVolumeConverter(AudioReader* source, float volume)
55 :
56 AudioReader(),
57 fSource(NULL),
58 fVolume(volume),
59 fPreviousVolume(volume)
60 {
61 if (source && source->Format().type == B_MEDIA_RAW_AUDIO)
62 fFormat = source->Format();
63 else
64 source = NULL;
65 fSource = source;
66 }
67
68
~AudioVolumeConverter()69 AudioVolumeConverter::~AudioVolumeConverter()
70 {
71 }
72
73
74 bigtime_t
InitialLatency() const75 AudioVolumeConverter::InitialLatency() const
76 {
77 return fSource->InitialLatency();
78 }
79
80
81 status_t
Read(void * buffer,int64 pos,int64 frames)82 AudioVolumeConverter::Read(void* buffer, int64 pos, int64 frames)
83 {
84 TRACE("AudioVolumeConverter::Read(%p, %lld, %lld)\n", buffer, pos, frames);
85 status_t error = InitCheck();
86 if (error != B_OK) {
87 TRACE("AudioVolumeConverter::Read() done 1\n");
88 return error;
89 }
90 pos += fOutOffset;
91
92 status_t ret = fSource->Read(buffer, pos, frames);
93 if (fPreviousVolume == 1.0 && fVolume == 1.0) {
94 TRACE("AudioVolumeConverter::Read() done 2\n");
95 return ret;
96 }
97
98 int32 channelCount = fFormat.u.raw_audio.channel_count;
99 int32 samples = frames * channelCount;
100
101 // apply volume
102 switch (fSource->Format().u.raw_audio.format) {
103 case media_raw_audio_format::B_AUDIO_FLOAT:
104 if (fVolume != fPreviousVolume) {
105 convert((float*)buffer, frames, channelCount,
106 fPreviousVolume, fVolume, 0.0);
107 } else
108 convert((float*)buffer, samples, fVolume, 0.0);
109 break;
110 case media_raw_audio_format::B_AUDIO_INT:
111 if (fVolume != fPreviousVolume) {
112 convert((int32*)buffer, frames, channelCount,
113 fPreviousVolume, fVolume, 0.5);
114 } else
115 convert((int32*)buffer, samples, fVolume, 0.5);
116 break;
117 case media_raw_audio_format::B_AUDIO_SHORT:
118 if (fVolume != fPreviousVolume) {
119 convert((int16*)buffer, frames, channelCount,
120 fPreviousVolume, fVolume, 0.5);
121 } else
122 convert((int16*)buffer, samples, fVolume, 0.5);
123 break;
124 case media_raw_audio_format::B_AUDIO_UCHAR: {
125 // handle this extra, because center != 0
126 // (also ignores ramping the volume)
127 uchar* b = (uchar*)buffer;
128 for (int32 i = 0; i < samples; i++) {
129 *b = (uchar)(((float)*b - 128) * fVolume + 128.5);
130 b++;
131 }
132 break;
133 }
134 case media_raw_audio_format::B_AUDIO_CHAR:
135 if (fVolume != fPreviousVolume) {
136 convert((int8*)buffer, frames, channelCount,
137 fPreviousVolume, fVolume, 0.0);
138 } else
139 convert((int8*)buffer, samples, fVolume, 0.5);
140 break;
141 }
142
143 fPreviousVolume = fVolume;
144
145 TRACE("AudioVolumeConverter::Read() done\n");
146 return B_OK;
147 }
148
149
150 status_t
InitCheck() const151 AudioVolumeConverter::InitCheck() const
152 {
153 status_t error = AudioReader::InitCheck();
154 if (error == B_OK && !fSource)
155 error = B_NO_INIT;
156 if (error == B_OK)
157 error = fSource->InitCheck();
158 return error;
159 }
160
161
162 AudioReader*
Source() const163 AudioVolumeConverter::Source() const
164 {
165 return fSource;
166 }
167
168
169 void
SetVolume(float volume)170 AudioVolumeConverter::SetVolume(float volume)
171 {
172 fVolume = volume;
173 }
174
175
176 float
Volume() const177 AudioVolumeConverter::Volume() const
178 {
179 return fVolume;
180 }
181
182