Mercurial > audlegacy-plugins
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 |