1 // 2 // Copyright (C) 2007 by sinamas <sinamas at users.sourceforge.net> 3 // 4 // This program is free software; you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License version 2 as 6 // published by the Free Software Foundation. 7 // 8 // This program is distributed in the hope that it will be useful, 9 // but WITHOUT ANY WARRANTY; without even the implied warranty of 10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 // GNU General Public License version 2 for more details. 12 // 13 // You should have received a copy of the GNU General Public License 14 // version 2 along with this program; if not, write to the 15 // Free Software Foundation, Inc., 16 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 // 18 19 #ifndef SOUND_CHANNEL4_H 20 #define SOUND_CHANNEL4_H 21 22 #include "envelope_unit.h" 23 #include "gbint.h" 24 #include "length_counter.h" 25 #include "master_disabler.h" 26 #include "static_output_tester.h" 27 28 namespace gambatte { 29 30 struct SaveState; 31 32 class Channel4 { 33 public: 34 Channel4(); 35 void setNr1(unsigned data); 36 void setNr2(unsigned data); setNr3(unsigned data)37 void setNr3(unsigned data) { lfsr_.nr3Change(data, cycleCounter_); } 38 void setNr4(unsigned data); 39 void setSo(unsigned long soMask); isActive()40 bool isActive() const { return master_; } 41 void update(uint_least32_t *buf, unsigned long soBaseVol, unsigned long cycles); 42 void reset(); 43 void saveState(SaveState &state); 44 void loadState(SaveState const &state); 45 46 private: 47 class Lfsr : public SoundUnit { 48 public: 49 Lfsr(); 50 virtual void event(); 51 virtual void resetCounters(unsigned long oldCc); isHighState()52 bool isHighState() const { return ~reg_ & 1; } 53 void nr3Change(unsigned newNr3, unsigned long cc); 54 void nr4Init(unsigned long cc); 55 void reset(unsigned long cc); 56 void saveState(SaveState &state, unsigned long cc); 57 void loadState(SaveState const &state); disableMaster()58 void disableMaster() { killCounter(); master_ = false; reg_ = 0x7FFF; } killCounter()59 void killCounter() { counter_ = counter_disabled; } 60 void reviveCounter(unsigned long cc); 61 62 private: 63 unsigned long backupCounter_; 64 unsigned short reg_; 65 unsigned char nr3_; 66 bool master_; 67 68 void updateBackupCounter(unsigned long cc); 69 }; 70 71 class Ch4MasterDisabler : public MasterDisabler { 72 public: Ch4MasterDisabler(bool & m,Lfsr & lfsr)73 Ch4MasterDisabler(bool &m, Lfsr &lfsr) : MasterDisabler(m), lfsr_(lfsr) {} operator()74 virtual void operator()() { MasterDisabler::operator()(); lfsr_.disableMaster(); } 75 76 private: 77 Lfsr &lfsr_; 78 }; 79 80 friend class StaticOutputTester<Channel4, Lfsr>; 81 82 StaticOutputTester<Channel4, Lfsr> staticOutputTest_; 83 Ch4MasterDisabler disableMaster_; 84 LengthCounter lengthCounter_; 85 EnvelopeUnit envelopeUnit_; 86 Lfsr lfsr_; 87 SoundUnit *nextEventUnit_; 88 unsigned long cycleCounter_; 89 unsigned long soMask_; 90 unsigned long prevOut_; 91 unsigned char nr4_; 92 bool master_; 93 94 void setEvent(); 95 }; 96 97 } 98 99 #endif 100