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