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 8cf6833..f7efd7f 100644 (file)
 */
 
 #include "pcm1bit.h"
-#include "../fileio.h"
 
 void PCM1BIT::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::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::init(int rate, int volume)
+void PCM1BIT::initialize_sound(int rate, int volume)
 {
        max_vol = volume;
 }
 
-#define STATE_VERSION  1
+#define STATE_VERSION  3
 
 void PCM1BIT::save_state(FILEIO* state_fio)
 {
@@ -135,15 +122,11 @@ void PCM1BIT::save_state(FILEIO* state_fio)
        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->FputBool(realtime);
+       state_fio->FputInt32(changed);
        state_fio->FputUint32(prev_clock);
-       state_fio->FputInt32(prev_vol);
-#endif
-       state_fio->FputInt32(update);
+       state_fio->FputInt32(positive_clocks);
+       state_fio->FputInt32(negative_clocks);
 }
 
 bool PCM1BIT::load_state(FILEIO* state_fio)
@@ -157,15 +140,16 @@ bool PCM1BIT::load_state(FILEIO* state_fio)
        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();
+       realtime = state_fio->FgetBool();
+       changed = state_fio->FgetInt32();
        prev_clock = state_fio->FgetUint32();
-       prev_vol = state_fio->FgetInt32();
-#endif
-       update = state_fio->FgetInt32();
+       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;
 }