341 lines
8.7 KiB
C++
341 lines
8.7 KiB
C++
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "twine/audio/music.h"
|
|
#include "audio/audiostream.h"
|
|
#include "audio/midiparser.h"
|
|
#include "audio/midiplayer.h"
|
|
#include "backends/audiocd/audiocd.h"
|
|
#include "common/debug.h"
|
|
#include "common/system.h"
|
|
#include "common/textconsole.h"
|
|
#include "twine/resources/hqr.h"
|
|
#include "twine/resources/resources.h"
|
|
#include "twine/twine.h"
|
|
|
|
namespace TwinE {
|
|
|
|
/**
|
|
* LBA1 default number of tracks
|
|
* <pre>
|
|
* TRACK 01 MODE1/2352
|
|
* INDEX 01 00:00:00
|
|
* TRACK 02 AUDIO
|
|
* INDEX 01 10:47:52
|
|
* TRACK 03 AUDIO
|
|
* INDEX 01 14:02:01
|
|
* TRACK 04 AUDIO
|
|
* INDEX 01 17:02:19
|
|
* TRACK 05 AUDIO
|
|
* INDEX 01 19:34:45
|
|
* TRACK 06 AUDIO
|
|
* INDEX 01 22:22:34
|
|
* TRACK 07 AUDIO
|
|
* INDEX 01 25:09:32
|
|
* TRACK 08 AUDIO
|
|
* INDEX 01 26:47:72
|
|
* TRACK 09 AUDIO
|
|
* INDEX 01 30:29:07
|
|
* TRACK 10 AUDIO
|
|
* INDEX 01 32:04:62
|
|
* </pre>
|
|
*/
|
|
|
|
TwinEMidiPlayer::TwinEMidiPlayer(TwinEEngine *engine) : _engine(engine) {
|
|
MidiPlayer::createDriver();
|
|
|
|
int ret = _driver->open();
|
|
if (ret == 0) {
|
|
if (_nativeMT32) {
|
|
_driver->sendMT32Reset();
|
|
} else {
|
|
_driver->sendGMReset();
|
|
}
|
|
_driver->setTimerCallback(this, &timerCallback);
|
|
}
|
|
}
|
|
|
|
void TwinEMidiPlayer::play(byte *buf, int size, bool loop) {
|
|
if (_parser == nullptr) {
|
|
if (_engine->_cfgfile.MidiType == MIDIFILE_DOS) {
|
|
_parser = MidiParser::createParser_XMIDI();
|
|
} else {
|
|
_parser = MidiParser::createParser_SMF();
|
|
}
|
|
}
|
|
|
|
if (!_parser->loadMusic(buf, size)) {
|
|
warning("Failed to load midi music");
|
|
return;
|
|
}
|
|
_parser->setTrack(0);
|
|
_parser->setMidiDriver(this);
|
|
_parser->setTimerRate(_driver->getBaseTempo());
|
|
_parser->property(MidiParser::mpCenterPitchWheelOnUnload, 1);
|
|
|
|
syncVolume();
|
|
debug("play midi with volume: %i", getVolume());
|
|
|
|
_isLooping = loop;
|
|
_isPlaying = true;
|
|
}
|
|
|
|
Music::Music(TwinEEngine *engine) : _engine(engine), _midiPlayer(engine) {
|
|
}
|
|
|
|
int32 Music::getLengthTrackCDR(int track) const {
|
|
// TODO:
|
|
return -1;
|
|
}
|
|
|
|
bool Music::playMidi(int32 midiIdx) {
|
|
const int32 loop = 1;
|
|
if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic()) {
|
|
// the midi tracks are stored in the lba1-xx files and the adeline logo jingle
|
|
// is in lba1-32.xx - while the midiIdx is 31
|
|
const int32 trackOffset = 1;
|
|
Common::Path trackName(Common::String::format("lba1-%02i", midiIdx + trackOffset));
|
|
Audio::SeekableAudioStream *stream = Audio::SeekableAudioStream::openStreamFile(trackName);
|
|
if (stream != nullptr) {
|
|
const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
|
|
_engine->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_midiHandle,
|
|
Audio::makeLoopingAudioStream(stream, loop), volume);
|
|
debug("Play midi music track %i", midiIdx);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
const char *filename;
|
|
if (_engine->_cfgfile.MidiType == MIDIFILE_DOS) {
|
|
filename = Resources::HQR_MIDI_MI_DOS_FILE;
|
|
} else if (_engine->_cfgfile.MidiType == MIDIFILE_WIN) {
|
|
filename = Resources::HQR_MIDI_MI_WIN_FILE;
|
|
} else {
|
|
debug("midi disabled - skip playing %i", midiIdx);
|
|
return false;
|
|
}
|
|
|
|
int32 midiSize = HQR::getAllocEntry(&midiPtr, filename, midiIdx);
|
|
if (midiSize == 0) {
|
|
debug("Could not find midi file for index %i", midiIdx);
|
|
return false;
|
|
}
|
|
debug("Play midi file for index %i", midiIdx);
|
|
_midiPlayer.play(midiPtr, midiSize, loop == 0 || loop > 1);
|
|
return true;
|
|
}
|
|
|
|
bool Music::playTrackCDR(int32 track) {
|
|
if (_engine->isLBA2()) {
|
|
static const char *musicTracksLba2[] = {
|
|
"",
|
|
"TADPCM1",
|
|
"TADPCM2",
|
|
"TADPCM3",
|
|
"TADPCM4",
|
|
"TADPCM5",
|
|
"JADPCM01",
|
|
"", // Track6.wav
|
|
"JADPCM02",
|
|
"JADPCM03",
|
|
"JADPCM04",
|
|
"JADPCM05",
|
|
"JADPCM06",
|
|
"JADPCM07",
|
|
"JADPCM08",
|
|
"JADPCM09",
|
|
"JADPCM10",
|
|
"JADPCM11",
|
|
"JADPCM12",
|
|
"JADPCM13",
|
|
"JADPCM14",
|
|
"JADPCM15",
|
|
"JADPCM16",
|
|
"JADPCM17",
|
|
"JADPCM18",
|
|
"LOGADPCM"};
|
|
|
|
const char *basename = musicTracksLba2[track];
|
|
Audio::SeekableAudioStream *stream = Audio::SeekableAudioStream::openStreamFile(basename);
|
|
if (stream != nullptr) {
|
|
const int volume = _engine->_system->getMixer()->getVolumeForSoundType(Audio::Mixer::kMusicSoundType);
|
|
_engine->_system->getMixer()->playStream(Audio::Mixer::kMusicSoundType, &_midiHandle,
|
|
Audio::makeLoopingAudioStream(stream, 1), volume);
|
|
debug(3, "Play audio track %s for track id %i", basename, track);
|
|
return true;
|
|
}
|
|
debug(3, "Failed to find a supported format for audio track: %s", basename);
|
|
// TODO: are there versions with real audio cd?
|
|
// us release starting at track 0
|
|
// other releases at track 6
|
|
return false;
|
|
}
|
|
|
|
AudioCDManager *cdrom = g_system->getAudioCDManager();
|
|
int offset = 1;
|
|
// usually the tracks are starting at track_02.xxx for gog and steam releases.
|
|
// But some users might have ripped the original cd audio tracks and named them
|
|
// from track_01.xxx onwards. So we need to check if the first track exists.
|
|
//
|
|
// see https://bugs.scummvm.org/ticket/15410 and https://bugs.scummvm.org/ticket/14669
|
|
if (cdrom->existExtractedCDAudioFiles(1)) {
|
|
offset = 0;
|
|
}
|
|
return cdrom->play(track + offset, 1, 0, 0);
|
|
}
|
|
|
|
bool Music::initCdrom() {
|
|
AudioCDManager *cdrom = g_system->getAudioCDManager();
|
|
return cdrom->open();
|
|
}
|
|
|
|
void Music::stopMusic() {
|
|
stopMusicCD();
|
|
stopMusicMidi();
|
|
}
|
|
|
|
void Music::stopMusicCD() {
|
|
AudioCDManager *cdrom = g_system->getAudioCDManager();
|
|
cdrom->stop();
|
|
}
|
|
|
|
void Music::fadeMusicMidi(uint32 time) {
|
|
// TODO implement fade out
|
|
stopMusicMidi();
|
|
}
|
|
|
|
void Music::stopMusicMidi() {
|
|
if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic() || _engine->isLBA2()) {
|
|
_engine->_system->getMixer()->stopHandle(_midiHandle);
|
|
}
|
|
|
|
_midiPlayer.stop();
|
|
free(midiPtr);
|
|
midiPtr = nullptr;
|
|
numXmi = -1;
|
|
}
|
|
|
|
bool Music::playMusic(int32 track) {
|
|
if (track == -1) {
|
|
stopMusic();
|
|
return true;
|
|
}
|
|
if (!_engine->_cfgfile.Sound) {
|
|
return false;
|
|
}
|
|
|
|
if (_engine->isCDROM()) {
|
|
if (_flagVoiceCD || track < 1 || track > 9) {
|
|
if (playMidiFile(track)) {
|
|
return true;
|
|
}
|
|
} else {
|
|
if (playCdTrack(track)) {
|
|
return true;
|
|
}
|
|
}
|
|
} else {
|
|
if (playMidiFile(track)) {
|
|
return true;
|
|
}
|
|
}
|
|
warning("Failed to play track %i", track);
|
|
return false;
|
|
}
|
|
|
|
bool Music::playMidiFile(int32 midiIdx) {
|
|
if (!_engine->_cfgfile.Sound) {
|
|
debug("sound disabled - skip playing %i", midiIdx);
|
|
return false;
|
|
}
|
|
|
|
if (_engine->isCDROM()) {
|
|
stopMusicCD();
|
|
}
|
|
|
|
if (midiIdx != numXmi || !isMidiPlaying()) {
|
|
stopMusicMidi();
|
|
numXmi = midiIdx;
|
|
if (!playMidi(midiIdx)) {
|
|
return false;
|
|
}
|
|
// volumeMidi(100);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
int32 Music::getMusicCD() {
|
|
AudioCDManager *cdrom = g_system->getAudioCDManager();
|
|
// if (_engine->_system->getMillis() > endMusicCD) {
|
|
if (!cdrom->isPlaying()) {
|
|
currentMusicCD = -1;
|
|
}
|
|
return currentMusicCD;
|
|
}
|
|
|
|
bool Music::playCdTrack(int32 track) {
|
|
fadeMusicMidi(1);
|
|
numXmi = -1;
|
|
|
|
if (track != getMusicCD()) {
|
|
stopMusicCD();
|
|
// TODO: endMusicCD = _engine->toSeconds(getLengthTrackCDR(track)) / 75 + _engine->toSeconds(1);
|
|
if (playTrackCDR(track)) {
|
|
// TODO: endMusicCD += _engine->_system->getMillis();
|
|
debug("Play cd music track %i", track);
|
|
currentMusicCD = track;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void Music::playAllMusic(int num) {
|
|
if (num != numXmi || !isMidiPlaying()) {
|
|
stopMusicMidi();
|
|
numXmi = num;
|
|
playMidi(num);
|
|
// volumeMidi(100);
|
|
}
|
|
if (num != getMusicCD()) {
|
|
stopMusicCD();
|
|
// TODO: endMusicCD = _engine->toSeconds(getLengthTrackCDR(num)) / 75 + _engine->toSeconds(1);
|
|
if (playTrackCDR(num)) {
|
|
// TODO: endMusicCD += _engine->_system->getMillis();
|
|
currentMusicCD = num;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool Music::isMidiPlaying() const {
|
|
if (_engine->isDotEmuEnhanced() || _engine->isLba1Classic()) {
|
|
return _engine->_system->getMixer()->isSoundHandleActive(_midiHandle);
|
|
}
|
|
|
|
return _midiPlayer.isPlaying();
|
|
}
|
|
|
|
void Music::musicVolume(int32 volume) {
|
|
_engine->_system->getMixer()->setVolumeForSoundType(Audio::Mixer::SoundType::kMusicSoundType, volume);
|
|
_midiPlayer.setVolume(volume);
|
|
}
|
|
|
|
} // namespace TwinE
|