integrate M-HT's neon scalers
[gpsp.git] / sound.h
CommitLineData
2823a4c8 1/* gameplaySP
2 *
3 * Copyright (C) 2006 Exophase <exophase@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of
8 * the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20#ifndef SOUND_H
21#define SOUND_H
22
23#define BUFFER_SIZE 65536
24
2f1c528a 25#define GBA_XTAL 16777216.0f
26#define GBA_60HZ_RATE 16853760.0f /* 228*(272+960)*60 */
2823a4c8 27
2f1c528a 28#if !defined(PSP_BUILD) && !defined(WIZ_BUILD)
29 // run GBA at 60Hz (~0.5% faster) to better match host display
30 #define GBC_BASE_RATE GBA_60HZ_RATE
2823a4c8 31#else
2f1c528a 32 #define GBC_BASE_RATE GBA_XTAL
2823a4c8 33#endif
34
35typedef enum
36{
37 DIRECT_SOUND_INACTIVE,
38 DIRECT_SOUND_RIGHT,
39 DIRECT_SOUND_LEFT,
40 DIRECT_SOUND_LEFTRIGHT
41} direct_sound_status_type;
42
43typedef enum
44{
45 DIRECT_SOUND_VOLUME_50,
46 DIRECT_SOUND_VOLUME_100
47} direct_sound_volume_type;
48
49typedef struct
50{
51 s8 fifo[32];
52 u32 fifo_base;
53 u32 fifo_top;
2f1c528a 54 fixed8_24 fifo_fractional;
2823a4c8 55 // The + 1 is to give some extra room for linear interpolation
56 // when wrapping around.
57 u32 buffer_index;
58 direct_sound_status_type status;
59 direct_sound_volume_type volume;
60 u32 last_cpu_ticks;
61} direct_sound_struct;
62
63typedef enum
64{
65 GBC_SOUND_INACTIVE,
66 GBC_SOUND_RIGHT,
67 GBC_SOUND_LEFT,
68 GBC_SOUND_LEFTRIGHT
69} gbc_sound_status_type;
70
71
72typedef struct
73{
74 u32 rate;
75 fixed16_16 frequency_step;
76 fixed16_16 sample_index;
77 fixed16_16 tick_counter;
78 u32 total_volume;
79 u32 envelope_initial_volume;
80 u32 envelope_volume;
81 u32 envelope_direction;
82 u32 envelope_status;
83 u32 envelope_step;
84 u32 envelope_ticks;
85 u32 envelope_initial_ticks;
86 u32 sweep_status;
87 u32 sweep_direction;
88 u32 sweep_ticks;
89 u32 sweep_initial_ticks;
90 u32 sweep_shift;
91 u32 length_status;
92 u32 length_ticks;
93 u32 noise_type;
94 u32 wave_type;
95 u32 wave_bank;
96 u32 wave_volume;
97 gbc_sound_status_type status;
98 u32 active_flag;
99 u32 master_enable;
100 s8 *sample_data;
101} gbc_sound_struct;
102
103extern direct_sound_struct direct_sound_channel[2];
104extern gbc_sound_struct gbc_sound_channel[4];
105extern s8 square_pattern_duty[4][8];
106extern u32 gbc_sound_master_volume_left;
107extern u32 gbc_sound_master_volume_right;
108extern u32 gbc_sound_master_volume;
2f1c528a 109extern u32 gbc_sound_buffer_index;
110extern u32 gbc_sound_last_cpu_ticks;
2823a4c8 111
112extern u32 sound_frequency;
113extern u32 sound_on;
114
115extern u32 global_enable_audio;
116extern u32 enable_low_pass_filter;
117extern u32 audio_buffer_size_number;
118
119extern SDL_mutex *sound_mutex;
2823a4c8 120
121void sound_timer_queue8(u32 channel, u8 value);
122void sound_timer_queue16(u32 channel, u16 value);
123void sound_timer_queue32(u32 channel, u32 value);
2f1c528a 124void sound_timer(fixed8_24 frequency_step, u32 channel);
2823a4c8 125void sound_reset_fifo(u32 channel);
126void update_gbc_sound(u32 cpu_ticks);
127void init_sound();
128void sound_write_mem_savestate(file_tag_type savestate_file);
129void sound_read_savestate(file_tag_type savestate_file);
130
bbba3209 131#ifdef IN_MEMORY_C
132
2823a4c8 133#define gbc_sound_tone_control_low(channel, address) \
134{ \
135 u32 initial_volume = (value >> 12) & 0x0F; \
136 u32 envelope_ticks = ((value >> 8) & 0x07) * 4; \
137 gbc_sound_channel[channel].length_ticks = 64 - (value & 0x3F); \
138 gbc_sound_channel[channel].sample_data = \
139 square_pattern_duty[(value >> 6) & 0x03]; \
140 gbc_sound_channel[channel].envelope_direction = (value >> 11) & 0x01; \
141 gbc_sound_channel[channel].envelope_initial_volume = initial_volume; \
142 gbc_sound_channel[channel].envelope_volume = initial_volume; \
143 gbc_sound_channel[channel].envelope_initial_ticks = envelope_ticks; \
144 gbc_sound_channel[channel].envelope_ticks = envelope_ticks; \
145 gbc_sound_channel[channel].envelope_status = (envelope_ticks != 0); \
146 gbc_sound_channel[channel].envelope_volume = initial_volume; \
147 gbc_sound_update = 1; \
148 address16(io_registers, address) = value; \
149} \
150
151#define gbc_sound_tone_control_high(channel, address) \
152{ \
153 u32 rate = value & 0x7FF; \
154 gbc_sound_channel[channel].rate = rate; \
155 gbc_sound_channel[channel].frequency_step = \
156 float_to_fp16_16(((131072.0 / (2048 - rate)) * 8.0) / sound_frequency); \
157 gbc_sound_channel[channel].length_status = (value >> 14) & 0x01; \
158 if(value & 0x8000) \
159 { \
160 gbc_sound_channel[channel].active_flag = 1; \
161 gbc_sound_channel[channel].sample_index -= float_to_fp16_16(1.0 / 12.0); \
162 gbc_sound_channel[channel].envelope_ticks = \
163 gbc_sound_channel[channel].envelope_initial_ticks; \
164 gbc_sound_channel[channel].envelope_volume = \
165 gbc_sound_channel[channel].envelope_initial_volume; \
166 } \
167 \
168 gbc_sound_update = 1; \
169 address16(io_registers, address) = value; \
170} \
171
172#define gbc_sound_tone_control_sweep() \
173{ \
174 u32 sweep_ticks = ((value >> 4) & 0x07) * 2; \
175 gbc_sound_channel[0].sweep_shift = value & 0x07; \
176 gbc_sound_channel[0].sweep_direction = (value >> 3) & 0x01; \
177 gbc_sound_channel[0].sweep_status = (value != 8); \
178 gbc_sound_channel[0].sweep_ticks = sweep_ticks; \
179 gbc_sound_channel[0].sweep_initial_ticks = sweep_ticks; \
180 gbc_sound_update = 1; \
181 address16(io_registers, 0x60) = value; \
182} \
183
184#define gbc_sound_wave_control() \
185{ \
186 gbc_sound_channel[2].wave_type = (value >> 5) & 0x01; \
187 gbc_sound_channel[2].wave_bank = (value >> 6) & 0x01; \
188 if(value & 0x80) \
189 { \
190 gbc_sound_channel[2].master_enable = 1; \
191 } \
192 else \
193 { \
194 gbc_sound_channel[2].master_enable = 0; \
195 } \
196 \
197 gbc_sound_update = 1; \
198 address16(io_registers, 0x70) = value; \
199} \
200
201static u32 gbc_sound_wave_volume[4] = { 0, 16384, 8192, 4096 };
202
203#define gbc_sound_tone_control_low_wave() \
204{ \
205 gbc_sound_channel[2].length_ticks = 256 - (value & 0xFF); \
206 if((value >> 15) & 0x01) \
207 { \
208 gbc_sound_channel[2].wave_volume = 12288; \
209 } \
210 else \
211 { \
212 gbc_sound_channel[2].wave_volume = \
213 gbc_sound_wave_volume[(value >> 13) & 0x03]; \
214 } \
215 gbc_sound_update = 1; \
216 address16(io_registers, 0x72) = value; \
217} \
218
219#define gbc_sound_tone_control_high_wave() \
220{ \
221 u32 rate = value & 0x7FF; \
222 gbc_sound_channel[2].rate = rate; \
223 gbc_sound_channel[2].frequency_step = \
224 float_to_fp16_16((2097152.0 / (2048 - rate)) / sound_frequency); \
225 gbc_sound_channel[2].length_status = (value >> 14) & 0x01; \
226 if(value & 0x8000) \
227 { \
228 gbc_sound_channel[2].sample_index = 0; \
229 gbc_sound_channel[2].active_flag = 1; \
230 } \
231 gbc_sound_update = 1; \
232 address16(io_registers, 0x74) = value; \
233} \
234
235#define gbc_sound_noise_control() \
236{ \
237 u32 dividing_ratio = value & 0x07; \
238 u32 frequency_shift = (value >> 4) & 0x0F; \
239 if(dividing_ratio == 0) \
240 { \
241 gbc_sound_channel[3].frequency_step = \
242 float_to_fp16_16(1048576.0 / (1 << (frequency_shift + 1)) / \
243 sound_frequency); \
244 } \
245 else \
246 { \
247 gbc_sound_channel[3].frequency_step = \
248 float_to_fp16_16(524288.0 / (dividing_ratio * \
249 (1 << (frequency_shift + 1))) / sound_frequency); \
250 } \
251 gbc_sound_channel[3].noise_type = (value >> 3) & 0x01; \
252 gbc_sound_channel[3].length_status = (value >> 14) & 0x01; \
253 if(value & 0x8000) \
254 { \
255 gbc_sound_channel[3].sample_index = 0; \
256 gbc_sound_channel[3].active_flag = 1; \
257 gbc_sound_channel[3].envelope_ticks = \
258 gbc_sound_channel[3].envelope_initial_ticks; \
259 gbc_sound_channel[3].envelope_volume = \
260 gbc_sound_channel[3].envelope_initial_volume; \
261 } \
262 gbc_sound_update = 1; \
263 address16(io_registers, 0x7C) = value; \
264} \
265
266#define gbc_trigger_sound_channel(channel) \
267 gbc_sound_master_volume_right = value & 0x07; \
268 gbc_sound_master_volume_left = (value >> 4) & 0x07; \
269 gbc_sound_channel[channel].status = ((value >> (channel + 8)) & 0x01) | \
270 ((value >> (channel + 11)) & 0x03) \
271
272#define gbc_trigger_sound() \
273{ \
274 gbc_trigger_sound_channel(0); \
275 gbc_trigger_sound_channel(1); \
276 gbc_trigger_sound_channel(2); \
277 gbc_trigger_sound_channel(3); \
278 address16(io_registers, 0x80) = value; \
279} \
280
281#define trigger_sound() \
282{ \
283 timer[0].direct_sound_channels = (((value >> 10) & 0x01) == 0) | \
284 ((((value >> 14) & 0x01) == 0) << 1); \
285 timer[1].direct_sound_channels = (((value >> 10) & 0x01) == 1) | \
286 ((((value >> 14) & 0x01) == 1) << 1); \
287 direct_sound_channel[0].volume = (value >> 2) & 0x01; \
288 direct_sound_channel[0].status = (value >> 8) & 0x03; \
289 direct_sound_channel[1].volume = (value >> 3) & 0x01; \
290 direct_sound_channel[1].status = (value >> 12) & 0x03; \
291 gbc_sound_master_volume = value & 0x03; \
292 \
293 if((value >> 11) & 0x01) \
294 sound_reset_fifo(0); \
295 if((value >> 15) & 0x01) \
296 sound_reset_fifo(1); \
297 address16(io_registers, 0x82) = value; \
298} \
299
300#define sound_on() \
301 if(value & 0x80) \
302 { \
303 if(sound_on != 1) \
304 { \
305 sound_on = 1; \
306 } \
307 } \
308 else \
309 { \
310 u32 i; \
311 for(i = 0; i < 4; i++) \
312 { \
313 gbc_sound_channel[i].active_flag = 0; \
314 } \
315 sound_on = 0; \
316 } \
317 address16(io_registers, 0x84) = \
318 (address16(io_registers, 0x84) & 0x000F) | (value & 0xFFF0); \
319
320#define sound_update_frequency_step(timer_number) \
321 timer[timer_number].frequency_step = \
2f1c528a 322 float_to_fp8_24(GBC_BASE_RATE / (timer_reload * sound_frequency)) \
2823a4c8 323
bbba3209 324#endif // IN_MEMORY_C
2823a4c8 325
326void reset_sound();
327void sound_exit();
328
329#endif