diff options
Diffstat (limited to 'lib/rbcodec/codecs/libgme/nes_vrc6_apu.c')
-rw-r--r-- | lib/rbcodec/codecs/libgme/nes_vrc6_apu.c | 192 |
1 files changed, 192 insertions, 0 deletions
diff --git a/lib/rbcodec/codecs/libgme/nes_vrc6_apu.c b/lib/rbcodec/codecs/libgme/nes_vrc6_apu.c new file mode 100644 index 0000000000..99a9ae3fed --- /dev/null +++ b/lib/rbcodec/codecs/libgme/nes_vrc6_apu.c | |||
@@ -0,0 +1,192 @@ | |||
1 | // Nes_Snd_Emu 0.1.8. http://www.slack.net/~ant/ | ||
2 | |||
3 | #include "nes_vrc6_apu.h" | ||
4 | |||
5 | /* Copyright (C) 2003-2006 Shay Green. This module is free software; you | ||
6 | can redistribute it and/or modify it under the terms of the GNU Lesser | ||
7 | General Public License as published by the Free Software Foundation; either | ||
8 | version 2.1 of the License, or (at your option) any later version. This | ||
9 | module is distributed in the hope that it will be useful, but WITHOUT ANY | ||
10 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS | ||
11 | FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more | ||
12 | details. You should have received a copy of the GNU Lesser General Public | ||
13 | License along with this module; if not, write to the Free Software Foundation, | ||
14 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ | ||
15 | |||
16 | #include "blargg_source.h" | ||
17 | |||
18 | void Vrc6_init( struct Nes_Vrc6_Apu* this ) | ||
19 | { | ||
20 | Synth_init( &this->saw_synth ); | ||
21 | Synth_init( &this->square_synth ); | ||
22 | |||
23 | Vrc6_output( this, NULL ); | ||
24 | Vrc6_volume( this, (int)FP_ONE_VOLUME ); | ||
25 | Vrc6_reset( this ); | ||
26 | } | ||
27 | |||
28 | void Vrc6_reset( struct Nes_Vrc6_Apu* this ) | ||
29 | { | ||
30 | this->last_time = 0; | ||
31 | int i; | ||
32 | for ( i = 0; i < vrc6_osc_count; i++ ) | ||
33 | { | ||
34 | struct Vrc6_Osc* osc = &this->oscs [i]; | ||
35 | int j; | ||
36 | for ( j = 0; j < vrc6_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 Vrc6_output( struct Nes_Vrc6_Apu* this, struct Blip_Buffer* buf ) | ||
46 | { | ||
47 | int i; | ||
48 | for ( i = 0; i < vrc6_osc_count; i++ ) | ||
49 | Vrc6_osc_output( this, i, buf ); | ||
50 | } | ||
51 | |||
52 | void run_square( struct Nes_Vrc6_Apu* this, struct Vrc6_Osc* osc, blip_time_t end_time ); | ||
53 | void run_saw( struct Nes_Vrc6_Apu* this, blip_time_t end_time ); | ||
54 | static void Vrc6_run_until( struct Nes_Vrc6_Apu* this, blip_time_t time ) | ||
55 | { | ||
56 | require( time >= this->last_time ); | ||
57 | run_square( this, &this->oscs [0], time ); | ||
58 | run_square( this, &this->oscs [1], time ); | ||
59 | run_saw( this, time ); | ||
60 | this->last_time = time; | ||
61 | } | ||
62 | |||
63 | void Vrc6_write_osc( struct Nes_Vrc6_Apu* this, blip_time_t time, int osc_index, int reg, int data ) | ||
64 | { | ||
65 | require( (unsigned) osc_index < vrc6_osc_count ); | ||
66 | require( (unsigned) reg < vrc6_reg_count ); | ||
67 | |||
68 | Vrc6_run_until( this, time ); | ||
69 | this->oscs [osc_index].regs [reg] = data; | ||
70 | } | ||
71 | |||
72 | void Vrc6_end_frame( struct Nes_Vrc6_Apu* this, blip_time_t time ) | ||
73 | { | ||
74 | if ( time > this->last_time ) | ||
75 | Vrc6_run_until( this, time ); | ||
76 | |||
77 | assert( this->last_time >= time ); | ||
78 | this->last_time -= time; | ||
79 | } | ||
80 | |||
81 | void run_square( struct Nes_Vrc6_Apu* this, struct Vrc6_Osc* osc, blip_time_t end_time ) | ||
82 | { | ||
83 | struct Blip_Buffer* output = osc->output; | ||
84 | if ( !output ) | ||
85 | return; | ||
86 | |||
87 | int volume = osc->regs [0] & 15; | ||
88 | if ( !(osc->regs [2] & 0x80) ) | ||
89 | volume = 0; | ||
90 | |||
91 | int gate = osc->regs [0] & 0x80; | ||
92 | int duty = ((osc->regs [0] >> 4) & 7) + 1; | ||
93 | int delta = ((gate || osc->phase < duty) ? volume : 0) - osc->last_amp; | ||
94 | blip_time_t time = this->last_time; | ||
95 | if ( delta ) | ||
96 | { | ||
97 | osc->last_amp += delta; | ||
98 | Blip_set_modified( output ); | ||
99 | Synth_offset( &this->square_synth, time, delta, output ); | ||
100 | } | ||
101 | |||
102 | time += osc->delay; | ||
103 | osc->delay = 0; | ||
104 | int period = Vrc6_osc_period( osc ); | ||
105 | if ( volume && !gate && period > 4 ) | ||
106 | { | ||
107 | if ( time < end_time ) | ||
108 | { | ||
109 | int phase = osc->phase; | ||
110 | Blip_set_modified( output ); | ||
111 | |||
112 | do | ||
113 | { | ||
114 | phase++; | ||
115 | if ( phase == 16 ) | ||
116 | { | ||
117 | phase = 0; | ||
118 | osc->last_amp = volume; | ||
119 | Synth_offset( &this->square_synth, time, volume, output ); | ||
120 | } | ||
121 | if ( phase == duty ) | ||
122 | { | ||
123 | osc->last_amp = 0; | ||
124 | Synth_offset( &this->square_synth, time, -volume, output ); | ||
125 | } | ||
126 | time += period; | ||
127 | } | ||
128 | while ( time < end_time ); | ||
129 | |||
130 | osc->phase = phase; | ||
131 | } | ||
132 | osc->delay = time - end_time; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | void run_saw( struct Nes_Vrc6_Apu* this, blip_time_t end_time ) | ||
137 | { | ||
138 | struct Vrc6_Osc* osc = &this->oscs [2]; | ||
139 | struct Blip_Buffer* output = osc->output; | ||
140 | if ( !output ) | ||
141 | return; | ||
142 | Blip_set_modified( output ); | ||
143 | |||
144 | int amp = osc->amp; | ||
145 | int amp_step = osc->regs [0] & 0x3F; | ||
146 | blip_time_t time = this->last_time; | ||
147 | int last_amp = osc->last_amp; | ||
148 | if ( !(osc->regs [2] & 0x80) || !(amp_step | amp) ) | ||
149 | { | ||
150 | osc->delay = 0; | ||
151 | int delta = (amp >> 3) - last_amp; | ||
152 | last_amp = amp >> 3; | ||
153 | Synth_offset( &this->saw_synth, time, delta, output ); | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | time += osc->delay; | ||
158 | if ( time < end_time ) | ||
159 | { | ||
160 | int period = Vrc6_osc_period( osc ) * 2; | ||
161 | int phase = osc->phase; | ||
162 | |||
163 | do | ||
164 | { | ||
165 | if ( --phase == 0 ) | ||
166 | { | ||
167 | phase = 7; | ||
168 | amp = 0; | ||
169 | } | ||
170 | |||
171 | int delta = (amp >> 3) - last_amp; | ||
172 | if ( delta ) | ||
173 | { | ||
174 | last_amp = amp >> 3; | ||
175 | Synth_offset( &this->saw_synth, time, delta, output ); | ||
176 | } | ||
177 | |||
178 | time += period; | ||
179 | amp = (amp + amp_step) & 0xFF; | ||
180 | } | ||
181 | while ( time < end_time ); | ||
182 | |||
183 | osc->phase = phase; | ||
184 | osc->amp = amp; | ||
185 | } | ||
186 | |||
187 | osc->delay = time - end_time; | ||
188 | } | ||
189 | |||
190 | osc->last_amp = last_amp; | ||
191 | } | ||
192 | |||