*/
#include "pcm1bit.h"
-#include "../fileio.h"
void PCM1BIT::initialize()
{
+ DEVICE::initialize();
signal = false;
on = true;
mute = false;
-
-#ifdef PCM1BIT_HIGH_QUALITY
- sample_count = 0;
- prev_clock = 0;
- prev_vol = 0;
-#endif
- update = 0;
+ realtime = false;
+ changed = 0;
+ last_vol_l = last_vol_r = 0;
register_frame_event(this);
}
-void PCM1BIT::write_signal(int id, uint32 data, uint32 mask)
+void PCM1BIT::reset()
+{
+ prev_clock = get_current_clock();
+ positive_clocks = negative_clocks = 0;
+}
+
+void PCM1BIT::write_signal(int id, uint32_t data, uint32_t mask)
{
if(id == SIG_PCM1BIT_SIGNAL) {
bool next = ((data & mask) != 0);
if(signal != next) {
-#ifdef PCM1BIT_HIGH_QUALITY
- if(sample_count < 1024) {
- samples_signal[sample_count] = signal;
- samples_out[sample_count] = (on && !mute);
- samples_clock[sample_count] = passed_clock(prev_clock);
- sample_count++;
+ touch_sound();
+ if(signal) {
+ positive_clocks += get_passed_clock(prev_clock);
+ } else {
+ negative_clocks += get_passed_clock(prev_clock);
}
-#endif
+ prev_clock = get_current_clock();
// mute if signal is not changed in 2 frames
- update = 2;
+ changed = 2;
signal = next;
}
} else if(id == SIG_PCM1BIT_ON) {
+ touch_sound();
on = ((data & mask) != 0);
+ set_realtime_render(this, on & !mute);
} else if(id == SIG_PCM1BIT_MUTE) {
+ touch_sound();
mute = ((data & mask) != 0);
+ set_realtime_render(this, on & !mute);
}
}
void PCM1BIT::event_frame()
{
- if(update && --update == 0) {
-#ifdef PCM1BIT_HIGH_QUALITY
- prev_vol = 0;
-#endif
+ if(changed) {
+ changed--;
}
}
-void PCM1BIT::mix(int32* buffer, int cnt)
+void PCM1BIT::mix(int32_t* buffer, int cnt)
{
-#ifdef PCM1BIT_HIGH_QUALITY
- uint32 cur_clock = current_clock();
- if(update) {
- if(sample_count < 1024) {
- samples_signal[sample_count] = signal;
- samples_out[sample_count] = (on && !mute);
- samples_clock[sample_count] = passed_clock(prev_clock);
- sample_count++;
+ if(on && !mute && changed) {
+ if(signal) {
+ positive_clocks += get_passed_clock(prev_clock);
+ } else {
+ negative_clocks += get_passed_clock(prev_clock);
}
- uint32 start_clock = 0;
- int start_index = 0;
+ int clocks = positive_clocks + negative_clocks;
+ int sample = clocks ? (max_vol * positive_clocks - max_vol * negative_clocks) / clocks : signal ? max_vol : -max_vol;
+
+ last_vol_l = apply_volume(sample, volume_l);
+ last_vol_r = apply_volume(sample, volume_r);
+
for(int i = 0; i < cnt; i++) {
- uint32 end_clock = ((cur_clock - prev_clock) * (i + 1)) / cnt;
- int on_clocks = 0, off_clocks = 0;
- for(int s = start_index; s < sample_count; s++) {
- uint32 clock = samples_clock[s];
- if(clock <= end_clock) {
- if(samples_out[s]) {
- if(samples_signal[s]) {
- on_clocks += clock - start_clock;
- } else {
- off_clocks += clock - start_clock;
- }
- }
- start_clock = clock;
- start_index = s + 1;
- } else {
- if(samples_out[s]) {
- if(samples_signal[s]) {
- on_clocks += end_clock - start_clock;
- } else {
- off_clocks += end_clock - start_clock;
- }
- }
- start_clock = end_clock;
- start_index = s;
- break;
- }
- }
- int clocks = on_clocks + off_clocks;
- if(clocks) {
- prev_vol = max_vol * (on_clocks - off_clocks) / clocks;
- }
- *buffer++ += prev_vol; // L
- *buffer++ += prev_vol; // R
+ *buffer++ += last_vol_l; // L
+ *buffer++ += last_vol_r; // R
}
- }
- prev_clock = cur_clock;
- sample_count = 0;
-#else
- if(on && !mute && signal) {
+ } else {
+ // suppress petite noise when go to mute
for(int i = 0; i < cnt; i++) {
- *buffer++ += max_vol; // L
- *buffer++ += max_vol; // R
+ *buffer++ += last_vol_l; // L
+ *buffer++ += last_vol_r; // R
+
+ if(last_vol_l > 0) {
+ last_vol_l--;
+ } else if(last_vol_l < 0) {
+ last_vol_l++;
+ }
+ if(last_vol_r > 0) {
+ last_vol_r--;
+ } else if(last_vol_r < 0) {
+ last_vol_r++;
+ }
}
}
-#endif
+ prev_clock = get_current_clock();
+ positive_clocks = negative_clocks = 0;
}
-void PCM1BIT::init(int rate, int volume)
+void PCM1BIT::set_volume(int ch, int decibel_l, int decibel_r)
{
- max_vol = volume;
+ volume_l = decibel_to_volume(decibel_l);
+ volume_r = decibel_to_volume(decibel_r);
}
-#define STATE_VERSION 1
-
-void PCM1BIT::save_state(FILEIO* state_fio)
+void PCM1BIT::initialize_sound(int rate, int volume)
{
- state_fio->FputUint32(STATE_VERSION);
- state_fio->FputInt32(this_device_id);
-
- state_fio->FputBool(signal);
- state_fio->FputBool(on);
- state_fio->FputBool(mute);
-#ifdef PCM1BIT_HIGH_QUALITY
- state_fio->Fwrite(samples_signal, sizeof(samples_signal), 1);
- state_fio->Fwrite(samples_out, sizeof(samples_out), 1);
- state_fio->Fwrite(samples_clock, sizeof(samples_clock), 1);
- state_fio->FputInt32(sample_count);
- state_fio->FputUint32(prev_clock);
- state_fio->FputInt32(prev_vol);
-#endif
- state_fio->FputInt32(update);
+ max_vol = volume;
}
-bool PCM1BIT::load_state(FILEIO* state_fio)
+#define STATE_VERSION 3
+
+bool PCM1BIT::process_state(FILEIO* state_fio, bool loading)
{
- if(state_fio->FgetUint32() != STATE_VERSION) {
- return false;
+ if(!state_fio->StateCheckUint32(STATE_VERSION)) {
+ return false;
+ }
+ if(!state_fio->StateCheckInt32(this_device_id)) {
+ return false;
+ }
+ state_fio->StateValue(signal);
+ state_fio->StateValue(on);
+ state_fio->StateValue(mute);
+ state_fio->StateValue(realtime);
+ state_fio->StateValue(changed);
+ state_fio->StateValue(prev_clock);
+ state_fio->StateValue(positive_clocks);
+ state_fio->StateValue(negative_clocks);
+
+ // post process
+ if(loading) {
+ last_vol_l = last_vol_r = 0;
+ set_realtime_render(this, on & !mute);
+ //touch_sound();
}
- if(state_fio->FgetInt32() != this_device_id) {
- return false;
- }
- signal = state_fio->FgetBool();
- on = state_fio->FgetBool();
- mute = state_fio->FgetBool();
-#ifdef PCM1BIT_HIGH_QUALITY
- state_fio->Fread(samples_signal, sizeof(samples_signal), 1);
- state_fio->Fread(samples_out, sizeof(samples_out), 1);
- state_fio->Fread(samples_clock, sizeof(samples_clock), 1);
- sample_count = state_fio->FgetInt32();
- prev_clock = state_fio->FgetUint32();
- prev_vol = state_fio->FgetInt32();
-#endif
- update = state_fio->FgetInt32();
- return true;
+ return true;
}
-