Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/genplus-gx/core/sound/sound.c
2 views
1
/***************************************************************************************
2
* Genesis Plus
3
* Sound Hardware
4
*
5
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Charles Mac Donald (original code)
6
* Copyright (C) 2007-2013 Eke-Eke (Genesis Plus GX)
7
*
8
* Redistribution and use of this code or any derivative works are permitted
9
* provided that the following conditions are met:
10
*
11
* - Redistributions may not be sold, nor may they be used in a commercial
12
* product or activity.
13
*
14
* - Redistributions that are modified from the original source must include the
15
* complete source code, including the source code for all components used by a
16
* binary built from the modified sources. However, as a special exception, the
17
* source code distributed need not include anything that is normally distributed
18
* (in either source or binary form) with the major components (compiler, kernel,
19
* and so on) of the operating system on which the executable runs, unless that
20
* component itself accompanies the executable.
21
*
22
* - Redistributions must reproduce the above copyright notice, this list of
23
* conditions and the following disclaimer in the documentation and/or other
24
* materials provided with the distribution.
25
*
26
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
30
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36
* POSSIBILITY OF SUCH DAMAGE.
37
*
38
****************************************************************************************/
39
40
#include "shared.h"
41
#include "blip_buf.h"
42
43
/* FM output buffer (large enough to hold a whole frame at original chips rate) */
44
int fm_buffer[1080 * 2];
45
int fm_last[2];
46
int *fm_ptr;
47
48
/* Cycle-accurate FM samples */
49
uint32 fm_cycles_ratio;
50
uint32 fm_cycles_start;
51
uint32 fm_cycles_count;
52
53
/* YM chip function pointers */
54
void (*YM_Reset)(void);
55
void (*YM_Update)(int *buffer, int length);
56
void (*YM_Write)(unsigned int a, unsigned int v);
57
58
/* Run FM chip until required M-cycles */
59
INLINE void fm_update(unsigned int cycles)
60
{
61
if (cycles > fm_cycles_count)
62
{
63
/* number of samples to run */
64
unsigned int samples = (cycles - fm_cycles_count + fm_cycles_ratio - 1) / fm_cycles_ratio;
65
66
/* run FM chip to sample buffer */
67
YM_Update(fm_ptr, samples);
68
69
/* update FM buffer pointer */
70
fm_ptr += (samples << 1);
71
72
/* update FM cycle counter */
73
fm_cycles_count += samples * fm_cycles_ratio;
74
}
75
}
76
77
void sound_init( void )
78
{
79
/* Initialize FM chip */
80
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
81
{
82
/* YM2612 */
83
YM2612Init();
84
YM2612Config(config.dac_bits);
85
YM_Reset = YM2612ResetChip;
86
YM_Update = YM2612Update;
87
YM_Write = YM2612Write;
88
89
/* chip is running a VCLK / 144 = MCLK / 7 / 144 */
90
fm_cycles_ratio = 144 * 7;
91
}
92
else
93
{
94
/* YM2413 */
95
YM2413Init();
96
YM_Reset = YM2413ResetChip;
97
YM_Update = YM2413Update;
98
YM_Write = YM2413Write;
99
100
/* chip is running a ZCLK / 72 = MCLK / 15 / 72 */
101
fm_cycles_ratio = 72 * 15;
102
}
103
104
/* Initialize PSG chip */
105
SN76489_Config(0, config.psg_preamp, config.psgBoostNoise, 0xff);
106
}
107
108
void sound_reset(void)
109
{
110
/* reset sound chips */
111
YM_Reset();
112
SN76489_Reset();
113
114
/* reset FM buffer ouput */
115
fm_last[0] = fm_last[1] = 0;
116
117
/* reset FM buffer pointer */
118
fm_ptr = fm_buffer;
119
120
/* reset FM cycle counters */
121
fm_cycles_start = fm_cycles_count = 0;
122
}
123
124
int sound_update(unsigned int cycles)
125
{
126
int delta, preamp, time, l, r, *ptr;
127
128
/* Run PSG & FM chips until end of frame */
129
SN76489_Update(cycles);
130
fm_update(cycles);
131
132
/* FM output pre-amplification */
133
preamp = config.fm_preamp;
134
135
/* FM frame initial timestamp */
136
time = fm_cycles_start;
137
138
/* Restore last FM outputs from previous frame */
139
l = fm_last[0];
140
r = fm_last[1];
141
142
/* FM buffer start pointer */
143
ptr = fm_buffer;
144
145
/* flush FM samples */
146
if (config.hq_fm)
147
{
148
/* high-quality Band-Limited synthesis */
149
do
150
{
151
/* left channel */
152
delta = ((*ptr++ * preamp) / 100) - l;
153
l += delta;
154
blip_add_delta(snd.blips[0][0], time, delta);
155
156
/* right channel */
157
delta = ((*ptr++ * preamp) / 100) - r;
158
r += delta;
159
blip_add_delta(snd.blips[0][1], time, delta);
160
161
/* increment time counter */
162
time += fm_cycles_ratio;
163
}
164
while (time < cycles);
165
}
166
else
167
{
168
/* faster Linear Interpolation */
169
do
170
{
171
/* left channel */
172
delta = ((*ptr++ * preamp) / 100) - l;
173
l += delta;
174
blip_add_delta_fast(snd.blips[0][0], time, delta);
175
176
/* right channel */
177
delta = ((*ptr++ * preamp) / 100) - r;
178
r += delta;
179
blip_add_delta_fast(snd.blips[0][1], time, delta);
180
181
/* increment time counter */
182
time += fm_cycles_ratio;
183
}
184
while (time < cycles);
185
}
186
187
/* reset FM buffer pointer */
188
fm_ptr = fm_buffer;
189
190
/* save last FM output for next frame */
191
fm_last[0] = l;
192
fm_last[1] = r;
193
194
/* adjust FM cycle counters for next frame */
195
fm_cycles_count = fm_cycles_start = time - cycles;
196
197
/* end of blip buffers time frame */
198
blip_end_frame(snd.blips[0][0], cycles);
199
blip_end_frame(snd.blips[0][1], cycles);
200
201
/* return number of available samples */
202
return blip_samples_avail(snd.blips[0][0]);
203
}
204
205
int sound_context_save(uint8 *state)
206
{
207
int bufferptr = 0;
208
209
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
210
{
211
bufferptr = YM2612SaveContext(state);
212
}
213
else
214
{
215
save_param(YM2413GetContextPtr(),YM2413GetContextSize());
216
}
217
218
save_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
219
220
save_param(&fm_cycles_start,sizeof(fm_cycles_start));
221
222
return bufferptr;
223
}
224
225
int sound_context_load(uint8 *state)
226
{
227
int bufferptr = 0;
228
229
if ((system_hw & SYSTEM_PBC) == SYSTEM_MD)
230
{
231
bufferptr = YM2612LoadContext(state);
232
YM2612Config(config.dac_bits);
233
}
234
else
235
{
236
load_param(YM2413GetContextPtr(),YM2413GetContextSize());
237
}
238
239
load_param(SN76489_GetContextPtr(),SN76489_GetContextSize());
240
241
load_param(&fm_cycles_start,sizeof(fm_cycles_start));
242
fm_cycles_count = fm_cycles_start;
243
244
return bufferptr;
245
}
246
247
void fm_reset(unsigned int cycles)
248
{
249
/* synchronize FM chip with CPU */
250
fm_update(cycles);
251
252
/* reset FM chip */
253
YM_Reset();
254
}
255
256
void fm_write(unsigned int cycles, unsigned int address, unsigned int data)
257
{
258
/* synchronize FM chip with CPU (on data port write only) */
259
if (address & 1)
260
{
261
fm_update(cycles);
262
}
263
264
/* write FM register */
265
YM_Write(address, data);
266
}
267
268
unsigned int fm_read(unsigned int cycles, unsigned int address)
269
{
270
/* synchronize FM chip with CPU */
271
fm_update(cycles);
272
273
/* read FM status (YM2612 only) */
274
return YM2612Read();
275
}
276
277