Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/Cherry/Core/audio/Multi_Buffer.cpp
2 views
1
// Blip_Buffer 0.4.1. http://www.slack.net/~ant/
2
3
#include "Multi_Buffer.h"
4
5
/* Copyright (C) 2003-2007 Shay Green. This module is free software; you
6
can redistribute it and/or modify it under the terms of the GNU Lesser
7
General Public License as published by the Free Software Foundation; either
8
version 2.1 of the License, or (at your option) any later version. This
9
module is distributed in the hope that it will be useful, but WITHOUT ANY
10
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12
details. You should have received a copy of the GNU Lesser General Public
13
License along with this module; if not, write to the Free Software Foundation,
14
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
15
16
#include "blargg_source.h"
17
18
#ifdef BLARGG_ENABLE_OPTIMIZER
19
#include BLARGG_ENABLE_OPTIMIZER
20
#endif
21
22
Multi_Buffer::Multi_Buffer( int spf ) : samples_per_frame_( spf )
23
{
24
length_ = 0;
25
sample_rate_ = 0;
26
channels_changed_count_ = 1;
27
channel_types_ = 0;
28
channel_count_ = 0;
29
immediate_removal_ = true;
30
}
31
32
Multi_Buffer::channel_t Multi_Buffer::channel( int /*index*/ )
33
{
34
static channel_t const ch = { 0, 0, 0 };
35
return ch;
36
}
37
38
// Silent_Buffer
39
40
Silent_Buffer::Silent_Buffer() : Multi_Buffer( 1 ) // 0 channels would probably confuse
41
{
42
// TODO: better to use empty Blip_Buffer so caller never has to check for NULL?
43
chan.left = 0;
44
chan.center = 0;
45
chan.right = 0;
46
}
47
48
// Mono_Buffer
49
50
Mono_Buffer::Mono_Buffer() : Multi_Buffer( 1 )
51
{
52
chan.center = &buf;
53
chan.left = &buf;
54
chan.right = &buf;
55
}
56
57
Mono_Buffer::~Mono_Buffer() { }
58
59
blargg_err_t Mono_Buffer::set_sample_rate( long rate, int msec )
60
{
61
RETURN_ERR( buf.set_sample_rate( rate, msec ) );
62
return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() );
63
}
64
65
66
// Tracked_Blip_Buffer
67
68
Tracked_Blip_Buffer::Tracked_Blip_Buffer()
69
{
70
last_non_silence = 0;
71
}
72
73
void Tracked_Blip_Buffer::clear()
74
{
75
last_non_silence = 0;
76
Blip_Buffer::clear();
77
}
78
79
void Tracked_Blip_Buffer::end_frame( blip_time_t t )
80
{
81
Blip_Buffer::end_frame( t );
82
if ( clear_modified() )
83
last_non_silence = (int)samples_avail() + blip_buffer_extra_;
84
}
85
86
blip_ulong Tracked_Blip_Buffer::non_silent() const
87
{
88
return last_non_silence | unsettled();
89
}
90
91
inline void Tracked_Blip_Buffer::remove_( long n )
92
{
93
if ( (last_non_silence -= n) < 0 )
94
last_non_silence = 0;
95
}
96
97
void Tracked_Blip_Buffer::remove_silence( long n )
98
{
99
remove_( n );
100
Blip_Buffer::remove_silence( n );
101
}
102
103
void Tracked_Blip_Buffer::remove_samples( long n )
104
{
105
remove_( n );
106
Blip_Buffer::remove_samples( n );
107
}
108
109
void Tracked_Blip_Buffer::remove_all_samples()
110
{
111
long avail = samples_avail();
112
if ( !non_silent() )
113
remove_silence( avail );
114
else
115
remove_samples( avail );
116
}
117
118
long Tracked_Blip_Buffer::read_samples( blip_sample_t* out, long count )
119
{
120
count = Blip_Buffer::read_samples( out, count );
121
remove_( count );
122
return count;
123
}
124
125
// Stereo_Buffer
126
127
int const stereo = 2;
128
129
Stereo_Buffer::Stereo_Buffer() : Multi_Buffer( 2 )
130
{
131
chan.center = mixer.bufs [2] = &bufs [2];
132
chan.left = mixer.bufs [0] = &bufs [0];
133
chan.right = mixer.bufs [1] = &bufs [1];
134
mixer.samples_read = 0;
135
}
136
137
Stereo_Buffer::~Stereo_Buffer() { }
138
139
blargg_err_t Stereo_Buffer::set_sample_rate( long rate, int msec )
140
{
141
mixer.samples_read = 0;
142
for ( int i = bufs_size; --i >= 0; )
143
RETURN_ERR( bufs [i].set_sample_rate( rate, msec ) );
144
return Multi_Buffer::set_sample_rate( bufs [0].sample_rate(), bufs [0].length() );
145
}
146
147
void Stereo_Buffer::clock_rate( long rate )
148
{
149
for ( int i = bufs_size; --i >= 0; )
150
bufs [i].clock_rate( rate );
151
}
152
153
void Stereo_Buffer::bass_freq( int bass )
154
{
155
for ( int i = bufs_size; --i >= 0; )
156
bufs [i].bass_freq( bass );
157
}
158
159
void Stereo_Buffer::clear()
160
{
161
mixer.samples_read = 0;
162
for ( int i = bufs_size; --i >= 0; )
163
bufs [i].clear();
164
}
165
166
void Stereo_Buffer::end_frame( blip_time_t time )
167
{
168
for ( int i = bufs_size; --i >= 0; )
169
bufs [i].end_frame( time );
170
}
171
172
long Stereo_Buffer::read_samples( blip_sample_t* out, long out_size )
173
{
174
require( (out_size & 1) == 0 ); // must read an even number of samples
175
out_size = min( out_size, samples_avail() );
176
177
int pair_count = int (out_size >> 1);
178
if ( pair_count )
179
{
180
mixer.read_pairs( out, pair_count );
181
182
if ( samples_avail() <= 0 || immediate_removal() )
183
{
184
for ( int i = bufs_size; --i >= 0; )
185
{
186
buf_t& b = bufs [i];
187
// TODO: might miss non-silence settling since it checks END of last read
188
if ( !b.non_silent() )
189
b.remove_silence( mixer.samples_read );
190
else
191
b.remove_samples( mixer.samples_read );
192
}
193
mixer.samples_read = 0;
194
}
195
}
196
return out_size;
197
}
198
199
200
// Stereo_Mixer
201
202
// mixers use a single index value to improve performance on register-challenged processors
203
// offset goes from negative to zero
204
205
void Stereo_Mixer::read_pairs( blip_sample_t* out, int count )
206
{
207
// TODO: if caller never marks buffers as modified, uses mono
208
// except that buffer isn't cleared, so caller can encounter
209
// subtle problems and not realize the cause.
210
samples_read += count;
211
if ( bufs [0]->non_silent() | bufs [1]->non_silent() )
212
mix_stereo( out, count );
213
else
214
mix_mono( out, count );
215
}
216
217
void Stereo_Mixer::mix_mono( blip_sample_t* out_, int count )
218
{
219
int const bass = BLIP_READER_BASS( *bufs [2] );
220
BLIP_READER_BEGIN( center, *bufs [2] );
221
BLIP_READER_ADJ_( center, samples_read );
222
223
typedef blip_sample_t stereo_blip_sample_t [stereo];
224
stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_ + count;
225
int offset = -count;
226
do
227
{
228
blargg_long s = BLIP_READER_READ( center );
229
BLIP_READER_NEXT_IDX_( center, bass, offset );
230
BLIP_CLAMP( s, s );
231
232
out [offset] [0] = (blip_sample_t) s;
233
out [offset] [1] = (blip_sample_t) s;
234
}
235
while ( ++offset );
236
237
BLIP_READER_END( center, *bufs [2] );
238
}
239
240
void Stereo_Mixer::mix_stereo( blip_sample_t* out_, int count )
241
{
242
blip_sample_t* BLIP_RESTRICT out = out_ + count * stereo;
243
244
// do left + center and right + center separately to reduce register load
245
Tracked_Blip_Buffer* const* buf = &bufs [2];
246
while ( true ) // loop runs twice
247
{
248
--buf;
249
--out;
250
251
int const bass = BLIP_READER_BASS( *bufs [2] );
252
BLIP_READER_BEGIN( side, **buf );
253
BLIP_READER_BEGIN( center, *bufs [2] );
254
255
BLIP_READER_ADJ_( side, samples_read );
256
BLIP_READER_ADJ_( center, samples_read );
257
258
int offset = -count;
259
do
260
{
261
blargg_long s = BLIP_READER_READ_RAW( center ) + BLIP_READER_READ_RAW( side );
262
s >>= blip_sample_bits - 16;
263
BLIP_READER_NEXT_IDX_( side, bass, offset );
264
BLIP_READER_NEXT_IDX_( center, bass, offset );
265
BLIP_CLAMP( s, s );
266
267
++offset; // before write since out is decremented to slightly before end
268
out [offset * stereo] = (blip_sample_t) s;
269
}
270
while ( offset );
271
272
BLIP_READER_END( side, **buf );
273
274
if ( buf != bufs )
275
continue;
276
277
// only end center once
278
BLIP_READER_END( center, *bufs [2] );
279
break;
280
}
281
}
282
283