diff options
Diffstat (limited to 'apps/codecs/libgme/nes_vrc6_apu.c')
-rw-r--r-- | apps/codecs/libgme/nes_vrc6_apu.c | 191 |
1 files changed, 191 insertions, 0 deletions
diff --git a/apps/codecs/libgme/nes_vrc6_apu.c b/apps/codecs/libgme/nes_vrc6_apu.c new file mode 100644 index 0000000000..0aba81e57f --- /dev/null +++ b/apps/codecs/libgme/nes_vrc6_apu.c | |||
@@ -0,0 +1,191 @@ | |||
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, 1.0 ); | ||
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 | 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 | Blip_set_modified( output ); | ||
87 | |||
88 | int volume = osc->regs [0] & 15; | ||
89 | if ( !(osc->regs [2] & 0x80) ) | ||
90 | volume = 0; | ||
91 | |||
92 | int gate = osc->regs [0] & 0x80; | ||
93 | int duty = ((osc->regs [0] >> 4) & 7) + 1; | ||
94 | int delta = ((gate || osc->phase < duty) ? volume : 0) - osc->last_amp; | ||
95 | blip_time_t time = this->last_time; | ||
96 | if ( delta ) | ||
97 | { | ||
98 | osc->last_amp += delta; | ||
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 | |||
111 | do | ||
112 | { | ||
113 | phase++; | ||
114 | if ( phase == 16 ) | ||
115 | { | ||
116 | phase = 0; | ||
117 | osc->last_amp = volume; | ||
118 | Synth_offset( &this->square_synth, time, volume, output ); | ||
119 | } | ||
120 | if ( phase == duty ) | ||
121 | { | ||
122 | osc->last_amp = 0; | ||
123 | Synth_offset( &this->square_synth, time, -volume, output ); | ||
124 | } | ||
125 | time += period; | ||
126 | } | ||
127 | while ( time < end_time ); | ||
128 | |||
129 | osc->phase = phase; | ||
130 | } | ||
131 | osc->delay = time - end_time; | ||
132 | } | ||
133 | } | ||
134 | |||
135 | void run_saw( struct Nes_Vrc6_Apu* this, blip_time_t end_time ) | ||
136 | { | ||
137 | struct Vrc6_Osc* osc = &this->oscs [2]; | ||
138 | struct Blip_Buffer* output = osc->output; | ||
139 | if ( !output ) | ||
140 | return; | ||
141 | Blip_set_modified( output ); | ||
142 | |||
143 | int amp = osc->amp; | ||
144 | int amp_step = osc->regs [0] & 0x3F; | ||
145 | blip_time_t time = this->last_time; | ||
146 | int last_amp = osc->last_amp; | ||
147 | if ( !(osc->regs [2] & 0x80) || !(amp_step | amp) ) | ||
148 | { | ||
149 | osc->delay = 0; | ||
150 | int delta = (amp >> 3) - last_amp; | ||
151 | last_amp = amp >> 3; | ||
152 | Synth_offset( &this->saw_synth, time, delta, output ); | ||
153 | } | ||
154 | else | ||
155 | { | ||
156 | time += osc->delay; | ||
157 | if ( time < end_time ) | ||
158 | { | ||
159 | int period = Vrc6_osc_period( osc ) * 2; | ||
160 | int phase = osc->phase; | ||
161 | |||
162 | do | ||
163 | { | ||
164 | if ( --phase == 0 ) | ||
165 | { | ||
166 | phase = 7; | ||
167 | amp = 0; | ||
168 | } | ||
169 | |||
170 | int delta = (amp >> 3) - last_amp; | ||
171 | if ( delta ) | ||
172 | { | ||
173 | last_amp = amp >> 3; | ||
174 | Synth_offset( &this->saw_synth, time, delta, output ); | ||
175 | } | ||
176 | |||
177 | time += period; | ||
178 | amp = (amp + amp_step) & 0xFF; | ||
179 | } | ||
180 | while ( time < end_time ); | ||
181 | |||
182 | osc->phase = phase; | ||
183 | osc->amp = amp; | ||
184 | } | ||
185 | |||
186 | osc->delay = time - end_time; | ||
187 | } | ||
188 | |||
189 | osc->last_amp = last_amp; | ||
190 | } | ||
191 | |||