xref: /haiku/src/apps/mediaplayer/media_node_framework/audio/AudioVolumeConverter.cpp (revision 1deede7388b04dbeec5af85cae7164735ea9e70d)
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
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
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 
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 
69 AudioVolumeConverter::~AudioVolumeConverter()
70 {
71 }
72 
73 
74 bigtime_t
75 AudioVolumeConverter::InitialLatency() const
76 {
77 	return fSource->InitialLatency();
78 }
79 
80 
81 status_t
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
151 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*
163 AudioVolumeConverter::Source() const
164 {
165 	return fSource;
166 }
167 
168 
169 void
170 AudioVolumeConverter::SetVolume(float volume)
171 {
172 	fVolume = volume;
173 }
174 
175 
176 float
177 AudioVolumeConverter::Volume() const
178 {
179 	return fVolume;
180 }
181 
182