diff options
-rw-r--r-- | engines/tinsel/detection_tables.h | 2 | ||||
-rw-r--r-- | engines/tinsel/music.cpp | 198 | ||||
-rw-r--r-- | engines/tinsel/sound.cpp | 20 | ||||
-rw-r--r-- | engines/tinsel/sound.h | 2 |
4 files changed, 114 insertions, 108 deletions
diff --git a/engines/tinsel/detection_tables.h b/engines/tinsel/detection_tables.h index f6b1487561..4762acfe2c 100644 --- a/engines/tinsel/detection_tables.h +++ b/engines/tinsel/detection_tables.h @@ -490,7 +490,7 @@ static const TinselGameDescription gameDescriptions[] = { }, GID_DW1, 0, - GF_SCNFILES, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, TINSEL_V1, }, diff --git a/engines/tinsel/music.cpp b/engines/tinsel/music.cpp index dab2a897fc..3144ea7f94 100644 --- a/engines/tinsel/music.cpp +++ b/engines/tinsel/music.cpp @@ -135,10 +135,6 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { if (ConfMan.hasKey("mute")) mute = ConfMan.getBool("mute"); - // The Macintosh version of DW1 uses raw PCM for music - if (TinselV1Mac) - return _vm->_sound->playDW1MacMusic(dwFileOffset); - SetMidiVolume(mute ? 0 : _vm->_config->_musicVolume); // the index and length of the last tune loaded @@ -191,43 +187,48 @@ bool PlayMidiSequence(uint32 dwFileOffset, bool bLoop) { // move to correct position in the file midiStream.seek(dwFileOffset, SEEK_SET); - // read the length of the sequence - dwSeqLen = midiStream.readUint32LE(); - - // make sure buffer is large enough for this sequence - assert(dwSeqLen > 0 && dwSeqLen <= g_midiBuffer.size); - - // stop any currently playing tune - _vm->_midiMusic->stop(); - - // read the sequence. This needs to be read again before playSEQ() is - // called even if the music is restarting, as playSEQ() reads the file - // name off the buffer itself. However, that function adds SMF headers - // to the buffer, thus if it's read again, the SMF headers will be read - // and the filename will always be 'MThd'. - if (midiStream.read(g_midiBuffer.pDat, dwSeqLen) != dwSeqLen) - error(FILE_IS_CORRUPT, MIDI_FILE); - - midiStream.close(); + if (TinselV1Mac) { + // The Macintosh version of DW1 uses raw PCM for music + dwSeqLen = midiStream.readUint32BE(); + _vm->_sound->playDW1MacMusic(midiStream, dwSeqLen); + } else { + dwSeqLen = midiStream.readUint32LE(); + + // make sure buffer is large enough for this sequence + assert(dwSeqLen > 0 && dwSeqLen <= g_midiBuffer.size); + + // stop any currently playing tune + _vm->_midiMusic->stop(); + + // read the sequence. This needs to be read again before playSEQ() is + // called even if the music is restarting, as playSEQ() reads the file + // name off the buffer itself. However, that function adds SMF headers + // to the buffer, thus if it's read again, the SMF headers will be read + // and the filename will always be 'MThd'. + if (midiStream.read(g_midiBuffer.pDat, dwSeqLen) != dwSeqLen) + error(FILE_IS_CORRUPT, MIDI_FILE); + + // WORKAROUND for bug #2820054 "DW1: No intro music at first start on Wii", + // which actually affects all ports, since it's specific to the GRA version. + // + // The GRA version does not seem to set the channel volume at all for the first + // intro track, thus we need to do that here. We only initialize the channels + // used in that sequence. And we are using 127 as default channel volume. + // + // Only in the GRA version dwFileOffset can be "38888", just to be sure, we + // check for the SCN files feature flag not being set though. + if (_vm->getGameID() == GID_DW1 && dwFileOffset == 38888 && !(_vm->getFeatures() & GF_SCNFILES)) { + _vm->_midiMusic->send(0x7F07B0 | 3); + _vm->_midiMusic->send(0x7F07B0 | 5); + _vm->_midiMusic->send(0x7F07B0 | 8); + _vm->_midiMusic->send(0x7F07B0 | 10); + _vm->_midiMusic->send(0x7F07B0 | 13); + } - // WORKAROUND for bug #2820054 "DW1: No intro music at first start on Wii", - // which actually affects all ports, since it's specific to the GRA version. - // - // The GRA version does not seem to set the channel volume at all for the first - // intro track, thus we need to do that here. We only initialize the channels - // used in that sequence. And we are using 127 as default channel volume. - // - // Only in the GRA version dwFileOffset can be "38888", just to be sure, we - // check for the SCN files feature flag not being set though. - if (_vm->getGameID() == GID_DW1 && dwFileOffset == 38888 && !(_vm->getFeatures() & GF_SCNFILES)) { - _vm->_midiMusic->send(0x7F07B0 | 3); - _vm->_midiMusic->send(0x7F07B0 | 5); - _vm->_midiMusic->send(0x7F07B0 | 8); - _vm->_midiMusic->send(0x7F07B0 | 10); - _vm->_midiMusic->send(0x7F07B0 | 13); + _vm->_midiMusic->playMIDI(dwSeqLen, bLoop); } - _vm->_midiMusic->playMIDI(dwSeqLen, bLoop); + midiStream.close(); return true; } @@ -281,68 +282,89 @@ void SetMidiVolume(int vol) { void OpenMidiFiles() { Common::File midiStream; - // Demo version has no midi file - if (TinselV0 || TinselV2) - return; + if (TinselV0) { + // The early demo version of DW1 doesn't have MIDI + } else if (TinselV2) { + // DW2 uses a different music mechanism + } else if (TinselV1Mac) { + // open MIDI sequence file in binary mode + if (!midiStream.open(MIDI_FILE)) + error(CANNOT_FIND_FILE, MIDI_FILE); - // The Macintosh version of DW1 does not use MIDI for music. - // It uses PCM music instead, which is quite big to be preloaded here. - if (TinselV1Mac) - return; + uint32 curTrack = 1; + uint32 songLength = 0; + int32 fileSize = midiStream.size(); - if (g_midiBuffer.pDat) - // already allocated - return; + // Init + for (int i = 0; i < ARRAYSIZE(g_midiOffsets); i++) + g_midiOffsets[i] = 0; - // open MIDI sequence file in binary mode - if (!midiStream.open(MIDI_FILE)) - error(CANNOT_FIND_FILE, MIDI_FILE); + midiStream.skip(4); // skip file header - // gen length of the largest sequence - g_midiBuffer.size = midiStream.readUint32LE(); - if (midiStream.eos() || midiStream.err()) - error(FILE_IS_CORRUPT, MIDI_FILE); - - if (g_midiBuffer.size) { - // allocate a buffer big enough for the largest MIDI sequence - if ((g_midiBuffer.pDat = (uint8 *)malloc(g_midiBuffer.size)) != NULL) { - // clear out the buffer - memset(g_midiBuffer.pDat, 0, g_midiBuffer.size); -// VMM_lock(midiBuffer.pDat, midiBuffer.size); - } else { - //mSeqHandle = NULL; + while (!midiStream.eos() && !midiStream.err() && midiStream.pos() != fileSize) { + assert(curTrack < ARRAYSIZE(g_midiOffsets)); + g_midiOffsets[curTrack] = midiStream.pos(); + //debug("%d: %d", curTrack, g_midiOffsets[curTrack]); + + songLength = midiStream.readUint32BE(); + midiStream.skip(songLength); + + curTrack++; } - } - // Now scan through the contents of the MIDI file to find the offset - // of each individual track, in order to create a mapping from MIDI - // offset to track number, for the enhanced MIDI soundtrack. - // The first song is always at position 4. The subsequent ones are - // calculated dynamically. - uint32 curOffset = 4; - uint32 curTrack = 0; - uint32 songLength = 0; + midiStream.close(); + } else { + if (g_midiBuffer.pDat) + // already allocated + return; + + // open MIDI sequence file in binary mode + if (!midiStream.open(MIDI_FILE)) + error(CANNOT_FIND_FILE, MIDI_FILE); + + // get length of the largest sequence + g_midiBuffer.size = midiStream.readUint32LE(); + if (midiStream.eos() || midiStream.err()) + error(FILE_IS_CORRUPT, MIDI_FILE); + + if (g_midiBuffer.size) { + // allocate a buffer big enough for the largest MIDI sequence + if ((g_midiBuffer.pDat = (uint8 *)malloc(g_midiBuffer.size)) != NULL) { + // clear out the buffer + memset(g_midiBuffer.pDat, 0, g_midiBuffer.size); + } + } - // Init - for (int i = 0; i < ARRAYSIZE(g_midiOffsets); i++) - g_midiOffsets[i] = 0; + // Now scan through the contents of the MIDI file to find the offset + // of each individual track, in order to create a mapping from MIDI + // offset to track number, for the enhanced MIDI soundtrack. + // The first song is always at position 4. The subsequent ones are + // calculated dynamically. + uint32 curOffset = 4; + uint32 curTrack = 0; + uint32 songLength = 0; + + // Init + for (int i = 0; i < ARRAYSIZE(g_midiOffsets); i++) + g_midiOffsets[i] = 0; + + while (!midiStream.eos() && !midiStream.err()) { + if (curOffset + (4 * curTrack) >= (uint32)midiStream.size()) + break; - while (!midiStream.eos() && !midiStream.err()) { - if (curOffset + (4 * curTrack) >= (uint32)midiStream.size()) - break; + assert(curTrack < ARRAYSIZE(g_midiOffsets)); + g_midiOffsets[curTrack] = curOffset + (4 * curTrack); + //debug("%d: %d", curTrack, midiOffsets[curTrack]); - assert(curTrack < ARRAYSIZE(g_midiOffsets)); - g_midiOffsets[curTrack] = curOffset + (4 * curTrack); - //debug("%d: %d", curTrack, midiOffsets[curTrack]); + songLength = midiStream.readUint32LE(); + curOffset += songLength; + midiStream.skip(songLength); - songLength = midiStream.readUint32LE(); - curOffset += songLength; - midiStream.skip(songLength); + curTrack++; + } - curTrack++; + midiStream.close(); } - - midiStream.close(); } void DeleteMidiBuffer() { diff --git a/engines/tinsel/sound.cpp b/engines/tinsel/sound.cpp index cea4971769..cadc754de6 100644 --- a/engines/tinsel/sound.cpp +++ b/engines/tinsel/sound.cpp @@ -177,15 +177,7 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound return true; } -bool SoundManager::playDW1MacMusic(int dwFileOffset) { - Common::File s; - - if (!s.open("midi.dat")) - error(CANNOT_FIND_FILE, "midi.dat"); - - s.seek(dwFileOffset); - uint32 length = s.readUint32BE(); - +void SoundManager::playDW1MacMusic(Common::File &s, uint32 length) { // TODO: It's a bad idea to load the music track in a buffer. // We should use a SubReadStream instead, and keep midi.dat open. // However, the track lengths aren't that big (about 1-4MB), @@ -195,28 +187,20 @@ bool SoundManager::playDW1MacMusic(int dwFileOffset) { // read all of the sample if (s.read(soundData, length) != length) - error(FILE_IS_CORRUPT, "midi.dat"); + error(FILE_IS_CORRUPT, MIDI_FILE); Common::SeekableReadStream *memStream = new Common::MemoryReadStream(soundData, length); Audio::SoundHandle *handle = &_channels[kChannelDW1MacMusic].handle; - //_channels[kChannelDW1MacMusic].sampleNum = dwFileOffset; // Stop any previously playing music track _vm->_mixer->stopHandle(*handle); - // FIXME: Should set this in a different place ;) - _vm->_mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, _vm->_config->_musicVolume); - // TODO: Compression support (MP3/OGG/FLAC) for midi.dat in DW1 Mac Audio::RewindableAudioStream *musicStream = Audio::makeRawStream(memStream, 22050, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES); if (musicStream) _vm->_mixer->playStream(Audio::Mixer::kMusicSoundType, handle, Audio::makeLoopingAudioStream(musicStream, 0)); - - s.close(); - - return true; } // playSample for DiscWorld 2 diff --git a/engines/tinsel/sound.h b/engines/tinsel/sound.h index 8510c1618f..c68d9cb71e 100644 --- a/engines/tinsel/sound.h +++ b/engines/tinsel/sound.h @@ -109,7 +109,7 @@ public: bool playSample(int id, Audio::Mixer::SoundType type, Audio::SoundHandle *handle = 0); bool playSample(int id, int sub, bool bLooped, int x, int y, int priority, Audio::Mixer::SoundType type, Audio::SoundHandle *handle = 0); - bool playDW1MacMusic(int dwFileOffset); + void playDW1MacMusic(Common::File &s, uint32 length); void stopAllSamples(); // Stops any currently playing sample void stopSpecSample(int id, int sub = 0); // Stops a specific sample |