diff options
Diffstat (limited to 'sound')
-rw-r--r-- | sound/adpcm.cpp | 2 | ||||
-rw-r--r-- | sound/aiff.cpp | 6 | ||||
-rw-r--r-- | sound/audiocd.cpp | 116 | ||||
-rw-r--r-- | sound/audiocd.h | 24 | ||||
-rw-r--r-- | sound/flac.cpp | 90 | ||||
-rw-r--r-- | sound/flac.h | 3 | ||||
-rw-r--r-- | sound/iff.cpp | 80 | ||||
-rw-r--r-- | sound/iff.h | 73 | ||||
-rw-r--r-- | sound/mixer.h | 2 | ||||
-rw-r--r-- | sound/mods/paula.h | 4 | ||||
-rw-r--r-- | sound/mods/protracker.h | 11 | ||||
-rw-r--r-- | sound/mods/soundfx.cpp | 306 | ||||
-rw-r--r-- | sound/mods/soundfx.h | 39 | ||||
-rw-r--r-- | sound/module.mk | 2 | ||||
-rw-r--r-- | sound/mp3.cpp | 87 | ||||
-rw-r--r-- | sound/mp3.h | 3 | ||||
-rw-r--r-- | sound/softsynth/ym2612.cpp | 38 | ||||
-rw-r--r-- | sound/vorbis.cpp | 80 | ||||
-rw-r--r-- | sound/vorbis.h | 3 |
19 files changed, 570 insertions, 399 deletions
diff --git a/sound/adpcm.cpp b/sound/adpcm.cpp index c6feb45aee..72564d7022 100644 --- a/sound/adpcm.cpp +++ b/sound/adpcm.cpp @@ -69,7 +69,7 @@ private: public: ADPCMInputStream(Common::SeekableReadStream *stream, uint32 size, typesADPCM type, int rate, int channels = 2, uint32 blockAlign = 0); - ~ADPCMInputStream() {}; + ~ADPCMInputStream() {} int readBuffer(int16 *buffer, const int numSamples); int readBufferOKI(int16 *buffer, const int numSamples); diff --git a/sound/aiff.cpp b/sound/aiff.cpp index 4942a66762..5d8d823756 100644 --- a/sound/aiff.cpp +++ b/sound/aiff.cpp @@ -46,7 +46,7 @@ uint32 readExtended(Common::SeekableReadStream &stream) { byte buf[10]; uint32 mantissa; - uint32 last; + uint32 last = 0; byte exp; stream.read(buf, 10); @@ -89,8 +89,8 @@ bool loadAIFFFromStream(Common::SeekableReadStream &stream, int &size, int &rate bool foundCOMM = false; bool foundSSND = false; - uint16 numChannels, bitsPerSample; - uint32 numSampleFrames, offset, blockSize, soundOffset; + uint16 numChannels = 0, bitsPerSample = 0; + uint32 numSampleFrames = 0, offset = 0, blockSize = 0, soundOffset = 0; while ((!foundCOMM || !foundSSND) && !stream.ioFailed()) { uint32 length, pos; diff --git a/sound/audiocd.cpp b/sound/audiocd.cpp index 44fb35a5ef..2635c2a0a6 100644 --- a/sound/audiocd.cpp +++ b/sound/audiocd.cpp @@ -23,6 +23,7 @@ #include "common/stdafx.h" #include "sound/audiocd.h" +#include "sound/audiostream.h" #include "sound/mp3.h" #include "sound/vorbis.h" #include "sound/flac.h" @@ -31,91 +32,76 @@ #include "common/util.h" #include "common/system.h" -DECLARE_SINGLETON(Audio::AudioCDManager); - namespace Audio { -struct TrackFormat { - /** Decodername */ - const char* decoderName; - /** - * Pointer to a function which tries to open the specified track - the only argument - * is the number of the track to be played. - * Returns either a DigitalTrackInfo object representing the requested track or null - * in case of an error - */ - DigitalTrackInfo* (*openTrackFunction)(int); -}; - -static const TrackFormat s_trackFormats[] = { - /* decoderName, openTrackFunction */ -#ifdef USE_FLAC - { "Flac", getFlacTrack }, -#endif -#ifdef USE_VORBIS - { "Ogg Vorbis", getVorbisTrack }, -#endif -#ifdef USE_MAD - { "MPEG Layer 3", getMP3Track }, -#endif - - { NULL, NULL } // Terminator -}; - - AudioCDManager::AudioCDManager() { - memset(_cachedTracks, 0, sizeof(_cachedTracks)); - memset(_trackInfo, 0, sizeof(_trackInfo)); _cd.playing = false; _cd.track = 0; _cd.start = 0; _cd.duration = 0; _cd.numLoops = 0; - _currentCacheIdx = 0; _mixer = g_system->getMixer(); assert(_mixer); } void AudioCDManager::play(int track, int numLoops, int startFrame, int duration) { if (numLoops != 0 || startFrame != 0) { - // Try to load the track from a .mp3/.ogg file, and if found, use - // that. If not found, attempt to do regular Audio CD playback of - // the requested track. - int index = getCachedTrack(track); - _cd.track = track; _cd.numLoops = numLoops; _cd.start = startFrame; _cd.duration = duration; - if (index >= 0) { - _mixer->stopHandle(_cd.handle); - _cd.playing = true; + // Try to load the track from a compressed data file, and if found, use + // that. If not found, attempt to start regular Audio CD playback of + // the requested track. + char trackName[2][16]; + sprintf(trackName[0], "track%d", track); + sprintf(trackName[1], "track%02d", track); + Audio::AudioStream *stream = 0; + + for (int i = 0; !stream && i < 2; ++i) { /* FIXME: Seems numLoops == 0 and numLoops == 1 both indicate a single repetition, while all other positive numbers indicate precisely the number of desired repetitions. Finally, -1 means infinitely many */ - numLoops = (numLoops < 1) ? numLoops + 1 : numLoops; - _trackInfo[index]->play(_mixer, &_cd.handle, numLoops, _cd.start, _cd.duration); + // We multiply by 40 / 3 = 1000 / 75 to convert frames to milliseconds + stream = AudioStream::openStreamFile(trackName[i], startFrame * 40 / 3, duration * 40 / 3, (numLoops < 1) ? numLoops + 1 : numLoops); + } + + // Stop any currently playing emulated track + _mixer->stopHandle(_cd.handle); + + // HACK: We abuse _cd.playing to store whether we are playing a real or an emulated track. + if (stream != 0) { + _cd.playing = true; + _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_cd.handle, stream); } else { - g_system->playCD(track, numLoops, startFrame, duration); _cd.playing = false; + g_system->playCD(track, numLoops, startFrame, duration); } } } void AudioCDManager::stop() { if (_cd.playing) { + // Audio CD emulation _mixer->stopHandle(_cd.handle); _cd.playing = false; } else { + // Real Audio CD g_system->stopCD(); } } bool AudioCDManager::isPlaying() const { - return _cd.playing || g_system->pollCD(); + if (_cd.playing) { + // Audio CD emulation + return _mixer->isSoundHandleActive(_cd.handle); + } else { + // Real Audio CD + return g_system->pollCD(); + } } void AudioCDManager::updateCD() { @@ -125,7 +111,8 @@ void AudioCDManager::updateCD() { // FIXME: We do not update the numLoops parameter here (and in fact, // currently can't do that). Luckily, only one engine ever checks // this part of the AudioCD status, namely the SCUMM engine; and it - // only checks + // only checks whether the track is currently set to infinite looping + // or not. _cd.playing = false; } } else { @@ -141,41 +128,4 @@ AudioCDManager::Status AudioCDManager::getStatus() const { return info; } -int AudioCDManager::getCachedTrack(int track) { - // See if we find the track in the cache - for (int i = 0; i < CACHE_TRACKS; i++) - if (_cachedTracks[i] == track) { - return _trackInfo[i] ? i : -1; - } - - // The track is not already in the cache. Try and see if - // we can load it. - DigitalTrackInfo *newTrack = 0; - for (const TrackFormat *format = s_trackFormats; - format->openTrackFunction != NULL && newTrack == NULL; - ++format) { - newTrack = format->openTrackFunction(track); - } - - int currentIndex = -1; - - if (newTrack != NULL) { - // We successfully loaded a digital track. Store it into _trackInfo. - - currentIndex = _currentCacheIdx++; - _currentCacheIdx %= CACHE_TRACKS; - - // First, delete the previous track info object - delete _trackInfo[currentIndex]; - - // Then, store the new track info object - _trackInfo[currentIndex] = newTrack; - _cachedTracks[currentIndex] = track; - } else { - debug(2, "Track %d not available in compressed format", track); - } - - return currentIndex; -} - } // End of namespace Audio diff --git a/sound/audiocd.h b/sound/audiocd.h index 23367ba262..281bf1b1b4 100644 --- a/sound/audiocd.h +++ b/sound/audiocd.h @@ -32,15 +32,6 @@ namespace Audio { -class DigitalTrackInfo { -public: - virtual ~DigitalTrackInfo() {} - - virtual void play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration) = 0; -// virtual void stop(); -}; - - class AudioCDManager : public Common::Singleton<AudioCDManager> { public: struct Status { @@ -73,27 +64,12 @@ private: friend class Common::Singleton<SingletonBaseType>; AudioCDManager(); - int getCachedTrack(int track); - -private: /* used for emulated CD music */ struct ExtStatus : Status { SoundHandle handle; }; ExtStatus _cd; - enum { -#if defined(__PSP__) - CACHE_TRACKS = 4 //the PSP can't have more than 8 files open simultaneously - //so don't use more than 4 filehandles for CD tracks -#else - CACHE_TRACKS = 10 -#endif - }; - int _cachedTracks[CACHE_TRACKS]; - DigitalTrackInfo *_trackInfo[CACHE_TRACKS]; - int _currentCacheIdx; - Mixer *_mixer; }; diff --git a/sound/flac.cpp b/sound/flac.cpp index 61e8800c31..215ccee26e 100644 --- a/sound/flac.cpp +++ b/sound/flac.cpp @@ -770,96 +770,6 @@ AudioStream *makeFlacStream( return input; } - -#pragma mark - -#pragma mark --- Flac Audio CD emulation --- -#pragma mark - - - -class FlacTrackInfo : public DigitalTrackInfo { -private: - Common::String _filename; - bool _errorFlag; - -public: - FlacTrackInfo(const char *filename); - bool error() { return _errorFlag; } - void play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration); -}; - -FlacTrackInfo::FlacTrackInfo(const char *filename) : - _filename(filename), - _errorFlag(false) { - - // Try to open the file - Common::File file; - if (!file.open(_filename)) { - _errorFlag = true; - return; - } - - // Next, try to create a FlacInputStream from it - FlacInputStream *tempStream = new FlacInputStream(&file, false); - - // If initialising the stream fails, we set the error flag - if (!tempStream || !tempStream->isStreamDecoderReady()) - _errorFlag = true; - - delete tempStream; -} - -void FlacTrackInfo::play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration) { - assert(!_errorFlag); - - if (error()) { - debug(1, "FlacTrackInfo::play: invalid state, method should not been called"); - } - - // Open the file - Common::File *file = new Common::File(); - if (!file || !file->open(_filename)) { - warning("FlacTrackInfo::play: failed to open '%s'", _filename.c_str()); - delete file; - return; - } - - // Convert startFrame & duration from frames (1/75 s) to milliseconds (1/1000s) - uint start = startFrame * 1000 / 75; - uint end = duration ? ((startFrame + duration) * 1000 / 75) : 0; - - // ... create an AudioStream ... - FlacInputStream *input = new FlacInputStream(file, true, start, end, numLoops); - if (!input->isStreamDecoderReady()) { - delete input; - return; - } - - // ... and play it - mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input); -} - -DigitalTrackInfo* getFlacTrack(int track) { - assert(track >= 1); - char trackName[4][32]; - - sprintf(trackName[0], "track%d.flac", track); - sprintf(trackName[1], "track%02d.flac", track); - sprintf(trackName[2], "track%d.fla", track); - sprintf(trackName[3], "track%02d.fla", track); - - for (int i = 0; i < 4; ++i) { - if (Common::File::exists(trackName[i])) { - FlacTrackInfo *trackInfo = new FlacTrackInfo(trackName[i]); - if (!trackInfo->error()) - return trackInfo; - delete trackInfo; - } - } - - return NULL; -} - - } // End of namespace Audio #endif // #ifdef USE_FLAC diff --git a/sound/flac.h b/sound/flac.h index 787a8ad79c..4b4acb3228 100644 --- a/sound/flac.h +++ b/sound/flac.h @@ -36,9 +36,6 @@ namespace Common { namespace Audio { class AudioStream; -class DigitalTrackInfo; - -DigitalTrackInfo *getFlacTrack(int track); /** * Create a new AudioStream from the FLAC data in the given diff --git a/sound/iff.cpp b/sound/iff.cpp new file mode 100644 index 0000000000..2fd6378b13 --- /dev/null +++ b/sound/iff.cpp @@ -0,0 +1,80 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2006 The ScummVM project + * + * 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$ + * + */ + +#include "sound/iff.h" +#include "sound/audiostream.h" +#include "sound/mixer.h" + +namespace Audio { + + +void A8SVXDecoder::readVHDR(Common::IFFChunk &chunk) { + _header.oneShotHiSamples = chunk.readUint32BE(); + _header.repeatHiSamples = chunk.readUint32BE(); + _header.samplesPerHiCycle = chunk.readUint32BE(); + _header.samplesPerSec = chunk.readUint16BE(); + _header.octaves = chunk.readByte(); + _header.compression = chunk.readByte(); + _header.volume = chunk.readUint32BE(); +} + +void A8SVXDecoder::readBODY(Common::IFFChunk &chunk) { + + switch (_header.compression) { + case 0: + _dataSize = chunk.size; + _data = (byte*)malloc(_dataSize); + chunk.read(_data, _dataSize); + break; + + case 1: + warning("compressed IFF audio is not supported"); + break; + } + +} + + +A8SVXDecoder::A8SVXDecoder(Common::ReadStream &input, Voice8Header &header, byte *&data, uint32 &dataSize) : + IFFParser(input), _header(header), _data(data), _dataSize(dataSize) { + if (_typeId != ID_8SVX) + error("unknown audio format"); +} + +void A8SVXDecoder::decode() { + + Common::IFFChunk *chunk; + + while ((chunk = nextChunk()) != 0) { + switch (chunk->id) { + case ID_VHDR: + readVHDR(*chunk); + break; + + case ID_BODY: + readBODY(*chunk); + break; + } + } +} + +} diff --git a/sound/iff.h b/sound/iff.h new file mode 100644 index 0000000000..592cf9c2f0 --- /dev/null +++ b/sound/iff.h @@ -0,0 +1,73 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2001-2006 The ScummVM project + * + * 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_IFF_H +#define SOUND_IFF_H + +#include "common/iff_container.h" + +namespace Audio { + +struct Voice8Header { + uint32 oneShotHiSamples; + uint32 repeatHiSamples; + uint32 samplesPerHiCycle; + uint16 samplesPerSec; + byte octaves; + byte compression; + uint32 volume; + + Voice8Header() { + memset(this, 0, sizeof(Voice8Header)); + } +}; + + +/* + A8SVX decoder reads 8SVX subtype of IFF files. + + TODO: make a factory function for this kind of stream? + */ +class A8SVXDecoder : public Common::IFFParser { + +protected: + Voice8Header &_header; + byte* &_data; + uint32 &_dataSize; + +protected: + void readVHDR(Common::IFFChunk &chunk); + void readBODY(Common::IFFChunk &chunk); + +public: + A8SVXDecoder(Common::ReadStream &input, Voice8Header &header, byte *&data, uint32 &dataSize); + void decode(); +}; + + +/* + TODO: Implement a parser for AIFF subtype. + */ + +} + +#endif diff --git a/sound/mixer.h b/sound/mixer.h index 5dfef06090..a0a7c93aed 100644 --- a/sound/mixer.h +++ b/sound/mixer.h @@ -132,7 +132,7 @@ public: * * @return whether the mixer is ready and setup */ - bool isReady() const { return _mixerReady; }; + bool isReady() const { return _mixerReady; } diff --git a/sound/mods/paula.h b/sound/mods/paula.h index 134ea8f845..b0c9bc96b8 100644 --- a/sound/mods/paula.h +++ b/sound/mods/paula.h @@ -41,7 +41,7 @@ public: ~Paula(); bool playing() const { return _playing; } - void setInterruptFreq(int freq) { _intFreq = freq; } + void setInterruptFreq(int freq) { _curInt = _intFreq = freq; } void setPanning(byte voice, byte panning) { assert(voice < NUM_VOICES); _voice[voice].panning = panning; @@ -86,7 +86,7 @@ protected: } else *buf++ += tmp; } - virtual void interrupt(void) {}; + virtual void interrupt(void) {} }; } // End of namespace Audio diff --git a/sound/mods/protracker.h b/sound/mods/protracker.h index 939b336b2f..7fefddd20c 100644 --- a/sound/mods/protracker.h +++ b/sound/mods/protracker.h @@ -31,6 +31,17 @@ namespace Audio { class AudioStream; +/* + * Factory function for ProTracker streams. Reads all data from the + * given ReadStream and creates an AudioStream from this. No reference + * to the 'stream' object is kept, so you can safely delete it after + * invoking this factory. + * + * @param stream the ReadStream from which to read the ProTracker data + * @param rate TODO + * @param stereo TODO + * @return a new AudioStream, or NULL, if an error occured + */ AudioStream *makeProtrackerStream(Common::ReadStream *stream, int rate = 44100, bool stereo = true); } // End of namespace Audio diff --git a/sound/mods/soundfx.cpp b/sound/mods/soundfx.cpp new file mode 100644 index 0000000000..27e596ac3b --- /dev/null +++ b/sound/mods/soundfx.cpp @@ -0,0 +1,306 @@ +/* ScummVM - Scumm Interpreter + * Copyright (C) 2007 The ScummVM project + * + * 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$ + * + */ + +#include "common/stdafx.h" +#include "common/endian.h" + +#include "sound/mods/paula.h" +#include "sound/mods/soundfx.h" +#include "sound/audiostream.h" + +namespace Audio { + +struct SoundFxInstrument { + char name[23]; + uint16 len; + uint8 finetune; + uint8 volume; + uint16 repeatPos; + uint16 repeatLen; + int8 *data; +}; + +class SoundFx : public Paula { +public: + + enum { + NUM_CHANNELS = 4, + NUM_INSTRUMENTS = 15, + CIA_FREQ = 715909 + }; + + SoundFx(int rate, bool stereo); + virtual ~SoundFx(); + + bool load(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb); + void play(); + +protected: + + void handlePattern(int ch, uint32 pat); + void updateEffects(int ch); + void handleTick(); + + void startPaula(); + void stopPaula(); + void setPaulaChannelPeriod(uint8 channel, int16 period); + void setPaulaChannelVolume(uint8 channel, uint8 volume); + void enablePaulaChannel(uint8 channel); + void disablePaulaChannel(uint8 channel); + void setupPaulaChannel(uint8 channel, const int8 *data, uint16 len, uint16 repeatPos, uint16 repeatLen); + + virtual void interrupt(); + + uint8 _ticks; + uint16 _delay; + SoundFxInstrument _instruments[NUM_INSTRUMENTS]; + uint8 _numOrders; + uint8 _curOrder; + uint16 _curPos; + uint8 _ordersTable[128]; + uint8 *_patternData; + int _eventsFreq; + uint16 _effects[NUM_CHANNELS]; +}; + +SoundFx::SoundFx(int rate, bool stereo) + : Paula(stereo, rate) { + _ticks = 0; + _delay = 0; + memset(_instruments, 0, sizeof(_instruments)); + _numOrders = 0; + _curOrder = 0; + _curPos = 0; + memset(_ordersTable, 0, sizeof(_ordersTable)); + _patternData = 0; + _eventsFreq = 0; + memset(_effects, 0, sizeof(_effects)); +} + +SoundFx::~SoundFx() { + free(_patternData); + for (int i = 0; i < NUM_INSTRUMENTS; ++i) { + free(_instruments[i].data); + } +} + +bool SoundFx::load(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb) { + int instrumentsSize[15]; + if (!loadCb) { + for (int i = 0; i < NUM_INSTRUMENTS; ++i) { + instrumentsSize[i] = data->readUint32BE(); + } + } + uint8 tag[4]; + data->read(tag, 4); + if (memcmp(tag, "SONG", 4) != 0) { + return false; + } + _delay = data->readUint16BE(); + data->skip(7 * 2); + for (int i = 0; i < NUM_INSTRUMENTS; ++i) { + SoundFxInstrument *ins = &_instruments[i]; + data->read(ins->name, 22); ins->name[22] = 0; + ins->len = data->readUint16BE(); + ins->finetune = data->readByte(); + ins->volume = data->readByte(); + ins->repeatPos = data->readUint16BE(); + ins->repeatLen = data->readUint16BE(); + } + _numOrders = data->readByte(); + data->skip(1); + data->read(_ordersTable, 128); + int maxOrder = 0; + for (int i = 0; i < _numOrders; ++i) { + if (_ordersTable[i] > maxOrder) { + maxOrder = _ordersTable[i]; + } + } + int patternSize = (maxOrder + 1) * 4 * 4 * 64; + _patternData = (uint8 *)malloc(patternSize); + if (!_patternData) { + return false; + } + data->read(_patternData, patternSize); + for (int i = 0; i < NUM_INSTRUMENTS; ++i) { + SoundFxInstrument *ins = &_instruments[i]; + if (!loadCb) { + if (instrumentsSize[i] != 0) { + assert(ins->len <= 1 || ins->len * 2 <= instrumentsSize[i]); + assert(ins->repeatLen <= 1 || (ins->repeatPos + ins->repeatLen) * 2 <= instrumentsSize[i]); + ins->data = (int8 *)malloc(instrumentsSize[i]); + if (!ins->data) { + return false; + } + data->read(ins->data, instrumentsSize[i]); + } + } else { + if (ins->name[0]) { + ins->name[8] = '\0'; + ins->data = (int8 *)(*loadCb)(ins->name, 0); + if (!ins->data) { + return false; + } + } + } + } + return true; +} + +void SoundFx::play() { + _curPos = 0; + _curOrder = 0; + _ticks = 0; + _eventsFreq = CIA_FREQ / _delay; + setInterruptFreq(_rate / _eventsFreq); + startPaula(); +} + +void SoundFx::handlePattern(int ch, uint32 pat) { + uint16 note1 = pat >> 16; + uint16 note2 = pat & 0xFFFF; + if (note1 != 0xFFFD) { + int ins = (note2 & 0xF000) >> 12; + if (ins != 0) { + SoundFxInstrument *i = &_instruments[ins - 1]; + setupPaulaChannel(ch, i->data, i->len, i->repeatPos, i->repeatLen); + int effect = (note2 & 0xF00) >> 8; + int volume = i->volume; + switch (effect) { + case 5: // volume up + volume += (note2 & 0xFF); + if (volume > 63) { + volume = 63; + } + break; + case 6: // volume down + volume -= (note2 & 0xFF); + if (volume < 0) { + volume = 0; + } + break; + } + setPaulaChannelVolume(ch, volume); + } + } + _effects[ch] = note2; + if (note1 == 0xFFFD) { // PIC + _effects[ch] = 0; + } else if (note1 == 0xFFFE) { // STP + disablePaulaChannel(ch); + } else if (note1 != 0) { + setPaulaChannelPeriod(ch, note1); + enablePaulaChannel(ch); + } +} + +void SoundFx::updateEffects(int ch) { + // updateEffects() is a no-op in all Delphine Software games using SoundFx : FW,OS,Cruise,AW + if (_effects[ch] != 0) { + switch (_effects[ch]) { + case 1: // appreggiato + case 2: // pitchbend + case 3: // ledon, enable low-pass filter + case 4: // ledoff, disable low-pass filter + case 7: // set step up + case 8: // set step down + warning("Unhandled effect %d\n", _effects[ch]); + break; + } + } +} + +void SoundFx::handleTick() { + ++_ticks; + if (_ticks != 6) { + for (int ch = 0; ch < 4; ++ch) { + updateEffects(ch); + } + } else { + _ticks = 0; + const uint8 *patternData = _patternData + _ordersTable[_curOrder] * 1024 + _curPos; + for (int ch = 0; ch < 4; ++ch) { + handlePattern(ch, READ_BE_UINT32(patternData)); + patternData += 4; + } + _curPos += 4 * 4; + if (_curPos >= 1024) { + _curPos = 0; + ++_curOrder; + if (_curOrder == _numOrders) { + stopPaula(); + } + } + } +} + +void SoundFx::startPaula() { + _playing = true; + _end = false; +} + +void SoundFx::stopPaula() { + _playing = false; + _end = true; +} + +void SoundFx::setPaulaChannelPeriod(uint8 channel, int16 period) { + _voice[channel].period = period; +} + +void SoundFx::setPaulaChannelVolume(uint8 channel, uint8 volume) { + _voice[channel].volume = volume; +} + +void SoundFx::enablePaulaChannel(uint8 channel) { +} + +void SoundFx::disablePaulaChannel(uint8 channel) { + _voice[channel].period = 0; +} + +void SoundFx::setupPaulaChannel(uint8 channel, const int8 *data, uint16 len, uint16 repeatPos, uint16 repeatLen) { + if (data && len > 1) { + Channel *ch = &_voice[channel]; + ch->data = data; + ch->dataRepeat = data + repeatPos * 2; + ch->length = len * 2; + ch->lengthRepeat = repeatLen * 2; + ch->offset = 0; + } +} + +void SoundFx::interrupt() { + handleTick(); +} + +AudioStream *makeSoundFxStream(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb, int rate, bool stereo) { + SoundFx *stream = new SoundFx(rate, stereo); + if (stream->load(data, loadCb)) { + stream->play(); + return stream; + } + delete stream; + return 0; +} + +} // End of namespace Audio diff --git a/sound/mods/soundfx.h b/sound/mods/soundfx.h new file mode 100644 index 0000000000..353aa6ecdc --- /dev/null +++ b/sound/mods/soundfx.h @@ -0,0 +1,39 @@ + +/* ScummVM - Scumm Interpreter + * Copyright (C) 2007 The ScummVM project + * + * 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_SOUNDFX_H +#define SOUND_MODS_SOUNDFX_H + +#include "common/stream.h" + +namespace Audio { + +class AudioStream; + +typedef byte *(*LoadSoundFxInstrumentCallback)(const char *name, uint32 *size); + +AudioStream *makeSoundFxStream(Common::SeekableReadStream *data, LoadSoundFxInstrumentCallback loadCb, int rate = 44100, bool stereo = true); + +} // End of namespace Audio + +#endif diff --git a/sound/module.mk b/sound/module.mk index dce7ace08e..a204dbadb9 100644 --- a/sound/module.mk +++ b/sound/module.mk @@ -5,6 +5,7 @@ MODULE_OBJS := \ aiff.o \ audiocd.o \ audiostream.o \ + iff.o \ flac.o \ fmopl.o \ mididrv.o \ @@ -24,6 +25,7 @@ MODULE_OBJS := \ mods/protracker.o \ mods/paula.o \ mods/rjp1.o \ + mods/soundfx.o \ softsynth/adlib.o \ softsynth/ym2612.o \ softsynth/fluidsynth.o \ diff --git a/sound/mp3.cpp b/sound/mp3.cpp index ff0e3d61dd..f9efdc4e8c 100644 --- a/sound/mp3.cpp +++ b/sound/mp3.cpp @@ -339,93 +339,6 @@ AudioStream *makeMP3Stream( return new MP3InputStream(stream, disposeAfterUse, start, end, numLoops); } - -#pragma mark - -#pragma mark --- MP3 Audio CD emulation --- -#pragma mark - - - -class MP3TrackInfo : public DigitalTrackInfo { -private: - Common::String _filename; - bool _errorFlag; - -public: - MP3TrackInfo(const char *filename); - bool error() { return _errorFlag; } - void play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration); -}; - -MP3TrackInfo::MP3TrackInfo(const char *filename) : - _filename(filename), - _errorFlag(false) { - - // Try to open the file - Common::File file; - if (!file.open(_filename)) { - _errorFlag = true; - return; - } - - // Next, try to create an MP3InputStream from it - MP3InputStream *tempStream = new MP3InputStream(&file, false); - - // If we see EOS here then that means that not (enough) valid input - // data was given. - _errorFlag = tempStream->endOfData(); - - // Clean up again - delete tempStream; -} - -void MP3TrackInfo::play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration) { - assert(!_errorFlag); - - mad_timer_t start; - mad_timer_t end; - - // Both startFrame and duration are given in frames, where 75 frames are one second. - // Calculate the appropriate mad_timer_t values from them. - mad_timer_set(&start, startFrame / 75, startFrame % 75, 75); - if (duration == 0) { - end = mad_timer_zero; - } else { - int endFrame = startFrame + duration; - mad_timer_set(&end, endFrame / 75, endFrame % 75, 75); - } - - // Open the file - Common::File *file = new Common::File(); - if (!file || !file->open(_filename)) { - warning("MP3TrackInfo::play: failed to open '%s'", _filename.c_str()); - delete file; - return; - } - - // ... create an AudioStream ... - MP3InputStream *input = new MP3InputStream(file, true, start, end, numLoops); - - // ... and play it - mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input); -} - -DigitalTrackInfo *getMP3Track(int track) { - char trackName[2][32]; - - sprintf(trackName[0], "track%d.mp3", track); - sprintf(trackName[1], "track%02d.mp3", track); - - for (int i = 0; i < 2; ++i) { - if (Common::File::exists(trackName[i])) { - MP3TrackInfo *trackInfo = new MP3TrackInfo(trackName[i]); - if (!trackInfo->error()) - return trackInfo; - delete trackInfo; - } - } - return NULL; -} - } // End of namespace Audio #endif // #ifdef USE_MAD diff --git a/sound/mp3.h b/sound/mp3.h index 354e880404..d4992ce10f 100644 --- a/sound/mp3.h +++ b/sound/mp3.h @@ -36,9 +36,6 @@ namespace Common { namespace Audio { class AudioStream; -class DigitalTrackInfo; - -DigitalTrackInfo *getMP3Track(int track); /** * Create a new AudioStream from the MP3 data in the given diff --git a/sound/softsynth/ym2612.cpp b/sound/softsynth/ym2612.cpp index 5ee864b168..e48f44ebc0 100644 --- a/sound/softsynth/ym2612.cpp +++ b/sound/softsynth/ym2612.cpp @@ -90,15 +90,15 @@ void Operator2612::setInstrument(byte const *instrument) { _specifiedSustainRate = instrument[24] & 31; _specifiedSustainLevel = (instrument[28] >> 4) & 15; _specifiedReleaseRate = instrument[28] & 15; - _state = _s_ready; // 本物ではどうなのかな? + _state = _s_ready; velocity(_velocity); } void Operator2612::keyOn() { _state = _s_attacking; _tickCount = 0; - _phase = 0; // どうも、実際こうらしい - _currentLevel = ((int32)0x7f << 15); // これも、実際こうらしい + _phase = 0; + _currentLevel = ((int32)0x7f << 15); } void Operator2612::keyOff() { @@ -116,7 +116,7 @@ void Operator2612::frequency(int freq) { if (r != 0) { r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale)); if (r >= 64) - r = 63; // するべきなんだろうとは思うんだけど (赤p.207) + r = 63; } r = 63 - r; @@ -125,7 +125,7 @@ void Operator2612::frequency(int freq) { else { value = powtbl[(r&3) << 7]; value *= 1 << (r >> 2); - value *= 41; // r == 20 のとき、0-96[db] が 10.01[ms] == 41.00096 + value *= 41; value /= 1 << (15 + 5); value *= 127 - _specifiedTotalLevel; value /= 127; @@ -156,7 +156,7 @@ void Operator2612::frequency(int freq) { if (r != 0) { r = r * 2 + 1; // (Translated) I cannot know whether the timing is a good choice or not r = r * 2 + (keyscaleTable[freq/262205] >> (3-_keyScale)); - // KS による補正はあるらしい。赤p.206 では記述されてないけど。 + // KS if (r >= 64) r = 63; } @@ -229,11 +229,11 @@ void Operator2612::nextTick(const int *phasebuf, int *outbuf, int buflen) { } if (level < zero_level) { - int phaseShift = *phasebuf >> 2; // 正しい変調量は? 3 じゃ小さすぎで 2 じゃ大きいような。 + int phaseShift = *phasebuf >> 2; if (_feedbackLevel) phaseShift += (output << (_feedbackLevel - 1)) / 1024; output = sintbl[((_phase >> 7) + phaseShift) & 0x7ff]; - output >>= (level >> 18); // 正しい減衰量は? + output >>= (level >> 18); // Here is the original code, which requires 64-bit ints // output *= powtbl[511 - ((level>>25)&511)]; // output >>= 16; @@ -438,13 +438,13 @@ void Voice2612::pitchBend(int value) { } void Voice2612::recalculateFrequency() { - // MIDI とも違うし.... - // どういう仕様なんだろうか? - // と思ったら、なんと、これ (↓) が正解らしい。 + // + // + // int32 basefreq = frequencyTable[_note]; int cfreq = frequencyTable[_note - (_note % 12)]; int oct = _note / 12; - int fnum = (int) (((double)basefreq * (1 << 13)) / cfreq); // OPL の fnum と同じようなもの。 + int fnum = (int) (((double)basefreq * (1 << 13)) / cfreq); fnum += _frequencyOffs - 0x2000; if (fnum < 0x2000) { fnum += 0x2000; @@ -455,7 +455,7 @@ void Voice2612::recalculateFrequency() { oct++; } - // _frequency は最終的にバイアス 256*1024 倍 + // _frequency = (int) ((frequencyTable[oct*12] * (double)fnum) / 8); int i; @@ -515,7 +515,7 @@ void MidiChannel_YM2612::noteOff(byte note) { } void MidiChannel_YM2612::controlChange(byte control, byte value) { - // いいのかこれで? + // if (control == 121) { // Reset controller removeAllVoices(); @@ -537,7 +537,7 @@ void MidiChannel_YM2612::sysEx_customInstrument(uint32 type, const byte *fmInst) } void MidiChannel_YM2612::pitchBend(int16 value) { - // いいのかこれで? + // Voice2612 *voice = _voices; for (; voice; voice = voice->next) voice->pitchBend(value); @@ -696,8 +696,8 @@ void MidiDriver_YM2612::createLookupTables() { 0x03d5, 0x0410, 0x044e, 0x048f, }; - // (int)(880.0 * 256.0 * pow(2.0, (note-0x51)/12.0)); // バイアス 256 倍 - // 0x45 が 440Hz (a4)、0x51 が 880Hz (a5) らしい + // (int)(880.0 * 256.0 * pow(2.0, (note-0x51)/12.0)) + // frequencyTable = new int [120]; for (block = -1; block < 9; block++) { for (i = 0; i < 12; i++) { @@ -707,7 +707,7 @@ void MidiDriver_YM2612::createLookupTables() { } keycodeTable = new int [120]; - // detune 量の計算や KS による rate 変換に使うんじゃないかな + // detune for (block = -1; block < 9; block++) { for (i = 0; i < 12; i++) { // see p.204 @@ -730,7 +730,7 @@ void MidiDriver_YM2612::createLookupTables() { keyscaleTable[0] = 0; for (freq = 1; freq < 8192; freq++) { keyscaleTable[freq] = (int)(log((double)freq) / 9.03 * 32.0) - 1; - // 8368[Hz] (o9c) で 32くらい。9.03 =:= ln 8368 + // 8368[Hz] (o9c) } } diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp index 9b88020974..7e9d9dc286 100644 --- a/sound/vorbis.cpp +++ b/sound/vorbis.cpp @@ -293,86 +293,6 @@ AudioStream *makeVorbisStream( } -#pragma mark - -#pragma mark --- Ogg Vorbis Audio CD emulation --- -#pragma mark - - - -class VorbisTrackInfo : public DigitalTrackInfo { -private: - Common::String _filename; - bool _errorFlag; - -public: - VorbisTrackInfo(const char *filename); - bool error() { return _errorFlag; } - void play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration); -}; - -VorbisTrackInfo::VorbisTrackInfo(const char *filename) : - _filename(filename), - _errorFlag(false) { - - - // Try to open the file - Common::File file; - if (!file.open(_filename)) { - _errorFlag = true; - return; - } - - // Next, try to create a VorbisInputStream from it - VorbisInputStream *tempStream = new VorbisInputStream(&file, false); - - // If an error occured... - // TODO: add an error or init method to VorbisInputStream - _errorFlag = tempStream->endOfData(); - - // Clean up again - delete tempStream; -} - -void VorbisTrackInfo::play(Mixer *mixer, SoundHandle *handle, int numLoops, int startFrame, int duration) { - assert(!_errorFlag); - - // Open the file - Common::File *file = new Common::File(); - if (!file || !file->open(_filename)) { - warning("VorbisTrackInfo::play: failed to open '%s'", _filename.c_str()); - delete file; - return; - } - - // Convert startFrame & duration from frames (1/75 s) to milliseconds (1/1000s), - // i.e. multiply with a factor of 1000/75 = 40/3. - uint start = startFrame * 40 / 3; - uint end = duration ? ((startFrame + duration) * 40 / 3) : 0; - - // ... create an AudioStream ... - VorbisInputStream *input = new VorbisInputStream(file, true, start, end, numLoops); - - // ... and play it - mixer->playInputStream(Audio::Mixer::kMusicSoundType, handle, input); -} - -DigitalTrackInfo *getVorbisTrack(int track) { - char trackName[2][32]; - - sprintf(trackName[0], "track%d.ogg", track); - sprintf(trackName[1], "track%02d.ogg", track); - - for (int i = 0; i < 2; ++i) { - if (Common::File::exists(trackName[i])) { - VorbisTrackInfo *trackInfo = new VorbisTrackInfo(trackName[i]); - if (!trackInfo->error()) - return trackInfo; - delete trackInfo; - } - } - return NULL; -} - - } // End of namespace Audio #endif // #ifdef USE_VORBIS diff --git a/sound/vorbis.h b/sound/vorbis.h index 9d702172df..88ef913360 100644 --- a/sound/vorbis.h +++ b/sound/vorbis.h @@ -36,9 +36,6 @@ namespace Common { namespace Audio { class AudioStream; -class DigitalTrackInfo; - -DigitalTrackInfo *getVorbisTrack(int track); /** * Create a new AudioStream from the Ogg Vorbis data in the given |