1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef AUDIO_SOFTSYNTH_EMUMIDI_H 24 #define AUDIO_SOFTSYNTH_EMUMIDI_H 25 26 #include "audio/audiostream.h" 27 #include "audio/mididrv.h" 28 #include "audio/mixer.h" 29 30 class MidiDriver_Emulated : public Audio::AudioStream, public MidiDriver { 31 protected: 32 bool _isOpen; 33 Audio::Mixer *_mixer; 34 Audio::SoundHandle _mixerSoundHandle; 35 36 private: 37 Common::TimerManager::TimerProc _timerProc; 38 void *_timerParam; 39 40 enum { 41 FIXP_SHIFT = 16 42 }; 43 44 int _nextTick; 45 int _samplesPerTick; 46 47 protected: 48 int _baseFreq; 49 50 virtual void generateSamples(int16 *buf, int len) = 0; onTimer()51 virtual void onTimer() {} 52 53 public: MidiDriver_Emulated(Audio::Mixer * mixer)54 MidiDriver_Emulated(Audio::Mixer *mixer) : 55 _mixer(mixer), 56 _isOpen(false), 57 _timerProc(0), 58 _timerParam(0), 59 _nextTick(0), 60 _samplesPerTick(0), 61 _baseFreq(250) { 62 } 63 64 // MidiDriver API open()65 virtual int open() { 66 _isOpen = true; 67 68 int d = getRate() / _baseFreq; 69 int r = getRate() % _baseFreq; 70 71 // This is equivalent to (getRate() << FIXP_SHIFT) / BASE_FREQ 72 // but less prone to arithmetic overflow. 73 74 _samplesPerTick = (d << FIXP_SHIFT) + (r << FIXP_SHIFT) / _baseFreq; 75 76 return 0; 77 } 78 isOpen()79 bool isOpen() const { return _isOpen; } 80 setTimerCallback(void * timer_param,Common::TimerManager::TimerProc timer_proc)81 virtual void setTimerCallback(void *timer_param, Common::TimerManager::TimerProc timer_proc) { 82 _timerProc = timer_proc; 83 _timerParam = timer_param; 84 } 85 getBaseTempo()86 virtual uint32 getBaseTempo() { 87 return 1000000 / _baseFreq; 88 } 89 90 // AudioStream API readBuffer(int16 * data,const int numSamples)91 virtual int readBuffer(int16 *data, const int numSamples) { 92 const int stereoFactor = isStereo() ? 2 : 1; 93 int len = numSamples / stereoFactor; 94 int step; 95 96 do { 97 step = len; 98 if (step > (_nextTick >> FIXP_SHIFT)) 99 step = (_nextTick >> FIXP_SHIFT); 100 101 generateSamples(data, step); 102 103 _nextTick -= step << FIXP_SHIFT; 104 if (!(_nextTick >> FIXP_SHIFT)) { 105 if (_timerProc) 106 (*_timerProc)(_timerParam); 107 108 onTimer(); 109 110 _nextTick += _samplesPerTick; 111 } 112 113 data += step * stereoFactor; 114 len -= step; 115 } while (len); 116 117 return numSamples; 118 } 119 endOfData()120 virtual bool endOfData() const { 121 return false; 122 } 123 }; 124 125 #endif 126