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