diff options
Diffstat (limited to 'audio/mods/paula.h')
-rw-r--r-- | audio/mods/paula.h | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/audio/mods/paula.h b/audio/mods/paula.h new file mode 100644 index 0000000000..f6f159d5a6 --- /dev/null +++ b/audio/mods/paula.h @@ -0,0 +1,210 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL$ + * $Id$ + * + */ + +#ifndef SOUND_MODS_PAULA_H +#define SOUND_MODS_PAULA_H + +#include "audio/audiostream.h" +#include "common/frac.h" +#include "common/mutex.h" + +namespace Audio { + +/** + * Emulation of the "Paula" Amiga music chip + * The interrupt frequency specifies the number of mixed wavesamples between + * calls of the interrupt method + */ +class Paula : public AudioStream { +public: + static const int NUM_VOICES = 4; + enum { + kPalSystemClock = 7093790, + kNtscSystemClock = 7159090, + kPalCiaClock = kPalSystemClock / 10, + kNtscCiaClock = kNtscSystemClock / 10, + kPalPaulaClock = kPalSystemClock / 2, + kNtscPauleClock = kNtscSystemClock / 2 + }; + + /* TODO: Document this */ + struct Offset { + uint int_off; // integral part of the offset + frac_t rem_off; // fractional part of the offset, at least 0 and less than 1 + + explicit Offset(int off = 0) : int_off(off), rem_off(0) {} + }; + + Paula(bool stereo = false, int rate = 44100, uint interruptFreq = 0); + ~Paula(); + + bool playing() const { return _playing; } + void setTimerBaseValue( uint32 ticksPerSecond ) { _timerBase = ticksPerSecond; } + uint32 getTimerBaseValue() { return _timerBase; } + void setSingleInterrupt(uint sampleDelay) { assert(sampleDelay < _intFreq); _curInt = sampleDelay; } + void setSingleInterruptUnscaled(uint timerDelay) { + setSingleInterrupt((uint)(((double)timerDelay * getRate()) / _timerBase)); + } + void setInterruptFreq(uint sampleDelay) { _intFreq = sampleDelay; _curInt = 0; } + void setInterruptFreqUnscaled(uint timerDelay) { + setInterruptFreq((uint)(((double)timerDelay * getRate()) / _timerBase)); + } + void clearVoice(byte voice); + void clearVoices() { for (int i = 0; i < NUM_VOICES; ++i) clearVoice(i); } + void startPlay() { _playing = true; } + void stopPlay() { _playing = false; } + void pausePlay(bool pause) { _playing = !pause; } + +// AudioStream API + int readBuffer(int16 *buffer, const int numSamples); + bool isStereo() const { return _stereo; } + bool endOfData() const { return _end; } + int getRate() const { return _rate; } + +protected: + struct Channel { + const int8 *data; + const int8 *dataRepeat; + uint32 length; + uint32 lengthRepeat; + int16 period; + byte volume; + Offset offset; + byte panning; // For stereo mixing: 0 = far left, 255 = far right + int dmaCount; + }; + + bool _end; + Common::Mutex _mutex; + + virtual void interrupt() = 0; + + void startPaula() { + _playing = true; + _end = false; + } + + void stopPaula() { + _playing = false; + _end = true; + } + + void setChannelPanning(byte channel, byte panning) { + assert(channel < NUM_VOICES); + _voice[channel].panning = panning; + } + + void disableChannel(byte channel) { + assert(channel < NUM_VOICES); + _voice[channel].data = 0; + } + + void enableChannel(byte channel) { + assert(channel < NUM_VOICES); + Channel &ch = _voice[channel]; + ch.data = ch.dataRepeat; + ch.length = ch.lengthRepeat; + // actually first 2 bytes are dropped? + ch.offset = Offset(0); + // ch.period = ch.periodRepeat; + } + + void setChannelPeriod(byte channel, int16 period) { + assert(channel < NUM_VOICES); + _voice[channel].period = period; + } + + void setChannelVolume(byte channel, byte volume) { + assert(channel < NUM_VOICES); + _voice[channel].volume = volume; + } + + void setChannelSampleStart(byte channel, const int8 *data) { + assert(channel < NUM_VOICES); + _voice[channel].dataRepeat = data; + } + + void setChannelSampleLen(byte channel, uint32 length) { + assert(channel < NUM_VOICES); + assert(length < 32768/2); + _voice[channel].lengthRepeat = 2 * length; + } + + void setChannelData(uint8 channel, const int8 *data, const int8 *dataRepeat, uint32 length, uint32 lengthRepeat, int32 offset = 0) { + assert(channel < NUM_VOICES); + + Channel &ch = _voice[channel]; + + ch.dataRepeat = data; + ch.lengthRepeat = length; + enableChannel(channel); + ch.offset = Offset(offset); + + ch.dataRepeat = dataRepeat; + ch.lengthRepeat = lengthRepeat; + } + + void setChannelOffset(byte channel, Offset offset) { + assert(channel < NUM_VOICES); + _voice[channel].offset = offset; + } + + Offset getChannelOffset(byte channel) { + assert(channel < NUM_VOICES); + return _voice[channel].offset; + } + + int getChannelDmaCount(byte channel) { + assert(channel < NUM_VOICES); + return _voice[channel].dmaCount; + } + + void setChannelDmaCount(byte channel, int dmaVal = 0) { + assert(channel < NUM_VOICES); + _voice[channel].dmaCount = dmaVal; + } + + void setAudioFilter(bool enable) { + // TODO: implement + } + +private: + Channel _voice[NUM_VOICES]; + + const bool _stereo; + const int _rate; + const double _periodScale; + uint _intFreq; + uint _curInt; + uint32 _timerBase; + bool _playing; + + template<bool stereo> + int readBufferIntern(int16 *buffer, const int numSamples); +}; + +} // End of namespace Audio + +#endif |