1
2// Nes_Snd_Emu 0.1.7. http://www.slack.net/~ant/libs/
3
4#include "Nes_Vrc6.h"
5
6/* Copyright (C) 2003-2005 Shay Green. This module is free software; you
7can redistribute it and/or modify it under the terms of the GNU Lesser
8General Public License as published by the Free Software Foundation; either
9version 2.1 of the License, or (at your option) any later version. This
10module is distributed in the hope that it will be useful, but WITHOUT ANY
11WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
13more details. You should have received a copy of the GNU Lesser General
14Public License along with this module; if not, write to the Free Software
15Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
17#include BLARGG_SOURCE_BEGIN
18
19Nes_Vrc6::Nes_Vrc6()
20{
21 output( NULL );
22 volume( 1.0 );
23 reset();
24}
25
26Nes_Vrc6::~Nes_Vrc6()
27{
28}
29
30void Nes_Vrc6::reset()
31{
32 last_time = 0;
33 for ( int i = 0; i < osc_count; i++ )
34 {
35 Vrc6_Osc& osc = oscs [i];
36 for ( int j = 0; j < reg_count; j++ )
37 osc.regs [j] = 0;
38 osc.delay = 0;
39 osc.last_amp = 0;
40 osc.phase = 1;
41 osc.amp = 0;
42 }
43}
44
45void Nes_Vrc6::volume( double v )
46{
47 v *= 0.0967 * 2;
48 saw_synth.volume( v );
49 square_synth.volume( v * 0.5 );
50}
51
52void Nes_Vrc6::treble_eq( blip_eq_t const& eq )
53{
54 saw_synth.treble_eq( eq );
55 square_synth.treble_eq( eq );
56}
57
58void Nes_Vrc6::output( Blip_Buffer* buf )
59{
60 for ( int i = 0; i < osc_count; i++ )
61 osc_output( i, buf );
62}
63
64void Nes_Vrc6::run_until( cpu_time_t time )
65{
66 require( time >= last_time );
67 run_square( oscs [0], time );
68 run_square( oscs [1], time );
69 run_saw( time );
70 last_time = time;
71}
72
73void Nes_Vrc6::write_osc( cpu_time_t time, int osc_index, int reg, int data )
74{
75 require( (unsigned) osc_index < osc_count );
76 require( (unsigned) reg < reg_count );
77
78 run_until( time );
79 oscs [osc_index].regs [reg] = data;
80}
81
82void Nes_Vrc6::end_frame( cpu_time_t time )
83{
84 if ( time > last_time )
85 run_until( time );
86 last_time -= time;
87 assert( last_time >= 0 );
88}
89
90void Nes_Vrc6::save_snapshot( vrc6_snapshot_t* out ) const
91{
92 out->saw_amp = oscs [2].amp;
93 for ( int i = 0; i < osc_count; i++ )
94 {
95 Vrc6_Osc const& osc = oscs [i];
96 for ( int r = 0; r < reg_count; r++ )
97 out->regs [i] [r] = osc.regs [r];
98
99 out->delays [i] = osc.delay;
100 out->phases [i] = osc.phase;
101 }
102}
103
104void Nes_Vrc6::load_snapshot( vrc6_snapshot_t const& in )
105{
106 reset();
107 oscs [2].amp = in.saw_amp;
108 for ( int i = 0; i < osc_count; i++ )
109 {
110 Vrc6_Osc& osc = oscs [i];
111 for ( int r = 0; r < reg_count; r++ )
112 osc.regs [r] = in.regs [i] [r];
113
114 osc.delay = in.delays [i];
115 osc.phase = in.phases [i];
116 }
117 if ( !oscs [2].phase )
118 oscs [2].phase = 1;
119}
120
121#include BLARGG_ENABLE_OPTIMIZER
122
123void Nes_Vrc6::run_square( Vrc6_Osc& osc, cpu_time_t end_time )
124{
125 Blip_Buffer* output = osc.output;
126 if ( !output )
127 return;
128
129 int volume = osc.regs [0] & 15;
130 if ( !(osc.regs [2] & 0x80) )
131 volume = 0;
132
133 int gate = osc.regs [0] & 0x80;
134 int duty = ((osc.regs [0] >> 4) & 7) + 1;
135 int delta = ((gate || osc.phase < duty) ? volume : 0) - osc.last_amp;
136 cpu_time_t time = last_time;
137 if ( delta )
138 {
139 osc.last_amp += delta;
140 square_synth.offset( time, delta, output );
141 }
142
143 time += osc.delay;
144 osc.delay = 0;
145 int period = osc.period();
146 if ( volume && !gate && period > 4 )
147 {
148 if ( time < end_time )
149 {
150 int phase = osc.phase;
151
152 do
153 {
154 phase++;
155 if ( phase == 16 )
156 {
157 phase = 0;
158 osc.last_amp = volume;
159 square_synth.offset( time, volume, output );
160 }
161 if ( phase == duty )
162 {
163 osc.last_amp = 0;
164 square_synth.offset( time, -volume, output );
165 }
166 time += period;
167 }
168 while ( time < end_time );
169
170 osc.phase = phase;
171 }
172 osc.delay = time - end_time;
173 }
174}
175
176void Nes_Vrc6::run_saw( cpu_time_t end_time )
177{
178 Vrc6_Osc& osc = oscs [2];
179 Blip_Buffer* output = osc.output;
180 if ( !output )
181 return;
182
183 int amp = osc.amp;
184 int amp_step = osc.regs [0] & 0x3F;
185 cpu_time_t time = last_time;
186 int last_amp = osc.last_amp;
187 if ( !(osc.regs [2] & 0x80) || !(amp_step | amp) )
188 {
189 osc.delay = 0;
190 int delta = (amp >> 3) - last_amp;
191 last_amp = amp >> 3;
192 saw_synth.offset( time, delta, output );
193 }
194 else
195 {
196 time += osc.delay;
197 if ( time < end_time )
198 {
199 int period = osc.period() * 2;
200 int phase = osc.phase;
201
202 do
203 {
204 if ( --phase == 0 )
205 {
206 phase = 7;
207 amp = 0;
208 }
209
210 int delta = (amp >> 3) - last_amp;
211 if ( delta )
212 {
213 last_amp = amp >> 3;
214 saw_synth.offset( time, delta, output );
215 }
216
217 time += period;
218 amp = (amp + amp_step) & 0xFF;
219 }
220 while ( time < end_time );
221
222 osc.phase = phase;
223 osc.amp = amp;
224 }
225
226 osc.delay = time - end_time;
227 }
228
229 osc.last_amp = last_amp;
230}
231
232