OSDN Git Service

[General][WIP] Merge upstream 2017-03-20.Still not implement UIs.
[csp-qt/common_source_project-fm7.git] / source / src / vm / pcm1bit.cpp
index 2e30c9c..f7efd7f 100644 (file)
-/*\r
-       Skelton for retropc emulator\r
-\r
-       Author : Takeda.Toshiya\r
-       Date   : 2007.02.09 -\r
-\r
-       [ 1bit PCM ]\r
-*/\r
-\r
-#include "pcm1bit.h"\r
-#include "../fileio.h"\r
-\r
-void PCM1BIT::initialize()\r
-{\r
-       signal = false;\r
-       on = true;\r
-       mute = false;\r
-       \r
-#ifdef PCM1BIT_HIGH_QUALITY\r
-       sample_count = 0;\r
-       prev_clock = 0;\r
-       prev_vol = 0;\r
-#endif\r
-       update = 0;\r
-       \r
-       register_frame_event(this);\r
-}\r
-\r
-void PCM1BIT::write_signal(int id, uint32 data, uint32 mask)\r
-{\r
-       if(id == SIG_PCM1BIT_SIGNAL) {\r
-               bool next = ((data & mask) != 0);\r
-               if(signal != next) {\r
-#ifdef PCM1BIT_HIGH_QUALITY\r
-                       if(sample_count < 1024) {\r
-                               samples_signal[sample_count] = signal;\r
-                               samples_out[sample_count] = (on && !mute);\r
-                               samples_clock[sample_count] = passed_clock(prev_clock);\r
-                               sample_count++;\r
-                       }\r
-#endif\r
-                       // mute if signal is not changed in 2 frames\r
-                       update = 2;\r
-                       signal = next;\r
-               }\r
-       } else if(id == SIG_PCM1BIT_ON) {\r
-               on = ((data & mask) != 0);\r
-       } else if(id == SIG_PCM1BIT_MUTE) {\r
-               mute = ((data & mask) != 0);\r
-       }\r
-}\r
-\r
-void PCM1BIT::event_frame()\r
-{\r
-       if(update && --update == 0) {\r
-#ifdef PCM1BIT_HIGH_QUALITY\r
-               prev_vol = 0;\r
-#endif\r
-       }\r
-}\r
-\r
-void PCM1BIT::mix(int32* buffer, int cnt)\r
-{\r
-#ifdef PCM1BIT_HIGH_QUALITY\r
-       uint32 cur_clock = current_clock();\r
-       if(update) {\r
-               if(sample_count < 1024) {\r
-                       samples_signal[sample_count] = signal;\r
-                       samples_out[sample_count] = (on && !mute);\r
-                       samples_clock[sample_count] = passed_clock(prev_clock);\r
-                       sample_count++;\r
-               }\r
-               uint32 start_clock = 0;\r
-               int start_index = 0;\r
-               for(int i = 0; i < cnt; i++) {\r
-                       uint32 end_clock = ((cur_clock - prev_clock) * (i + 1)) / cnt;\r
-                       int on_clocks = 0, off_clocks = 0;\r
-                       for(int s = start_index; s < sample_count; s++) {\r
-                               uint32 clock = samples_clock[s];\r
-                               if(clock <= end_clock) {\r
-                                       if(samples_out[s]) {\r
-                                               if(samples_signal[s]) {\r
-                                                       on_clocks += clock - start_clock;\r
-                                               } else {\r
-                                                       off_clocks += clock - start_clock;\r
-                                               }\r
-                                       }\r
-                                       start_clock = clock;\r
-                                       start_index = s + 1;\r
-                               } else {\r
-                                       if(samples_out[s]) {\r
-                                               if(samples_signal[s]) {\r
-                                                       on_clocks += end_clock - start_clock;\r
-                                               } else {\r
-                                                       off_clocks += end_clock - start_clock;\r
-                                               }\r
-                                       }\r
-                                       start_clock = end_clock;\r
-                                       start_index = s;\r
-                                       break;\r
-                               }\r
-                       }\r
-                       int clocks = on_clocks + off_clocks;\r
-                       if(clocks) {\r
-                               prev_vol = max_vol * (on_clocks - off_clocks) / clocks;\r
-                       }\r
-                       *buffer++ += prev_vol; // L\r
-                       *buffer++ += prev_vol; // R\r
-               }\r
-       }\r
-       prev_clock = cur_clock;\r
-       sample_count = 0;\r
-#else\r
-       if(on && !mute && signal) {\r
-               for(int i = 0; i < cnt; i++) {\r
-                       *buffer++ += max_vol; // L\r
-                       *buffer++ += max_vol; // R\r
-               }\r
-       }\r
-#endif\r
-}\r
-\r
-void PCM1BIT::init(int rate, int volume)\r
-{\r
-       max_vol = volume;\r
-}\r
-\r
-#define STATE_VERSION  1\r
-\r
-void PCM1BIT::save_state(FILEIO* state_fio)\r
-{\r
-       state_fio->FputUint32(STATE_VERSION);\r
-       state_fio->FputInt32(this_device_id);\r
-       \r
-       state_fio->FputBool(signal);\r
-       state_fio->FputBool(on);\r
-       state_fio->FputBool(mute);\r
-#ifdef PCM1BIT_HIGH_QUALITY\r
-       state_fio->Fwrite(samples_signal, sizeof(samples_signal), 1);\r
-       state_fio->Fwrite(samples_out, sizeof(samples_out), 1);\r
-       state_fio->Fwrite(samples_clock, sizeof(samples_clock), 1);\r
-       state_fio->FputInt32(sample_count);\r
-       state_fio->FputUint32(prev_clock);\r
-       state_fio->FputInt32(prev_vol);\r
-#endif\r
-       state_fio->FputInt32(update);\r
-}\r
-\r
-bool PCM1BIT::load_state(FILEIO* state_fio)\r
-{\r
-       if(state_fio->FgetUint32() != STATE_VERSION) {\r
-               return false;\r
-       }\r
-       if(state_fio->FgetInt32() != this_device_id) {\r
-               return false;\r
-       }\r
-       signal = state_fio->FgetBool();\r
-       on = state_fio->FgetBool();\r
-       mute = state_fio->FgetBool();\r
-#ifdef PCM1BIT_HIGH_QUALITY\r
-       state_fio->Fread(samples_signal, sizeof(samples_signal), 1);\r
-       state_fio->Fread(samples_out, sizeof(samples_out), 1);\r
-       state_fio->Fread(samples_clock, sizeof(samples_clock), 1);\r
-       sample_count = state_fio->FgetInt32();\r
-       prev_clock = state_fio->FgetUint32();\r
-       prev_vol = state_fio->FgetInt32();\r
-#endif\r
-       update = state_fio->FgetInt32();\r
-       return true;\r
-}\r
-\r
+/*
+       Skelton for retropc emulator
+
+       Author : Takeda.Toshiya
+       Date   : 2007.02.09 -
+
+       [ 1bit PCM ]
+*/
+
+#include "pcm1bit.h"
+
+void PCM1BIT::initialize()
+{
+       signal = false;
+       on = true;
+       mute = false;
+       realtime = false;
+       changed = 0;
+       last_vol_l = last_vol_r = 0;
+       
+       register_frame_event(this);
+}
+
+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) {
+                       touch_sound();
+                       if(signal) {
+                               positive_clocks += get_passed_clock(prev_clock);
+                       } else {
+                               negative_clocks += get_passed_clock(prev_clock);
+                       }
+                       prev_clock = get_current_clock();
+                       // mute if signal is not changed in 2 frames
+                       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(changed) {
+               changed--;
+       }
+}
+
+void PCM1BIT::mix(int32_t* buffer, int cnt)
+{
+       if(on && !mute && changed) {
+               if(signal) {
+                       positive_clocks += get_passed_clock(prev_clock);
+               } else {
+                       negative_clocks += get_passed_clock(prev_clock);
+               }
+               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++) {
+                       *buffer++ += last_vol_l; // L
+                       *buffer++ += last_vol_r; // R
+               }
+       } else {
+               // suppress petite noise when go to mute
+               for(int i = 0; i < cnt; i++) {
+                       *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++;
+                       }
+               }
+       }
+       prev_clock = get_current_clock();
+       positive_clocks = negative_clocks = 0;
+}
+
+void PCM1BIT::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 PCM1BIT::initialize_sound(int rate, int volume)
+{
+       max_vol = volume;
+}
+
+#define STATE_VERSION  3
+
+void PCM1BIT::save_state(FILEIO* state_fio)
+{
+       state_fio->FputUint32(STATE_VERSION);
+       state_fio->FputInt32(this_device_id);
+       
+       state_fio->FputBool(signal);
+       state_fio->FputBool(on);
+       state_fio->FputBool(mute);
+       state_fio->FputBool(realtime);
+       state_fio->FputInt32(changed);
+       state_fio->FputUint32(prev_clock);
+       state_fio->FputInt32(positive_clocks);
+       state_fio->FputInt32(negative_clocks);
+}
+
+bool PCM1BIT::load_state(FILEIO* state_fio)
+{
+       if(state_fio->FgetUint32() != STATE_VERSION) {
+               return false;
+       }
+       if(state_fio->FgetInt32() != this_device_id) {
+               return false;
+       }
+       signal = state_fio->FgetBool();
+       on = state_fio->FgetBool();
+       mute = state_fio->FgetBool();
+       realtime = state_fio->FgetBool();
+       changed = state_fio->FgetInt32();
+       prev_clock = state_fio->FgetUint32();
+       positive_clocks = state_fio->FgetInt32();
+       negative_clocks = state_fio->FgetInt32();
+       
+       // post process
+       last_vol_l = last_vol_r = 0;
+       //touch_sound();
+       set_realtime_render(on & !mute);
+       return true;
+}
+