File: vlevel_wrapper.cpp

package info (click to toggle)
vlevel 0.5.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 380 kB
  • sloc: cpp: 1,429; makefile: 106; sh: 7
file content (174 lines) | stat: -rw-r--r-- 5,615 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
///////////////////////////////////////////////////////////////////////////////
//
// vlevel_wrapper.cpp - this file is part of vlevel winamp plugin 0.1
// Copyright (C) 2003 Markus Sablatnig
// Copyright (C) 2003 Tom Felker
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
//
///////////////////////////////////////////////////////////////////////////////

#include <new>
#include <assert.h>

#include "..\\volumeleveler\\volumeleveler.h"
#include "vlevel_wrapper.h"

CVLWrapper::CVLWrapper():
	ms_samples(44100),
	ms_channels(2),
	mv_strength(.8),
	mv_maxMultiplier(25),
	mv_length(1),
	ms_rate(44100),
	mb_samplesOrChannelsChanged(false),
	mb_strengthChanged(false),
	mb_maxMultiplierChanged(false)
{
	mpvl_wrapped = new VolumeLeveler(ms_samples, ms_channels, mv_strength, mv_maxMultiplier);
	
	// I'm surprised this isn't automatic.
	if(!mpvl_wrapped)
		throw std::bad_alloc();
} // CVLWrapper::CVLWrapper

CVLWrapper::~CVLWrapper()
{
	delete mpvl_wrapped;
	// TODO: when I cache the buffer allocations, I must delete them here.
}

void CVLWrapper::SetCachedChannels(size_t s_channels)
{
	assert(s_channels > 0);
	if(ms_channels != s_channels) {
		ms_channels = s_channels;
		mb_samplesOrChannelsChanged = true;
	}
} // CVLWrapper::SetCachedChannels

void CVLWrapper::SetCachedStrength(value_t v_strength)
{	
	mv_strength = v_strength;
	mb_strengthChanged = true;
} // CVLWrapper::SetCachedStrength

void CVLWrapper::SetCachedMaxMultiplier(value_t v_maxMultiplier)
{	
	mv_maxMultiplier = v_maxMultiplier;
	mb_maxMultiplierChanged = true;
} // CVLWrapper::SetCachedMaxMultiplier

void CVLWrapper::SetCachedLength(value_t v_length)
{
	mv_length = v_length;
	SetCachedSamples(GetCachedLength() * GetCachedRate());
} // CVLWrapper::SetCachedLength

void CVLWrapper::SetCachedRate(size_t s_rate)
{
	ms_rate = s_rate;
	ms_samples = mv_length * ms_rate;
	
	SetCachedSamples(GetCachedLength() * GetCachedRate());
} // CVLWrapper::SetCachedRate

// Don't call this unless you've just computed s_amples from mv_length and ms_rate.
void CVLWrapper::SetCachedSamples(size_t s_samples)
{	
	assert(s_samples > 1);
	if(ms_samples != s_samples) {
		ms_samples = s_samples;
		mb_samplesOrChannelsChanged = true;
	}
} // CVLWrapper::SetCachedSamples

void CVLWrapper::CacheFlush()
{
	if( mb_samplesOrChannelsChanged)
	{
		mpvl_wrapped->SetSamplesAndChannels(ms_samples, ms_channels);
		mb_samplesOrChannelsChanged = false;
	} // if

	if( mb_strengthChanged )
	{
		mpvl_wrapped->SetStrength(mv_strength);
		mb_strengthChanged = false;
	} // if

	if(mb_maxMultiplierChanged)
	{
		mpvl_wrapped->SetMaxMultiplier(mv_maxMultiplier);
		SetCachedMaxMultiplier(mpvl_wrapped->GetMaxMultiplier()); // turns negative mms to HUGE_VAL
		mb_maxMultiplierChanged = false;
	} // if
} // CVLWrapper::CacheFlush

int CVLWrapper::Exchange(void *raw_buf, int samples, int bits_per_value, int channels, int rate)
{
	SetCachedChannels(channels);
	SetCachedRate(rate);
	CacheFlush();
	
	size_t values = samples * channels;
	
	// TODO: cache these allocations for performance.
	// This buffer holds interleaved value_t data.
	value_t *raw_value_buf = new value_t[values];
	// Allocate our per-channel value_t buffers.
	// This is the format VolumeLeveler requires.
	value_t **bufs = new value_t*[channels];
	for(size_t ch = 0; ch < channels; ++ch)
		bufs[ch] = new value_t[samples];
	
	// Take data from supplied integer raw_buf to allocated value_t interleaved raw_value_buf.
	ToValues((char *)raw_buf, raw_value_buf, values, bits_per_value, true); // true because data is signed.
	
	// De-interleave the data.
	for(size_t s = 0; s < samples; ++s)
		for(size_t ch = 0; ch < channels; ++ch)
			bufs[ch][s] = raw_value_buf[s * channels + ch];
	
	// Perform the effect.
	// silence_samples is how many samples at the beginning of the returned buffer
	// are silent because the real data hasn't worked through VLevel's buffer yet.
	size_t silence_samples = mpvl_wrapped->Exchange(bufs, bufs, samples);
	
	size_t good_samples = samples - silence_samples;
	size_t good_values = good_samples * channels;

	// Re-interleave the data.
	// Visual C++ improperly lets the s defined above persist outside that loop.
	// Notice that leading silence_samples are stripped and good data is shifted.
	for(/* size_t */ s = 0; s < good_samples; ++s)
		for(size_t ch = 0; ch < channels; ++ch)
			raw_value_buf[s * channels + ch] = bufs[ch][s + silence_samples];
	
	// Put the good data back into the supplied integer buffer.
	FromValues(raw_value_buf, (char *)raw_buf, good_values, bits_per_value, true);
	
	// Deallocate our buffers.
	for(/* size_t */ ch = 0; ch < channels; ++ch)
		delete [] bufs[ch];
	delete [] bufs;
	delete [] raw_value_buf;

	// Winamp is sloppy about using int when size_t is correct.  Oh, well.	
	// dsp.h says we shouldn't return less than half as many samples as we're given,
	// but returning 0 seems to work fine.	
	return good_samples;	
} // CVLWrapper::Exchange