// Will move to initialize()?
fifo_enabled = false;
pcm_freq = 44100;
- pcm_da_intleft = 256 << 7;
+ pcm_da_intleft = 128;
// Q: Is clear FIFO?
lrclock = false;
fifo_direction = true; // PLAY
fifo_int_status = false;
fifo_int_flag = false;
- fifo_reset_req = false;
pcm_is_16bit = false;
pcm_l_enabled = true;
pcm_r_enabled = true;
play_wptr = 0;
memset(play_pool, 0x00, sizeof(int32_t) * play_bufsize);
-
+ mix_mod = 0;
if(event_pcm >= 0) {
cancel_event(this, event_pcm);
event_pcm = -1;
{
#ifdef _PC98_HAVE_86PCM
if(pcm_fifo != NULL) {
- if(pcm_da_intleft == pcm_fifo->count()) {
- if(fifo_int_flag) {
+ if(pcm_da_intleft >= pcm_fifo->count()) {
+ if(fifo_int_flag && !(fifo_int_status)) {
+ //out_debug_log("PCM INTERRUPT at %d\n", pcm_da_intleft);
fifo_int_status = true;
write_signals(&outputs_int_pcm, 0xffffffff);
}
void FMSOUND::mix(int32_t* buffer, int cnt)
{
int ncount = 0;
- int32_t rsample, lsample;
+ int32_t sample_l, sample_r;
+ int32_t lastvol_l, lastvol_r;
#ifdef _PC98_HAVE_86PCM
+ int lptr = play_rptr;
+ if(lptr >= play_bufsize) lptr = 0;
+ int rptr;
+
+ if(((pcm_l_enabled) || (pcm_r_enabled)) && (play_w_remain > 0) && (fifo_direction) && (fifo_enabled)) { // Play
+ if(pcm_freq == sample_rate) {
+ int32_t* p = buffer;
+ if((pcm_l_enabled) && (pcm_r_enabled)) {
+ rptr = lptr + 1;
+ if(rptr >= play_bufsize) rptr = 0;
+ sample_l = play_pool[lptr];
+ sample_r = play_pool[rptr];
+ } else if(pcm_l_enabled) {
+ rptr = lptr;
+ sample_l = play_pool[lptr];
+ sample_r = 0;
+ } else if(pcm_r_enabled) {
+ rptr = lptr;
+ sample_r = play_pool[rptr];
+ sample_l = 0;
+ }
+ lastvol_l = apply_volume(sample_l, volume_l);
+ lastvol_r = apply_volume(sample_r, volume_r);
+ for(int i = 0; i < cnt; i++) {
+ p[0] += lastvol_l;
+ p[1] += lastvol_r;
+ play_w_remain -= (((pcm_l_enabled) && (pcm_r_enabled)) ? 2 : 1);
+ if(play_w_remain > 0) {
+ if((pcm_l_enabled) && (pcm_r_enabled)) {
+ lptr += 2;
+ if(lptr >= play_bufsize) lptr = 0;
+ rptr = lptr + 1;
+ if(rptr >= play_bufsize) rptr = 0;
+ sample_l = play_pool[lptr];
+ sample_r = play_pool[rptr];
+ } else if(pcm_l_enabled) {
+ lptr++;
+ if(lptr >= play_bufsize) lptr = 0;
+ rptr = lptr;
+ sample_l = play_pool[lptr];
+ sample_r = 0;
+ } else if(pcm_r_enabled) {
+ lptr++;
+ if(lptr >= play_bufsize) lptr = 0;
+ rptr = lptr;
+ sample_r = play_pool[rptr];
+ sample_l = 0;
+ }
+ lastvol_l = apply_volume(sample_l, volume_l);
+ lastvol_r = apply_volume(sample_r, volume_r);
+ } else {
+ play_w_remain = 0;
+ }
+ p += 2;
+ play_rptr = lptr;
+ }
+ } else if(pcm_freq < sample_rate) {
+ int32_t* p = buffer;
+ if((pcm_l_enabled) && (pcm_r_enabled)) {
+ rptr = lptr + 1;
+ if(rptr >= play_bufsize) rptr = 0;
+ sample_l = play_pool[lptr];
+ sample_r = play_pool[rptr];
+ } else if(pcm_l_enabled) {
+ rptr = lptr;
+ sample_l = play_pool[lptr];
+ sample_r = 0;
+ } else if(pcm_r_enabled) {
+ rptr = lptr;
+ sample_r = play_pool[rptr];
+ sample_l = 0;
+ }
+ lastvol_l = apply_volume(sample_l, volume_l);
+ lastvol_r = apply_volume(sample_r, volume_r);
+ for(int i = 0; i < cnt; i++) {
+ p[0] += lastvol_l;
+ p[1] += lastvol_r;
+ mix_mod = mix_mod + pcm_freq;
+ if(mix_mod >= sample_rate) {
+ mix_mod -= sample_rate;
+ //play_w_remain -= (((pcm_l_enabled) && (pcm_r_enabled)) ? 2 : 1);
+ if(play_w_remain > 0) {
+ if((pcm_l_enabled) && (pcm_r_enabled)) {
+ lptr += 2;
+ if(lptr >= play_bufsize) lptr = 0;
+ rptr = lptr + 1;
+ if(rptr >= play_bufsize) rptr = 0;
+ sample_l = play_pool[lptr];
+ sample_r = play_pool[rptr];
+ play_w_remain -= 2;
+ } else if(pcm_r_enabled) {
+ lptr++;
+ if(lptr >= play_bufsize) lptr = 0;
+ rptr = lptr;
+ sample_r = play_pool[rptr];
+ play_w_remain -= 1;
+ } else if(pcm_l_enabled) {
+ lptr++;
+ if(lptr >= play_bufsize) lptr = 0;
+ rptr = lptr;
+ sample_l = play_pool[lptr];
+ play_w_remain -= 1;
+ }
+ lastvol_l = apply_volume(sample_l, volume_l);
+ lastvol_r = apply_volume(sample_r, volume_r);
+ } else {
+ play_w_remain = 0;
+ }
+ }
+ p += 2;
+ play_rptr = lptr;
+ }
+ } else if(pcm_freq > sample_rate) {
+ int32_t* p = buffer;
+ int min_skip = pcm_freq / sample_rate;
+ if((pcm_l_enabled) && (pcm_r_enabled)) {
+ rptr = lptr + 1;
+ if(rptr >= play_bufsize) rptr = 0;
+ sample_l = play_pool[lptr];
+ sample_r = play_pool[rptr];
+ } else if(pcm_l_enabled) {
+ rptr = lptr;
+ sample_l = play_pool[lptr];
+ sample_r = 0;
+ } else if(pcm_r_enabled) {
+ rptr = lptr;
+ sample_r = play_pool[rptr];
+ sample_l = 0;
+ }
+ lastvol_l = apply_volume(sample_l, volume_l);
+ lastvol_r = apply_volume(sample_r, volume_r);
+ int inc_factor;
+ for(int i = 0; i < cnt; i++) {
+ p[0] += lastvol_l;
+ p[1] += lastvol_r;
+ inc_factor = 0;
+ mix_mod = mix_mod + (sample_rate * min_skip);
+ if(mix_mod >= pcm_freq) {
+ mix_mod -= pcm_freq;
+ inc_factor = 1;
+ }
+ play_w_remain -= (((pcm_l_enabled) && (pcm_r_enabled)) ? ((min_skip + inc_factor) * 2) : (min_skip + inc_factor));
+ if(play_w_remain > 0) {
+ if((pcm_l_enabled) && (pcm_r_enabled)) {
+ lptr += ((min_skip + inc_factor) * 2);
+ if(lptr >= play_bufsize) lptr = lptr - play_bufsize;
+ rptr = lptr + 1;
+ if(rptr >= play_bufsize) rptr = 0;
+ sample_l = play_pool[lptr];
+ sample_r = play_pool[rptr];
+ } else if(pcm_l_enabled) {
+ lptr += (min_skip + inc_factor);
+ if(lptr >= play_bufsize) lptr = lptr - play_bufsize;
+ rptr = lptr;
+ sample_l = play_pool[lptr];
+ sample_r = 0;
+ } else if(pcm_r_enabled) {
+ lptr += (min_skip + inc_factor);
+ if(lptr >= play_bufsize) lptr = lptr - play_bufsize;
+ rptr = lptr;
+ sample_r = play_pool[rptr];
+ sample_l = 0;
+ }
+ lastvol_l = apply_volume(sample_l, volume_l);
+ lastvol_r = apply_volume(sample_r, volume_r);
+ } else {
+ play_w_remain = 0;
+ }
+ p += 2;
+ play_rptr = lptr;
+ }
+ }
+ }
//* ToDo: Mix PCM
#endif
}
case EVENT_PCM:
#ifdef _PC98_HAVE_86PCM
lrclock = !lrclock;
- if((pcm_fifo != NULL) && (lrclock)) {
+ if((pcm_fifo != NULL)) {
if(fifo_direction) { // Play
pair16_t data;
data.w = 0;
- if(fifo_enabled) {
- if(pcm_is_16bit) {
- data.b.h = (uint8_t)(pcm_fifo->read());
- check_fifo_position();
- data.b.l = (uint8_t)(pcm_fifo->read());
- check_fifo_position();
- } else {
- data.b.h = (uint8_t)(pcm_fifo->read());
- check_fifo_position();
- data.b.l = 0x00;
+ if(!(pcm_fifo->empty())) {
+ if(fifo_enabled) {
+ if(pcm_is_16bit) {
+ if(((lrclock) && (pcm_l_enabled)) || (!(lrclock) && (pcm_r_enabled))) {
+ data.b.h = (uint8_t)(pcm_fifo->read());
+ data.b.l = (uint8_t)(pcm_fifo->read());
+ check_fifo_position();
+ }
+ } else {
+ if(((lrclock) && (pcm_l_enabled)) || (!(lrclock) && (pcm_r_enabled))) {
+ data.b.h = (uint8_t)(pcm_fifo->read());
+ check_fifo_position();
+ data.b.l = 0x00;
+ }
+ }
}
+ if(((lrclock) && (pcm_l_enabled)) || (!(lrclock) && (pcm_r_enabled))) {
+ pcm_data.sd = (int32_t)(data.sw >> 1);
+ play_pool[play_wptr++] = pcm_data.sd;
+ }
+ if(play_wptr >= play_bufsize) play_wptr = 0;
+ play_w_remain++;
+ if(play_w_remain >= play_bufsize) play_w_remain = play_bufsize;
}
- pcm_data.sd = (int32_t)(data.sw);
- play_pool[play_wptr++] = pcm_data.sd;
- if(play_wptr >= play_bufsize) play_wptr = 0;
- play_w_remain++;
} else { // ToDo: Record
pcm_data.sd = 0;
if(pcm_is_16bit) {
break;
case 0xa468:
{
- fifo_enabled = ((data & 0x80) != 0);
- fifo_direction = ((data & 0x40) == 0); // '1' = recording, '0' = playing.
- fifo_int_flag = ((data & 0x20) != 0);
- if((data & 0x10) == 0) {
+ if((pcm_ctrl_reg & 0x80) != (data & 0x80)) {
+ fifo_enabled = ((data & 0x80) != 0);
+ //out_debug_log("FIFO : %s\n", (fifo_enabled) ? "ENABLED" : "DISABLED");
+ }
+ if((pcm_ctrl_reg & 0x40) != (data & 0x40)) {
+ fifo_direction = ((data & 0x40) == 0); // '1' = recording, '0' = playing.
+ //out_debug_log("Update PCM FIFO TYPE : %s\n", (fifo_direction) ? "PLAY" : "REC");
+ }
+ if((pcm_ctrl_reg & 0x20) != (data & 0x20)) {
+ fifo_int_flag = ((data & 0x20) != 0);
+ //out_debug_log("Update PCM FIFO INT-MASK : %s\n", (fifo_int_flag) ? "YES" : "NO");
+ }
+ if(((pcm_ctrl_reg & 0x10) != 0) && ((data & 0x10) == 0)) {
+ //out_debug_log("PCM CLEAR INTr\n");
write_signals(&outputs_int_pcm, 0x00000000);
fifo_int_status = false;
}
- if((data & 0x08) != 0) {
- fifo_reset_req = true;
- } else {
- if(fifo_reset_req) {
+ if((pcm_ctrl_reg & 0x08) != (data & 0x08)) {
+ if((data & 0x08) != 0) {
+ //out_debug_log("PCM RESET \n");
+ play_w_remain = 0;
+ play_rptr = 0;
+ play_wptr = 0;
+ memset(play_pool, 0x00, sizeof(int32_t) * play_bufsize);
+ mix_mod = 0;
pcm_fifo->clear();
- fifo_reset_req = false;
}
}
uint32_t freq;
freq = 4130;
break;
}
- if(event_pcm >= 0) {
- cancel_event(this, event_pcm);
- event_pcm = -1;
+ if(freq != pcm_freq) {
+ if(event_pcm >= 0) {
+ cancel_event(this, event_pcm);
+ event_pcm = -1;
+ }
+ //out_debug_log("Update PCM FREQ=%d\n", freq);
+ lrclock = false;
+ pcm_freq = freq;
+ mix_mod = 0;
}
- if(fifo_enabled) {
- register_event(this, EVENT_PCM, 1.0e6 / ((double)freq * 2.0), true, &event_pcm);
+ if(event_pcm < 0) {
+ register_event(this, EVENT_PCM, 1.0e6 / (double)(freq * 2), true, &event_pcm);
}
- lrclock = true;
- pcm_freq = freq;
}
pcm_ctrl_reg = data;
break;
pcm_l_enabled = ((data & 0x20) != 0);
pcm_r_enabled = ((data & 0x10) != 0);
pcm_da_reg = data;
+ //out_debug_log("Update PCM TYPE: %s / %s%s\n", (pcm_is_16bit) ? "16bit" : "8bit", (pcm_l_enabled) ? "L" : " ", (pcm_r_enabled) ? "R" : " ");
} else {
- pcm_da_intleft = (int)(((uint32_t)data) << 7);
+ if((data & 0xff) == 0xff) {
+ pcm_da_intleft = 0x7ffc;
+ } else {
+ pcm_da_intleft = (int)(((uint32_t)((data & 0xff) + 1)) << 7);
+ }
}
case 0xa46c:
if(pcm_fifo != NULL) {
- if((fifo_enabled) && (fifo_direction)) {
+ //out_debug_log("FIFO DATA OUT %02x", data);
+ //if((fifo_enabled) && (fifo_direction)) {
pcm_fifo->write(data);
- check_fifo_position();
- }
+ //out_debug_log("FIFO DATA OUT %02x", data);
+ //check_fifo_position();
+ //}
}
break;
#endif
return pcm_da_reg;
break;
case 0xa46c:
- if((fifo_enabled) && !(fifo_direction)) {
+ //if((fifo_enabled) && !(fifo_direction)) {
uint8_t data = pcm_fifo->read();
- check_fifo_position();
+ // check_fifo_position();
return (uint32_t)data;
- }
+ //}
break;
#endif
}
return 0xff;
}
+void FMSOUND::set_volume(int ch, int decibel_l, int decibel_r)
+{
+ volume_l = decibel_to_volume(decibel_l);
+ volume_r = decibel_to_volume(decibel_r);
+}
+
+void FMSOUND::initialize_sound(int rate, int samples)
+{
+ sample_rate = rate;
+ sample_samples = samples;
+}
+
#define STATE_VERSION 2
bool FMSOUND::process_state(FILEIO* state_fio, bool loading)
state_fio->StateValue(fifo_direction);
state_fio->StateValue(fifo_int_flag);
state_fio->StateValue(fifo_int_status);
- state_fio->StateValue(fifo_reset_req);
state_fio->StateValue(lrclock);
state_fio->StateValue(pcm_is_16bit);
state_fio->StateValue(play_w_remain);
state_fio->StateValue(play_rptr);
state_fio->StateValue(play_wptr);
+ state_fio->StateValue(mix_mod);
state_fio->StateValue(event_pcm);
state_fio->StateArray(play_pool, sizeof(play_pool), 1);