comparison src/Input/console/Track_Emu.cxx @ 0:13389e613d67 trunk

[svn] - initial import of audacious-plugins tree (lots to do)
author nenolod
date Mon, 18 Sep 2006 01:11:49 -0700
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:13389e613d67
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 sync ( 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 long Track_Emu::tell() const
69 {
70 long rate = emu->sample_rate() * stereo;
71 return (out_time / rate * 1000) + (out_time % rate * 1000 / rate);
72 }
73
74 void Track_Emu::start_track( Music_Emu* e, int t, long length, bool ds )
75 {
76 // to do: remove
77 //length = 50 * 1000;
78 //ds = true;
79 //t = 23;
80
81 emu = e;
82 track = t;
83 detect_silence = ds;
84 fade_factor = pow( 0.005, 1.0 / msec_to_samples( fade_length ) );
85 fade_time = msec_to_samples( length );
86 restart_track();
87 }
88
89 static bool is_silence( const Music_Emu::sample_t* p, int count )
90 {
91 while ( count-- )
92 {
93 if ( (unsigned) (*p++ + silence_threshold / 2) > (unsigned) silence_threshold )
94 return false;
95 }
96 return true;
97 }
98
99 void Track_Emu::fill_buf( bool check_silence )
100 {
101 emu->play( buf_size, buf );
102 emu_time += buf_size;
103 if ( (check_silence || emu_time > fade_time) && is_silence( buf, buf_size ) )
104 {
105 silence_count += buf_size;
106 }
107 else
108 {
109 silence_time = emu_time;
110 buf_count = buf_size;
111 }
112 if ( emu->track_ended() || emu->error_count() )
113 track_ended = true;
114 }
115
116 inline void Track_Emu::end_track()
117 {
118 silence_count = 0;
119 buf_count = 0;
120 track_ended = true;
121 }
122
123 bool Track_Emu::play( int out_count, Music_Emu::sample_t* out )
124 {
125 assert( out_count % 2 == 0 );
126 assert( emu );
127
128 int pos = 0;
129 while ( pos < out_count )
130 {
131 // fill with any remaining silence
132 int count = min( silence_count, out_count - pos );
133 if ( count )
134 {
135 silence_count -= count;
136 memset( &out [pos], 0, count * sizeof *out );
137 }
138 else
139 {
140 // empty internal buffer
141 count = min( buf_count, out_count - pos );
142 if ( !count && track_ended )
143 {
144 memset( &out [pos], 0, (out_count - pos) * sizeof *out );
145 return true;
146 }
147
148 memcpy( &out [pos], &buf [buf_size - buf_count], count * sizeof *out );
149 buf_count -= count;
150 }
151 pos += count;
152
153 // keep internal buffer full and possibly run ahead
154 for ( int n = 6; n--; )
155 {
156 if ( buf_count || track_ended ||
157 emu_time - out_time > silence_max * stereo * emu->sample_rate() )
158 break;
159 fill_buf( detect_silence );
160 }
161 }
162 out_time += out_count;
163
164 if ( detect_silence &&
165 ( emu_time - silence_time > silence_max * stereo * emu->sample_rate() && silence_time ) )
166 end_track();
167
168 // fade if track is ending
169 if ( out_time > fade_time )
170 {
171 for ( int i = 0; i < out_count; i += fade_block_size )
172 {
173 double gain = pow( fade_factor, (double) (out_time + i - fade_time) );
174 if ( gain < 0.005 )
175 end_track();
176
177 int count = min( fade_block_size, out_count - i );
178 int igain = (unsigned int)((double)gain * (1 << 15));;
179 for ( int j = 0; j < count; j++ )
180 out [i + j] = (out [i + j] * igain) >> 15;
181 }
182 }
183
184 return !silence_count && !buf_count && track_ended;
185 }
186