OSDN Git Service

[VM][WIP] Pre-process to apply new state framework.Still not buildable.
[csp-qt/common_source_project-fm7.git] / source / src / vm / scv / sound.cpp
1 /*
2         EPOCH Super Cassette Vision Emulator 'eSCV'
3
4         Author : Takeda.Toshiya
5         Date   : 2006.08.21 -
6
7         [ uPD1771C ]
8 */
9
10 #include <math.h>
11 #include "sound.h"
12 #include "sound_tbl.h"
13 #include "../upd7801.h"
14
15 //#define SOUND_DEBUG
16 #define ACK_WAIT 100
17
18 void SOUND::reset()
19 {
20         touch_sound();
21         clear_channel(&tone);
22         clear_channel(&noise);
23         clear_channel(&square1);
24         clear_channel(&square2);
25         clear_channel(&square3);
26         clear_channel(&pcm);
27         
28         memset(params, 0, sizeof(params));
29         param_cnt = param_ptr = 0;
30         register_id = -1;
31         cmd_addr = 0;
32 }
33
34 void SOUND::write_data8(uint32_t addr, uint32_t data)
35 {
36         if(register_id != -1) {
37                 return; // ignore new commands before return ack
38         }
39         if(!param_cnt) {
40                 // new command
41                 touch_sound();
42                 switch(data) {
43                 case 0x00: param_cnt = 1;         break; // note off
44                 case 0x01: param_cnt = 10;        break; // noises & square
45                 case 0x02: param_cnt = 4;         break; // tone
46                 case 0x1f: param_cnt = MAX_PARAM; break; // pcm
47                 }
48                 param_ptr = 0;
49                 cmd_addr  = get_cpu_pc(0); // for patch
50 #ifdef SOUND_DEBUG
51                 this->out_debug_log(_T("PC=%4x\tSOUND\t"), cmd_addr);
52 #endif
53         }
54
55 #ifdef SOUND_DEBUG
56         this->out_debug_log(_T("%2x "), data);
57 #endif
58         if(param_cnt) {
59                 touch_sound();
60                 params[param_ptr++] = data;
61                 if(params[0] == 0x1f) {
62                         // pcm command
63                         if(param_ptr == 6) {
64                                 memset(pcm_table, 0, sizeof(pcm_table));
65                                 pcm_len = pcm.ptr = 0;
66                         } else if(param_ptr >= 7) {
67                                 // 0xfe,0x00 : end of pcm, intf1 must not be done except star speeder
68                                 if(params[param_ptr - 2] == 0xfe && data == 0x00 && cmd_addr != 0xa765) {
69                                         param_cnt = 1;
70                                 } else {
71                                         process_pcm(params[param_ptr - 2]);
72                                 }
73                         }
74                 }
75                 if(--param_cnt) {
76                         if(register_id != -1) {
77                                 cancel_event(this, register_id);
78                         }
79                         register_event(this, 0, ACK_WAIT, false, &register_id);
80                 }
81         }
82         if(!param_cnt) {
83                 // process command
84                 process_cmd();
85 #ifdef SOUND_DEBUG
86                 this->out_debug_log(_T("\n"));
87 #endif
88         }
89 }
90
91 void SOUND::write_io8(uint32_t addr, uint32_t data)
92 {
93         // PC3 : L->H
94         if(data & 0x08) {
95                 // note off
96                 touch_sound();
97                 clear_channel(&tone);
98                 clear_channel(&noise);
99                 clear_channel(&square1);
100                 clear_channel(&square2);
101                 clear_channel(&square3);
102                 
103                 if(cmd_addr == 0x8402) {
104                         // y2 monster land
105                         bool pause = (get_cpu_pc(0) == 0x96c);
106                         if(pause || !(params[0] == 0x1f && param_ptr > 5)) {
107                                 // terminate command
108                                 if(register_id != -1) {
109                                         cancel_event(this, register_id);
110                                 }
111                                 memset(params, 0, sizeof(params));
112                                 param_cnt = param_ptr = 0;
113                                 
114                                 // terminate pcm when pause
115                                 if(pause) {
116                                         clear_channel(&pcm);
117                                 }
118 //                      } else if(register_id == -1) {
119 //                              vm->register_callback(this, 0, 100, false, &register_id);
120                         }
121                 } else {
122                         if(params[0]) {
123                                 // terminate command
124                                 memset(params, 0, sizeof(params));
125                                 param_cnt = param_ptr = 0;
126 //                              clear_channel(&pcm);
127                         }
128 //                      if(register_id == -1) {
129 //                              vm->register_callback(this, 0, 100, false, &register_id);
130 //                      }
131                 }
132 #ifdef SOUND_DEBUG
133                 this->out_debug_log(_T("PC3\n"));
134 #endif
135         }
136 }
137
138 void SOUND::event_callback(int event_id, int err)
139 {
140         if(pcm.count && param_ptr == 5 && params[0] == 0x1f && params[1] == 0x04 && params[2] == 0x64) {
141                 // wait previous pcm
142                 register_event(this, 0, ACK_WAIT, false, &register_id);
143                 return;
144         }
145         d_cpu->write_signal(SIG_UPD7801_INTF1, 1, 1);
146         register_id = -1;
147 }
148
149 void SOUND::initialize_sound(int rate)
150 {
151         tone.diff    = (int)((SOUND_CLOCK  / rate) * 128.0 * 16.0 + 0.5);
152         noise.diff   = (int)((NOISE_CLOCK  / rate) * 128.0 * 16.0 + 0.5);
153         square1.diff = (int)((SQUARE_CLOCK / rate) * 128.0 * 16.0 + 0.5);
154         square2.diff = (int)((SQUARE_CLOCK / rate) * 128.0 * 16.0 + 0.5);
155         square3.diff = (int)((SQUARE_CLOCK / rate) * 128.0 * 16.0 + 0.5);
156         pcm.diff     = (int)((SOUND_CLOCK  / rate) * 128.0 * 16.0 + 0.5);
157         
158         // create volume table
159         double vol = MAX_TONE;
160         for(int i = 0; i < 32; i++) {
161                 volume_table[31 - i] = (int) vol;
162                 vol /= 1.12201845439369;//1.258925412;
163         }
164         volume_table[0] = 0;
165         
166         // create detune table
167         for(int i = 0; i < 32; i++) {
168                 detune_table[i] = (int) (detune_rate[i] * 256 / 100 + 0.5);
169         }
170         
171         // reset device
172 //      reset();
173 }
174
175 void SOUND::process_cmd()
176 {
177         if(params[0] == 0x00) {
178                 // note off
179                 touch_sound();
180                 clear_channel(&tone);
181                 clear_channel(&noise);
182                 clear_channel(&square1);
183                 clear_channel(&square2);
184                 clear_channel(&square3);
185         } else if(params[0] == 0x01) {
186                 // noise & square
187                 touch_sound();
188                 noise.timbre = params[1] >> 5;
189                 noise.period = params[2] << 8;
190                 noise.volume = (MAX_NOISE * (params[3] > 0x1f ? 0x1f : params[3])) / 0x1f;
191                 noise.output = (noise_table[noise.ptr] * noise.volume) >> 8;
192                 
193                 square1.period = params[4] << 8;
194                 square1.volume = (MAX_SQUARE * (params[7] > 0x7f ? 0x7f : params[7])) / 0x7f;
195                 square1.output = (square_table[square1.ptr] * square1.volume) >> 8;
196                 
197                 square2.period = params[5] << 8;
198                 square2.volume = (MAX_SQUARE * (params[8] > 0x7f ? 0x7f : params[8])) / 0x7f;
199                 square2.output = (square_table[square2.ptr] * square2.volume) >> 8;
200                 
201                 square3.period = params[6] << 8;
202                 square3.volume = (MAX_SQUARE * (params[9] > 0x7f ? 0x7f : params[9])) / 0x7f;
203                 square3.output = (square_table[square3.ptr] * square3.volume) >> 8;
204                 
205                 // tone off
206                 clear_channel(&tone);
207         } else if(params[0] == 0x02) { // note on : $02, timbre, period, volume ?
208                 touch_sound();
209                 tone.timbre = params[1] >> 5;
210                 tone.period = (params[2] * detune_table[params[1] & 0x1f]);
211                 tone.volume = volume_table[params[3] & 0x1f];
212                 tone.output = (timbre_table[tone.timbre][tone.ptr] * tone.volume) >> 8;
213                 
214                 // noise & square off
215                 clear_channel(&noise);
216                 clear_channel(&square1);
217                 clear_channel(&square2);
218                 clear_channel(&square3);
219         }
220         
221         // clear command buffer
222         memset(params, 0, sizeof(params));
223         param_cnt = param_ptr = 0;
224 }
225
226 void SOUND::process_pcm(uint8_t data)
227 {
228         // add pcm wave to buffer
229         pcm_table[pcm_len++] = (data & 0x80) ? MAX_PCM : 0;
230         pcm_table[pcm_len++] = (data & 0x40) ? MAX_PCM : 0;
231         pcm_table[pcm_len++] = (data & 0x20) ? MAX_PCM : 0;
232         pcm_table[pcm_len++] = (data & 0x10) ? MAX_PCM : 0;
233         pcm_table[pcm_len++] = (data & 0x08) ? MAX_PCM : 0;
234         pcm_table[pcm_len++] = (data & 0x04) ? MAX_PCM : 0;
235         pcm_table[pcm_len++] = (data & 0x02) ? MAX_PCM : 0;
236         pcm_table[pcm_len++] = (data & 0x01) ? MAX_PCM : 0;
237         
238         if(!pcm.count) {
239                 pcm.count  = PCM_PERIOD;
240                 pcm.output = pcm_table[pcm_len - 8];
241         }
242 }
243
244 void SOUND::clear_channel(channel_t *ch)
245 {
246         ch->count  = 0;
247         ch->volume = 0;
248         ch->ptr    = 0;
249         ch->output = 0;
250 }
251
252 void SOUND::mix(int32_t* buffer, int cnt)
253 {
254         // create sound buffer
255         for(int i = 0; i < cnt; i++) {
256                 int vol = 0, vol_l, vol_r;
257                 // mix pcm
258                 if(pcm.count) {
259                         pcm.count -= pcm.diff;
260                         while (pcm.count <= 0) {
261                                 pcm.count += PCM_PERIOD;
262                                 // low-pass filter for the next sample
263                                 if(++pcm.ptr < pcm_len) {
264                                         pcm.output =  (pcm_table[pcm.ptr] + pcm_table[pcm.ptr + 1] + pcm_table[pcm.ptr + 2] + pcm_table[pcm.ptr + 3]) >> 2;
265                                 } else {
266                                         pcm.count = 0;
267                                         break;
268                                 }
269                         }
270                         vol = pcm.output;
271                         vol_l = apply_volume(vol, pcm_volume_l);
272                         vol_r = apply_volume(vol, pcm_volume_r);
273                 } else {
274                         // mix tone
275                         if(tone.volume && tone.period) {
276                                 tone.count -= tone.diff;
277                                 while (tone.count <= 0) {
278                                         tone.count  += tone.period;
279                                         tone.ptr     = (tone.ptr + 1) & 0xff;
280                                         tone.output  = (timbre_table[tone.timbre][tone.ptr] * tone.volume) >> 8;
281                                 }
282                                 vol += tone.output;
283                         }
284                         if(noise.volume && noise.period) {
285                                 noise.count -= noise.diff;
286                                 while (noise.count <= 0) {
287                                         noise.count  += noise.period;
288                                         noise.ptr     = (noise.ptr + 1) & 0xff;
289 //                                      noise.output  = (noise_table[noise.timbre][noise.ptr] * noise.volume) >> 8;
290                                         noise.output  = (noise_table[noise.ptr] * noise.volume) >> 8;
291                                 }
292                                 vol += noise.output;
293                         }
294                         if(square1.volume && square1.period) {
295                                 square1.count -= square1.diff;
296                                 while (square1.count <= 0) {
297                                         square1.count  += square1.period;
298                                         square1.ptr     = (square1.ptr + 1) & 0xff;
299                                         square1.output  = (square_table[square1.ptr] * square1.volume) >> 8;
300                                 }
301                                 vol += square1.output;
302                         }
303                         if(square2.volume && square2.period) {
304                                 square2.count -= square2.diff;
305                                 while (square2.count <= 0) {
306                                         square2.count  += square2.period;
307                                         square2.ptr     = (square2.ptr + 1) & 0xff;
308                                         square2.output  = (square_table[square2.ptr] * square2.volume) >> 8;
309                                 }
310                                 vol += square2.output;
311                         }
312                         if(square3.volume && square3.period) {
313                                 square3.count -= square3.diff;
314                                 while (square3.count <= 0) {
315                                         square3.count  += square3.period;
316                                         square3.ptr     = (square3.ptr + 1) & 0xff;
317                                         square3.output  = (square_table[square3.ptr] * square3.volume) >> 8;
318                                 }
319                                 vol += square3.output;
320                         }
321                         vol_l = apply_volume(vol, psg_volume_l);
322                         vol_r = apply_volume(vol, psg_volume_r);
323                 }
324                 *buffer++ += vol_l; // L
325                 *buffer++ += vol_r; // R
326         }
327 }
328
329 void SOUND::set_volume(int ch, int decibel_l, int decibel_r)
330 {
331         if(ch == 0) {
332                 psg_volume_l = decibel_to_volume(decibel_l);
333                 psg_volume_r = decibel_to_volume(decibel_r);
334         } else if(ch == 1) {
335                 pcm_volume_l = decibel_to_volume(decibel_l);
336                 pcm_volume_r = decibel_to_volume(decibel_r);
337         }
338 }
339
340 #define STATE_VERSION   1
341
342 #include "../../statesub.h"
343
344 #define DECL_STATE_ENTRY_CHANNEL_T(__pname) {           \
345                 DECL_STATE_ENTRY_INT32((__pname.count));        \
346                 DECL_STATE_ENTRY_INT32((__pname.diff)); \
347                 DECL_STATE_ENTRY_INT32((__pname.period)); \
348                 DECL_STATE_ENTRY_INT32((__pname.timbre)); \
349                 DECL_STATE_ENTRY_INT32((__pname.volume)); \
350                 DECL_STATE_ENTRY_INT32((__pname.output)); \
351                 DECL_STATE_ENTRY_INT32((__pname.ptr));  \
352         }               
353
354 void SOUND::decl_state()
355 {
356         enter_decl_state(STATE_VERSION);
357         
358         DECL_STATE_ENTRY_CHANNEL_T(tone);
359         DECL_STATE_ENTRY_CHANNEL_T(noise);
360         DECL_STATE_ENTRY_CHANNEL_T(square1);
361         DECL_STATE_ENTRY_CHANNEL_T(square2);
362         DECL_STATE_ENTRY_CHANNEL_T(square3);
363         DECL_STATE_ENTRY_CHANNEL_T(pcm);
364         
365         DECL_STATE_ENTRY_1D_ARRAY(pcm_table, sizeof(pcm_table) / sizeof(int));
366         DECL_STATE_ENTRY_UINT32(cmd_addr);
367         DECL_STATE_ENTRY_INT32(pcm_len);
368         DECL_STATE_ENTRY_INT32(param_cnt);
369         DECL_STATE_ENTRY_INT32(param_ptr);
370         DECL_STATE_ENTRY_INT32(register_id);
371         DECL_STATE_ENTRY_1D_ARRAY(params, sizeof(params));
372         
373         leave_decl_state();
374 }
375
376 void SOUND::save_state(FILEIO* state_fio)
377 {
378         if(state_entry != NULL) {
379                 state_entry->save_state(state_fio);
380         }
381 //      state_fio->FputUint32(STATE_VERSION);
382 //      state_fio->FputInt32(this_device_id);
383         
384 //      state_fio->Fwrite(&tone, sizeof(tone), 1);
385 //      state_fio->Fwrite(&noise, sizeof(noise), 1);
386 //      state_fio->Fwrite(&square1, sizeof(square1), 1);
387 //      state_fio->Fwrite(&square2, sizeof(square2), 1);
388 //      state_fio->Fwrite(&square3, sizeof(square3), 1);
389 //      state_fio->Fwrite(&pcm, sizeof(pcm), 1);
390 //      state_fio->Fwrite(pcm_table, sizeof(pcm_table), 1);
391 //      state_fio->FputUint32(cmd_addr);
392 //      state_fio->FputInt32(pcm_len);
393 //      state_fio->FputInt32(param_cnt);
394 //      state_fio->FputInt32(param_ptr);
395 //      state_fio->FputInt32(register_id);
396 //      state_fio->Fwrite(params, sizeof(params), 1);
397 }
398
399 bool SOUND::load_state(FILEIO* state_fio)
400 {
401         // pre process
402         int tone_diff = tone.diff;
403         int noise_diff = noise.diff;
404         int square1_diff = square1.diff;
405         int square2_diff = square2.diff;
406         int square3_diff = square3.diff;
407         int pcm_diff = pcm.diff;
408         
409         bool mb = false;
410         if(state_entry != NULL) {
411                 mb = state_entry->load_state(state_fio);
412         }
413         if(!mb) {
414                 return false;
415         }
416 //      if(state_fio->FgetUint32() != STATE_VERSION) {
417 //              return false;
418 //      }
419 //      if(state_fio->FgetInt32() != this_device_id) {
420 //              return false;
421 //      }
422 //      state_fio->Fread(&tone, sizeof(tone), 1);
423 //      state_fio->Fread(&noise, sizeof(noise), 1);
424 //      state_fio->Fread(&square1, sizeof(square1), 1);
425 //      state_fio->Fread(&square2, sizeof(square2), 1);
426 //      state_fio->Fread(&square3, sizeof(square3), 1);
427 //      state_fio->Fread(&pcm, sizeof(pcm), 1);
428 //      state_fio->Fread(pcm_table, sizeof(pcm_table), 1);
429 //      cmd_addr = state_fio->FgetUint32();
430 //      pcm_len = state_fio->FgetInt32();
431 //      param_cnt = state_fio->FgetInt32();
432 //      param_ptr = state_fio->FgetInt32();
433 //      register_id = state_fio->FgetInt32();
434 //      state_fio->Fread(params, sizeof(params), 1);
435         
436         // post process
437         tone.diff = tone_diff;
438         noise.diff = noise_diff;
439         square1.diff = square1_diff;
440         square2.diff = square2_diff;
441         square3.diff = square3_diff;
442         pcm.diff = pcm_diff;
443         return true;
444 }
445
446 bool SOUND::process_state(FILEIO* state_fio, bool loading)
447 {
448         // pre process
449         int tone_diff = tone.diff;
450         int noise_diff = noise.diff;
451         int square1_diff = square1.diff;
452         int square2_diff = square2.diff;
453         int square3_diff = square3.diff;
454         int pcm_diff = pcm.diff;
455         
456         if(!state_fio->StateCheckUint32(STATE_VERSION)) {
457                 return false;
458         }
459         if(!state_fio->StateCheckInt32(this_device_id)) {
460                 return false;
461         }
462         state_fio->StateBuffer(&tone, sizeof(tone), 1);
463         state_fio->StateBuffer(&noise, sizeof(noise), 1);
464         state_fio->StateBuffer(&square1, sizeof(square1), 1);
465         state_fio->StateBuffer(&square2, sizeof(square2), 1);
466         state_fio->StateBuffer(&square3, sizeof(square3), 1);
467         state_fio->StateBuffer(&pcm, sizeof(pcm), 1);
468         state_fio->StateBuffer(pcm_table, sizeof(pcm_table), 1);
469         state_fio->StateUint32(cmd_addr);
470         state_fio->StateInt32(pcm_len);
471         state_fio->StateInt32(param_cnt);
472         state_fio->StateInt32(param_ptr);
473         state_fio->StateInt32(register_id);
474         state_fio->StateBuffer(params, sizeof(params), 1);
475         
476         // post process
477         if(loading) {
478                 tone.diff = tone_diff;
479                 noise.diff = noise_diff;
480                 square1.diff = square1_diff;
481                 square2.diff = square2_diff;
482                 square3.diff = square3_diff;
483                 pcm.diff = pcm_diff;
484         }
485         return true;
486 }