1
2 // Nes_Emu 0.7.0. http://www.slack.net/~ant/libs/
3
4 #include "Nes_Buffer.h"
5
6 #include "Nes_Apu.h"
7
8 /* Library Copyright (C) 2003-2006 Shay Green. This library is free software;
9 you can redistribute it and/or modify it under the terms of the GNU Lesser
10 General Public License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version. This
12 module is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
14 A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
15 details. You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
19 #include "blargg_source.h"
20
21 #ifdef BLARGG_ENABLE_OPTIMIZER
22 #include BLARGG_ENABLE_OPTIMIZER
23 #endif
24
25 // Nes_Buffer
26
Nes_Buffer()27 Nes_Buffer::Nes_Buffer() : Multi_Buffer( 1 ) { }
28
~Nes_Buffer()29 Nes_Buffer::~Nes_Buffer() { }
30
set_apu(Nes_Buffer * buf,Nes_Apu * apu)31 Multi_Buffer* set_apu( Nes_Buffer* buf, Nes_Apu* apu )
32 {
33 buf->set_apu( apu );
34 return buf;
35 }
36
enable_nonlinearity(bool b)37 void Nes_Buffer::enable_nonlinearity( bool b )
38 {
39 if ( b )
40 clear();
41
42 Nes_Apu* apu = nonlin.enable( b, &tnd );
43 apu->osc_output( 0, &buf );
44 apu->osc_output( 1, &buf );
45 }
46
set_sample_rate(long rate,int msec)47 const char * Nes_Buffer::set_sample_rate( long rate, int msec )
48 {
49 enable_nonlinearity( nonlin.enabled ); // reapply
50 RETURN_ERR( buf.set_sample_rate( rate, msec ) );
51 RETURN_ERR( tnd.set_sample_rate( rate, msec ) );
52 return Multi_Buffer::set_sample_rate( buf.sample_rate(), buf.length() );
53 }
54
clock_rate(long rate)55 void Nes_Buffer::clock_rate( long rate )
56 {
57 buf.clock_rate( rate );
58 tnd.clock_rate( rate );
59 }
60
bass_freq(int freq)61 void Nes_Buffer::bass_freq( int freq )
62 {
63 buf.bass_freq( freq );
64 tnd.bass_freq( freq );
65 }
66
clear()67 void Nes_Buffer::clear()
68 {
69 nonlin.clear();
70 buf.clear();
71 tnd.clear();
72 }
73
channel(int i)74 Nes_Buffer::channel_t Nes_Buffer::channel( int i )
75 {
76 channel_t c;
77 c.center = &buf;
78 if ( 2 <= i && i <= 4 )
79 c.center = &tnd; // only use for triangle, noise, and dmc
80 c.left = c.center;
81 c.right = c.center;
82 return c;
83 }
84
end_frame(blip_time_t length,bool)85 void Nes_Buffer::end_frame( blip_time_t length, bool )
86 {
87 buf.end_frame( length );
88 tnd.end_frame( length );
89 }
90
samples_avail() const91 long Nes_Buffer::samples_avail() const
92 {
93 return buf.samples_avail();
94 }
95
read_samples(blip_sample_t * out,long count)96 long Nes_Buffer::read_samples( blip_sample_t* out, long count )
97 {
98 count = nonlin.make_nonlinear( tnd, count );
99 if ( count )
100 {
101 Blip_Reader lin;
102 Blip_Reader nonlin;
103
104 int lin_bass = lin.begin( buf );
105 int nonlin_bass = nonlin.begin( tnd );
106
107 if (out != NULL)
108 {
109 for ( int n = count; n--; )
110 {
111 int s = lin.read() + nonlin.read();
112 lin.next( lin_bass );
113 nonlin.next( nonlin_bass );
114 *out++ = s;
115
116 if ( (int16_t) s != s )
117 out [-1] = 0x7FFF - (s >> 24);
118 }
119 }
120 else
121 {
122 //only run accumulators, do not output audio
123 for (int n = count; n--; )
124 {
125 lin.next(lin_bass);
126 nonlin.next(nonlin_bass);
127 }
128 }
129
130 lin.end( buf );
131 nonlin.end( tnd );
132
133 buf.remove_samples( count );
134 tnd.remove_samples( count );
135 }
136
137 return count;
138 }
139
SaveAudioBufferState()140 void Nes_Buffer::SaveAudioBufferState()
141 {
142 SaveAudioBufferStatePrivate();
143 nonlin.SaveAudioBufferState();
144 buf.SaveAudioBufferState();
145 tnd.SaveAudioBufferState();
146 }
147
RestoreAudioBufferState()148 void Nes_Buffer::RestoreAudioBufferState()
149 {
150 RestoreAudioBufferStatePrivate();
151 nonlin.RestoreAudioBufferState();
152 buf.RestoreAudioBufferState();
153 tnd.RestoreAudioBufferState();
154 }
155
156 // Nes_Nonlinearizer
157
Nes_Nonlinearizer()158 Nes_Nonlinearizer::Nes_Nonlinearizer()
159 {
160 apu = NULL;
161 enabled = true;
162
163 float const gain = 0x7fff * 1.3f;
164 // don't use entire range, so any overflow will stay within table
165 int const range = (int) (table_size * Nes_Apu::nonlinear_tnd_gain());
166 for ( int i = 0; i < table_size; i++ )
167 {
168 int const offset = table_size - range;
169 int j = i - offset;
170 float n = 202.0f / (range - 1) * j;
171 float d = 0;
172 // Prevent division by zero
173 if ( n )
174 d = gain * 163.67f / (24329.0f / n + 100.0f);
175 int out = (int) d;
176 table [j & (table_size - 1)] = out;
177 }
178 extra_accum = 0;
179 extra_prev = 0;
180 }
181
enable(bool b,Blip_Buffer * buf)182 Nes_Apu* Nes_Nonlinearizer::enable( bool b, Blip_Buffer* buf )
183 {
184 apu->osc_output( 2, buf );
185 apu->osc_output( 3, buf );
186 apu->osc_output( 4, buf );
187 enabled = b;
188 if ( b )
189 apu->enable_nonlinear( 1.0 );
190 else
191 apu->volume( 1.0 );
192 return apu;
193 }
194
195 #define ENTRY( s ) table [(s) >> (blip_sample_bits - table_bits - 1) & (table_size - 1)]
196
make_nonlinear(Blip_Buffer & buf,long count)197 long Nes_Nonlinearizer::make_nonlinear( Blip_Buffer& buf, long count )
198 {
199 long avail = buf.samples_avail();
200 if ( count > avail )
201 count = avail;
202 if ( count && enabled )
203 {
204
205 Blip_Buffer::buf_t_* p = buf.buffer_;
206 long accum = this->accum;
207 long prev = this->prev;
208 for ( unsigned n = count; n; --n )
209 {
210 long entry = ENTRY( accum );
211 accum += *p;
212 *p++ = (entry - prev) << (blip_sample_bits - 16);
213 prev = entry;
214 }
215
216 this->prev = prev;
217 this->accum = accum;
218 }
219
220 return count;
221 }
222
clear()223 void Nes_Nonlinearizer::clear()
224 {
225 accum = 0;
226 prev = ENTRY( 86016000 ); // avoid thump due to APU's triangle dc bias
227 // TODO: still results in slight clicks and thumps
228 }
229
SaveAudioBufferState()230 void Nes_Nonlinearizer::SaveAudioBufferState()
231 {
232 extra_accum = accum;
233 extra_prev = prev;
234 }
235
RestoreAudioBufferState()236 void Nes_Nonlinearizer::RestoreAudioBufferState()
237 {
238 accum = extra_accum;
239 prev = extra_prev;
240 }
241