Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
folium-app
GitHub Repository: folium-app/Folium
Path: blob/a-new-beginning/Cherry/Core/audio/Effects_Buffer.cpp
2 views
1
// Game_Music_Emu $vers. http://www.slack.net/~ant/
2
3
#include "Effects_Buffer.h"
4
5
#include <string.h>
6
7
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
8
can redistribute it and/or modify it under the terms of the GNU Lesser
9
General Public License as published by the Free Software Foundation; either
10
version 2.1 of the License, or (at your option) any later version. This
11
module is distributed in the hope that it will be useful, but WITHOUT ANY
12
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14
details. You should have received a copy of the GNU Lesser General Public
15
License along with this module; if not, write to the Free Software Foundation,
16
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
17
18
#include "blargg_source.h"
19
20
int const fixed_shift = 12;
21
#define TO_FIXED( f ) fixed_t ((f) * ((fixed_t) 1 << fixed_shift))
22
#define FROM_FIXED( f ) ((f) >> fixed_shift)
23
24
int const max_read = 2560; // determines minimum delay
25
26
Effects_Buffer::Effects_Buffer( int max_bufs, long echo_size_ ) : Multi_Buffer( stereo )
27
{
28
echo_size = (int)max( max_read * (long) stereo, echo_size_ & ~1 );
29
clock_rate_ = 0;
30
bass_freq_ = 90;
31
bufs = 0;
32
bufs_size = 0;
33
bufs_max = max( max_bufs, (int) extra_chans );
34
no_echo = true;
35
no_effects = true;
36
37
// defaults
38
config_.enabled = false;
39
config_.delay [0] = 120;
40
config_.delay [1] = 122;
41
config_.feedback = 0.2f;
42
config_.treble = 0.4f;
43
44
static float const sep = 0.8f;
45
config_.side_chans [0].pan = -sep;
46
config_.side_chans [1].pan = +sep;
47
config_.side_chans [0].vol = 1.0f;
48
config_.side_chans [1].vol = 1.0f;
49
50
memset( &s, 0, sizeof s );
51
clear();
52
}
53
54
Effects_Buffer::~Effects_Buffer()
55
{
56
delete_bufs();
57
}
58
59
// avoid using new []
60
blargg_err_t Effects_Buffer::new_bufs( int size )
61
{
62
bufs = (buf_t*) malloc( size * sizeof *bufs );
63
CHECK_ALLOC( bufs );
64
for ( int i = 0; i < size; i++ )
65
new (bufs + i) buf_t;
66
bufs_size = size;
67
return 0;
68
}
69
70
void Effects_Buffer::delete_bufs()
71
{
72
if ( bufs )
73
{
74
for ( int i = bufs_size; --i >= 0; )
75
bufs [i].~buf_t();
76
free( bufs );
77
bufs = 0;
78
}
79
bufs_size = 0;
80
}
81
82
blargg_err_t Effects_Buffer::set_sample_rate( long rate, int msec )
83
{
84
// extra to allow farther past-the-end pointers
85
mixer.samples_read = 0;
86
RETURN_ERR( echo.resize( echo_size + stereo ) );
87
return Multi_Buffer::set_sample_rate( rate, msec );
88
}
89
90
void Effects_Buffer::clock_rate( long rate )
91
{
92
clock_rate_ = rate;
93
for ( int i = bufs_size; --i >= 0; )
94
bufs [i].clock_rate( clock_rate_ );
95
}
96
97
void Effects_Buffer::bass_freq( int freq )
98
{
99
bass_freq_ = freq;
100
for ( int i = bufs_size; --i >= 0; )
101
bufs [i].bass_freq( bass_freq_ );
102
}
103
104
blargg_err_t Effects_Buffer::set_channel_count( int count, int const* types )
105
{
106
RETURN_ERR( Multi_Buffer::set_channel_count( count, types ) );
107
108
delete_bufs();
109
110
mixer.samples_read = 0;
111
112
RETURN_ERR( chans.resize( count + extra_chans ) );
113
114
RETURN_ERR( new_bufs( min( bufs_max, count + extra_chans ) ) );
115
116
for ( int i = bufs_size; --i >= 0; )
117
RETURN_ERR( bufs [i].set_sample_rate( sample_rate(), length() ) );
118
119
for ( int i = (int)chans.size(); --i >= 0; )
120
{
121
chan_t& ch = chans [i];
122
ch.cfg.vol = 1.0f;
123
ch.cfg.pan = 0.0f;
124
ch.cfg.surround = false;
125
ch.cfg.echo = false;
126
}
127
// side channels with echo
128
chans [2].cfg.echo = true;
129
chans [3].cfg.echo = true;
130
131
clock_rate( clock_rate_ );
132
bass_freq( bass_freq_ );
133
apply_config();
134
clear();
135
136
return 0;
137
}
138
139
void Effects_Buffer::clear_echo()
140
{
141
if ( echo.size() )
142
memset( echo.begin(), 0, echo.size() * sizeof echo [0] );
143
}
144
145
void Effects_Buffer::clear()
146
{
147
echo_pos = 0;
148
s.low_pass [0] = 0;
149
s.low_pass [1] = 0;
150
mixer.samples_read = 0;
151
152
for ( int i = bufs_size; --i >= 0; )
153
bufs [i].clear();
154
clear_echo();
155
}
156
157
Effects_Buffer::channel_t Effects_Buffer::channel( int i )
158
{
159
i += extra_chans;
160
require( extra_chans <= i && i < (int) chans.size() );
161
return chans [i].channel;
162
}
163
164
165
// Configuration
166
167
// 3 wave positions with/without surround, 2 multi (one with same config as wave)
168
int const simple_bufs = 3 * 2 + 2 - 1;
169
170
Simple_Effects_Buffer::Simple_Effects_Buffer() :
171
Effects_Buffer( extra_chans + simple_bufs, 18 * 1024L )
172
{
173
config_.echo = 0.20f;
174
config_.stereo = 0.20f;
175
config_.surround = true;
176
config_.enabled = false;
177
}
178
179
void Simple_Effects_Buffer::apply_config()
180
{
181
Effects_Buffer::config_t& c = Effects_Buffer::config();
182
183
c.enabled = config_.enabled;
184
if ( c.enabled )
185
{
186
c.delay [0] = 120;
187
c.delay [1] = 122;
188
c.feedback = config_.echo * 0.7f;
189
c.treble = 0.6f - 0.3f * config_.echo;
190
191
float sep = config_.stereo + 0.80f;
192
if ( sep > 1.0f )
193
sep = 1.0f;
194
195
c.side_chans [0].pan = -sep;
196
c.side_chans [1].pan = +sep;
197
198
for ( int i = channel_count(); --i >= 0; )
199
{
200
chan_config_t& ch = Effects_Buffer::chan_config( i );
201
202
ch.pan = 0.0f;
203
ch.surround = config_.surround;
204
ch.echo = false;
205
206
int const type = (channel_types() ? channel_types() [i] : 0);
207
if ( !(type & noise_type) )
208
{
209
int index = (type & type_index_mask) % 6 - 3;
210
if ( index < 0 )
211
{
212
index += 3;
213
ch.surround = false;
214
ch.echo = true;
215
}
216
if ( index >= 1 )
217
{
218
ch.pan = config_.stereo;
219
if ( index == 1 )
220
ch.pan = -ch.pan;
221
}
222
}
223
else if ( type & 1 )
224
{
225
ch.surround = false;
226
}
227
}
228
}
229
230
Effects_Buffer::apply_config();
231
}
232
233
int Effects_Buffer::min_delay() const
234
{
235
require( sample_rate() );
236
return max_read * 1000L / sample_rate();
237
}
238
239
int Effects_Buffer::max_delay() const
240
{
241
require( sample_rate() );
242
return (echo_size / stereo - max_read) * 1000L / sample_rate();
243
}
244
245
void Effects_Buffer::apply_config()
246
{
247
int i;
248
249
if ( !bufs_size )
250
return;
251
252
s.treble = TO_FIXED( config_.treble );
253
254
bool echo_dirty = false;
255
256
fixed_t old_feedback = s.feedback;
257
s.feedback = TO_FIXED( config_.feedback );
258
if ( !old_feedback && s.feedback )
259
echo_dirty = true;
260
261
// delays
262
for ( i = stereo; --i >= 0; )
263
{
264
long delay = config_.delay [i] * sample_rate() / 1000 * stereo;
265
delay = max( delay, long (max_read * stereo) );
266
delay = min( delay, long (echo_size - max_read * stereo) );
267
if ( s.delay [i] != delay )
268
{
269
s.delay [i] = delay;
270
echo_dirty = true;
271
}
272
}
273
274
// side channels
275
for ( i = 2; --i >= 0; )
276
{
277
chans [i+2].cfg.vol = chans [i].cfg.vol = config_.side_chans [i].vol * 0.5f;
278
chans [i+2].cfg.pan = chans [i].cfg.pan = config_.side_chans [i].pan;
279
}
280
281
// convert volumes
282
for ( i = (int)chans.size(); --i >= 0; )
283
{
284
chan_t& ch = chans [i];
285
ch.vol [0] = TO_FIXED( ch.cfg.vol - ch.cfg.vol * ch.cfg.pan );
286
ch.vol [1] = TO_FIXED( ch.cfg.vol + ch.cfg.vol * ch.cfg.pan );
287
if ( ch.cfg.surround )
288
ch.vol [0] = -ch.vol [0];
289
}
290
291
assign_buffers();
292
293
// set side channels
294
for ( i = (int)chans.size(); --i >= 0; )
295
{
296
chan_t& ch = chans [i];
297
ch.channel.left = chans [ch.cfg.echo*2 ].channel.center;
298
ch.channel.right = chans [ch.cfg.echo*2+1].channel.center;
299
}
300
301
bool old_echo = !no_echo && !no_effects;
302
303
// determine whether effects and echo are needed at all
304
no_effects = true;
305
no_echo = true;
306
for ( i = (int)chans.size(); --i >= extra_chans; )
307
{
308
chan_t& ch = chans [i];
309
if ( ch.cfg.echo && s.feedback )
310
no_echo = false;
311
312
if ( ch.vol [0] != TO_FIXED( 1 ) || ch.vol [1] != TO_FIXED( 1 ) )
313
no_effects = false;
314
}
315
if ( !no_echo )
316
no_effects = false;
317
318
if ( chans [0].vol [0] != TO_FIXED( 1 ) ||
319
chans [0].vol [1] != TO_FIXED( 0 ) ||
320
chans [1].vol [0] != TO_FIXED( 0 ) ||
321
chans [1].vol [1] != TO_FIXED( 1 ) )
322
no_effects = false;
323
324
if ( !config_.enabled )
325
no_effects = true;
326
327
if ( no_effects )
328
{
329
for ( i = (int)chans.size(); --i >= 0; )
330
{
331
chan_t& ch = chans [i];
332
ch.channel.center = &bufs [2];
333
ch.channel.left = &bufs [0];
334
ch.channel.right = &bufs [1];
335
}
336
}
337
338
mixer.bufs [0] = &bufs [0];
339
mixer.bufs [1] = &bufs [1];
340
mixer.bufs [2] = &bufs [2];
341
342
if ( echo_dirty || (!old_echo && (!no_echo && !no_effects)) )
343
clear_echo();
344
345
channels_changed();
346
}
347
348
void Effects_Buffer::assign_buffers()
349
{
350
// assign channels to buffers
351
int buf_count = 0;
352
for ( int i = 0; i < (int) chans.size(); i++ )
353
{
354
// put second two side channels at end to give priority to main channels
355
// in case closest matching is necessary
356
int x = i;
357
if ( i > 1 )
358
x += 2;
359
if ( x >= (int) chans.size() )
360
x -= ((int)chans.size() - 2);
361
chan_t& ch = chans [x];
362
363
int b = 0;
364
for ( ; b < buf_count; b++ )
365
{
366
if ( ch.vol [0] == bufs [b].vol [0] &&
367
ch.vol [1] == bufs [b].vol [1] &&
368
(ch.cfg.echo == bufs [b].echo || !s.feedback) )
369
break;
370
}
371
372
if ( b >= buf_count )
373
{
374
if ( buf_count < bufs_max )
375
{
376
bufs [b].vol [0] = ch.vol [0];
377
bufs [b].vol [1] = ch.vol [1];
378
bufs [b].echo = ch.cfg.echo;
379
buf_count++;
380
}
381
else
382
{
383
// TODO: this is a mess, needs refinement
384
dprintf( "Effects_Buffer ran out of buffers; using closest match\n" );
385
b = 0;
386
fixed_t best_dist = TO_FIXED( 8 );
387
for ( int h = buf_count; --h >= 0; )
388
{
389
#define CALC_LEVELS( vols, sum, diff, surround ) \
390
fixed_t sum, diff;\
391
bool surround = false;\
392
{\
393
fixed_t vol_0 = vols [0];\
394
if ( vol_0 < 0 ) vol_0 = -vol_0, surround = true;\
395
fixed_t vol_1 = vols [1];\
396
if ( vol_1 < 0 ) vol_1 = -vol_1, surround = true;\
397
sum = vol_0 + vol_1;\
398
diff = vol_0 - vol_1;\
399
}
400
CALC_LEVELS( ch.vol, ch_sum, ch_diff, ch_surround );
401
CALC_LEVELS( bufs [h].vol, buf_sum, buf_diff, buf_surround );
402
403
fixed_t dist = abs( ch_sum - buf_sum ) + abs( ch_diff - buf_diff );
404
405
if ( ch_surround != buf_surround )
406
dist += TO_FIXED( 1 ) / 2;
407
408
if ( s.feedback && ch.cfg.echo != bufs [h].echo )
409
dist += TO_FIXED( 1 ) / 2;
410
411
if ( best_dist > dist )
412
{
413
best_dist = dist;
414
b = h;
415
}
416
}
417
}
418
}
419
420
//dprintf( "ch %d->buf %d\n", x, b );
421
ch.channel.center = &bufs [b];
422
}
423
}
424
425
426
// Mixing
427
428
void Effects_Buffer::end_frame( blip_time_t time )
429
{
430
for ( int i = bufs_size; --i >= 0; )
431
bufs [i].end_frame( time );
432
}
433
434
long Effects_Buffer::read_samples( blip_sample_t* out, long out_size )
435
{
436
out_size = min( out_size, samples_avail() );
437
438
int pair_count = int (out_size >> 1);
439
require( pair_count * stereo == out_size ); // must read an even number of samples
440
if ( pair_count )
441
{
442
if ( no_effects )
443
{
444
mixer.read_pairs( out, pair_count );
445
}
446
else
447
{
448
int pairs_remain = pair_count;
449
do
450
{
451
// mix at most max_read pairs at a time
452
int count = max_read;
453
if ( count > pairs_remain )
454
count = pairs_remain;
455
456
if ( no_echo )
457
{
458
// optimization: clear echo here to keep mix_effects() a leaf function
459
echo_pos = 0;
460
memset( echo.begin(), 0, count * stereo * sizeof echo [0] );
461
}
462
mix_effects( out, count );
463
464
blargg_long new_echo_pos = echo_pos + count * stereo;
465
if ( new_echo_pos >= echo_size )
466
new_echo_pos -= echo_size;
467
echo_pos = new_echo_pos;
468
assert( echo_pos < echo_size );
469
470
out += count * stereo;
471
mixer.samples_read += count;
472
pairs_remain -= count;
473
}
474
while ( pairs_remain );
475
}
476
477
if ( samples_avail() <= 0 || immediate_removal() )
478
{
479
for ( int i = bufs_size; --i >= 0; )
480
{
481
buf_t& b = bufs [i];
482
// TODO: might miss non-silence settling since it checks END of last read
483
if ( b.non_silent() )
484
b.remove_samples( mixer.samples_read );
485
else
486
b.remove_silence( mixer.samples_read );
487
}
488
mixer.samples_read = 0;
489
}
490
}
491
return out_size;
492
}
493
494
void Effects_Buffer::mix_effects( blip_sample_t* out_, int pair_count )
495
{
496
typedef fixed_t stereo_fixed_t [stereo];
497
498
// add channels with echo, do echo, add channels without echo, then convert to 16-bit and output
499
int echo_phase = 1;
500
do
501
{
502
// mix any modified buffers
503
{
504
buf_t* buf = bufs;
505
int bufs_remain = bufs_size;
506
do
507
{
508
if ( buf->non_silent() && ( buf->echo == !!echo_phase ) )
509
{
510
stereo_fixed_t* BLIP_RESTRICT out = (stereo_fixed_t*) &echo [echo_pos];
511
int const bass = BLIP_READER_BASS( *buf );
512
BLIP_READER_BEGIN( in, *buf );
513
BLIP_READER_ADJ_( in, mixer.samples_read );
514
fixed_t const vol_0 = buf->vol [0];
515
fixed_t const vol_1 = buf->vol [1];
516
517
int count = unsigned (echo_size - echo_pos) / stereo;
518
int remain = pair_count;
519
if ( count > remain )
520
count = remain;
521
do
522
{
523
remain -= count;
524
BLIP_READER_ADJ_( in, count );
525
526
out += count;
527
int offset = -count;
528
do
529
{
530
fixed_t s = BLIP_READER_READ( in );
531
BLIP_READER_NEXT_IDX_( in, bass, offset );
532
533
out [offset] [0] += s * vol_0;
534
out [offset] [1] += s * vol_1;
535
}
536
while ( ++offset );
537
538
out = (stereo_fixed_t*) echo.begin();
539
count = remain;
540
}
541
while ( remain );
542
543
BLIP_READER_END( in, *buf );
544
}
545
buf++;
546
}
547
while ( --bufs_remain );
548
}
549
550
// add echo
551
if ( echo_phase && !no_echo )
552
{
553
fixed_t const feedback = s.feedback;
554
fixed_t const treble = s.treble;
555
556
int i = 1;
557
do
558
{
559
fixed_t low_pass = s.low_pass [i];
560
561
fixed_t* echo_end = &echo [echo_size + i];
562
fixed_t const* BLIP_RESTRICT in_pos = &echo [echo_pos + i];
563
blargg_long out_offset = (int)(echo_pos + i + s.delay [i]);
564
if ( out_offset >= echo_size )
565
out_offset -= echo_size;
566
assert( out_offset < echo_size );
567
fixed_t* BLIP_RESTRICT out_pos = &echo [out_offset];
568
569
// break into up to three chunks to avoid having to handle wrap-around
570
// in middle of core loop
571
int remain = pair_count;
572
do
573
{
574
fixed_t const* pos = in_pos;
575
if ( pos < out_pos )
576
pos = out_pos;
577
int count = blargg_ulong ((char*) echo_end - (char const*) pos) /
578
unsigned (stereo * sizeof (fixed_t));
579
if ( count > remain )
580
count = remain;
581
remain -= count;
582
583
in_pos += count * stereo;
584
out_pos += count * stereo;
585
int offset = -count;
586
do
587
{
588
low_pass += FROM_FIXED( in_pos [offset * stereo] - low_pass ) * treble;
589
out_pos [offset * stereo] = FROM_FIXED( low_pass ) * feedback;
590
}
591
while ( ++offset );
592
593
if ( in_pos >= echo_end ) in_pos -= echo_size;
594
if ( out_pos >= echo_end ) out_pos -= echo_size;
595
}
596
while ( remain );
597
598
s.low_pass [i] = low_pass;
599
}
600
while ( --i >= 0 );
601
}
602
}
603
while ( --echo_phase >= 0 );
604
605
// clamp to 16 bits
606
{
607
stereo_fixed_t const* BLIP_RESTRICT in = (stereo_fixed_t*) &echo [echo_pos];
608
typedef blip_sample_t stereo_blip_sample_t [stereo];
609
stereo_blip_sample_t* BLIP_RESTRICT out = (stereo_blip_sample_t*) out_;
610
int count = unsigned (echo_size - echo_pos) / (unsigned) stereo;
611
int remain = pair_count;
612
if ( count > remain )
613
count = remain;
614
do
615
{
616
remain -= count;
617
in += count;
618
out += count;
619
int offset = -count;
620
do
621
{
622
fixed_t in_0 = FROM_FIXED( in [offset] [0] );
623
fixed_t in_1 = FROM_FIXED( in [offset] [1] );
624
625
BLIP_CLAMP( in_0, in_0 );
626
out [offset] [0] = (blip_sample_t) in_0;
627
628
BLIP_CLAMP( in_1, in_1 );
629
out [offset] [1] = (blip_sample_t) in_1;
630
}
631
while ( ++offset );
632
633
in = (stereo_fixed_t*) echo.begin();
634
count = remain;
635
}
636
while ( remain );
637
}
638
}
639
640