comparison Plugins/Input/console/Track_Emu.cpp @ 493:c04dff121e1d trunk

[svn] hostile merge, phase 2: reimport based on new plugin code
author nenolod
date Tue, 24 Jan 2006 20:19:01 -0800
parents
children a371216b5c8a
comparison
equal deleted inserted replaced
492:ccb68bad47b2 493:c04dff121e1d
1
2 // Game_Music_Emu 0.3.0. http://www.slack.net/~ant/
3
4 #include "Track_Emu.h"
5
6 #include <string.h>
7 #include <math.h>
8
9 /* Copyright (C) 2005-2006 Shay Green. This module is free software; you
10 can redistribute it and/or modify it under the terms of the GNU Lesser
11 General Public License as published by the Free Software Foundation; either
12 version 2.1 of the License, or (at your option) any later version. This
13 module is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
16 more details. You should have received a copy of the GNU Lesser General
17 Public License along with this module; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
19
20 #include BLARGG_SOURCE_BEGIN
21
22 int const stereo = 2; // channels for a stereo signal
23 int const fade_block_size = 512;
24 int const fade_length = 8000; // msec
25 int const silence_max = 6; // seconds
26 int const silence_threshold = 0x10;
27
28 long Track_Emu::msec_to_samples( long msec ) const
29 {
30 long rate = emu->sample_rate() * stereo;
31 return (msec / 1000L) * rate + (msec % 1000L) * rate / 1000;
32 }
33
34 void Track_Emu::sync( long time )
35 {
36 buf_count = 0;
37 silence_count = 0;
38 emu_time = time;
39 out_time = time;
40 silence_time = time;
41 track_ended = time > fade_time + fade_length * stereo * emu->sample_rate();
42 }
43
44 void Track_Emu::restart_track()
45 {
46 emu->start_track( track );
47 emu_time = 0;
48
49 // skip initial silence
50 for ( int n = 40 * stereo * emu->sample_rate() / buf_size; n--; )
51 {
52 fill_buf( true );
53 if ( buf_count || track_ended )
54 break;
55 }
56 sync( 0 );
57 }
58
59 void Track_Emu::seek( long time )
60 {
61 long pos = msec_to_samples( time ) & ~1;
62 if ( pos < out_time )
63 restart_track();
64 emu->skip( pos - emu_time );
65 sync( pos );
66 }
67
68 void Track_Emu::start_track( Music_Emu* e, int t, long length, bool ds )
69 {
70 // to do: remove
71 //length = 50 * 1000;
72 //ds = true;
73 //t = 23;
74
75 emu = e;
76 track = t;
77 detect_silence = ds;
78 fade_factor = pow( 0.005, 1.0 / msec_to_samples( fade_length ) );
79 fade_time = msec_to_samples( length );
80 restart_track();
81 }
82
83 static bool is_silence( const Music_Emu::sample_t* p, int count )
84 {
85 while ( count-- )
86 {
87 if ( (unsigned) (*p++ + silence_threshold / 2) > (unsigned) silence_threshold )
88 return false;
89 }
90 return true;
91 }
92
93 void Track_Emu::fill_buf( bool check_silence )
94 {
95 if ( !buf_count && !track_ended &&
96 emu_time - out_time < silence_max * stereo * emu->sample_rate() )
97 {
98 emu->play( buf_size, buf );
99 emu_time += buf_size;
100 if ( (check_silence || emu_time > fade_time) && is_silence( buf, buf_size ) )
101 {
102 silence_count += buf_size;
103 }
104 else
105 {
106 silence_time = emu_time;
107 buf_count = buf_size;
108 }
109 if ( emu->track_ended() || emu->error_count() )
110 track_ended = true;
111 }
112 }
113
114 inline void Track_Emu::end_track()
115 {
116 silence_count = 0;
117 buf_count = 0;
118 track_ended = true;
119 }
120
121 bool Track_Emu::play( int out_count, Music_Emu::sample_t* out )
122 {
123 assert( out_count % 2 == 0 );
124 assert( emu );
125
126 int pos = 0;
127 while ( pos < out_count )
128 {
129 // fill with any remaining silence
130 int count = min( silence_count, out_count - pos );
131 if ( count )
132 {
133 silence_count -= count;
134 memset( &out [pos], 0, count * sizeof *out );
135 }
136 else
137 {
138 // empty internal buffer
139 count = min( buf_count, out_count - pos );
140 if ( !count && track_ended )
141 {
142 memset( &out [pos], 0, (out_count - pos) * sizeof *out );
143 return true;
144 }
145
146 memcpy( &out [pos], &buf [buf_size - buf_count], count * sizeof *out );
147 buf_count -= count;
148 }
149 pos += count;
150
151 // keep internal buffer full and possibly run ahead
152 for ( int n = 6; n--; )
153 fill_buf( detect_silence );
154 }
155 out_time += out_count;
156
157 if ( emu_time - silence_time > silence_max * stereo * emu->sample_rate() && silence_time )
158 end_track();
159
160 // fade if track is ending
161 if ( out_time > fade_time )
162 {
163 for ( int i = 0; i < out_count; i += fade_block_size )
164 {
165 double gain = pow( fade_factor, (double) (out_time + i - fade_time) );
166 if ( gain < 0.005 )
167 end_track();
168
169 int count = min( fade_block_size, out_count - i );
170 int igain = gain * (1 << 15);
171 for ( int j = 0; j < count; j++ )
172 out [i + j] = (out [i + j] * igain) >> 15;
173 }
174 }
175
176 return !silence_count && !buf_count && track_ended;
177 }
178