Initial commit
This commit is contained in:
244
engines/ultima/ultima8/audio/music_flex.cpp
Normal file
244
engines/ultima/ultima8/audio/music_flex.cpp
Normal file
@@ -0,0 +1,244 @@
|
||||
/* 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 "ultima/shared/std/string.h"
|
||||
#include "ultima/ultima8/misc/debugger.h"
|
||||
|
||||
#include "ultima/ultima8/audio/music_flex.h"
|
||||
#include "common/memstream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Ultima8 {
|
||||
|
||||
MusicFlex::MusicFlex(Common::SeekableReadStream *rs) : Archive(rs) {
|
||||
memset(_info, 0, sizeof(SongInfo *) * 128);
|
||||
_songs = new XMidiData *[_count];
|
||||
memset(_songs, 0, sizeof(XMidiData *) * _count);
|
||||
loadSongInfo();
|
||||
}
|
||||
|
||||
MusicFlex::~MusicFlex() {
|
||||
uint32 i;
|
||||
for (i = 0; i < 128; i++) {
|
||||
delete _info[i];
|
||||
}
|
||||
for (i = 0; i < _count; i++) {
|
||||
delete _songs[i];
|
||||
}
|
||||
delete [] _songs;
|
||||
}
|
||||
|
||||
MusicFlex::SongInfo::SongInfo() : _numMeasures(0), _loopJump(0) {
|
||||
memset(_filename, 0, 17);
|
||||
memset(_transitions, 0, 128 * sizeof(int *));
|
||||
}
|
||||
|
||||
MusicFlex::SongInfo::~SongInfo() {
|
||||
for (int i = 0; i < 128; i++) {
|
||||
delete [] _transitions[i];
|
||||
}
|
||||
}
|
||||
|
||||
MusicFlex::XMidiData *MusicFlex::getXMidi(uint32 index) {
|
||||
if (index >= _count)
|
||||
return nullptr;
|
||||
cache(index);
|
||||
return _songs[index];
|
||||
}
|
||||
|
||||
const MusicFlex::SongInfo *MusicFlex::getSongInfo(uint32 index) const {
|
||||
if (index > 127)
|
||||
return nullptr;
|
||||
return _info[index];
|
||||
}
|
||||
|
||||
void MusicFlex::cache(uint32 index) {
|
||||
if (index >= _count) return;
|
||||
uint32 size;
|
||||
uint8 *data = getRawObject(index, &size);
|
||||
if (!data) {
|
||||
// Note: multiple sorcerer scenes (such as MALCHIR::03F2)
|
||||
// request track 122, which is blank in the Gold Edition
|
||||
// music flex.
|
||||
warning("Unable to cache song %d from sound/music.flx", index);
|
||||
return;
|
||||
}
|
||||
_songs[index] = new XMidiData(data, size);
|
||||
}
|
||||
|
||||
void MusicFlex::uncache(uint32 index) {
|
||||
if (index >= _count) return;
|
||||
delete _songs[index];
|
||||
_songs[index] = nullptr;
|
||||
}
|
||||
|
||||
bool MusicFlex::isCached(uint32 index) const {
|
||||
if (index >= _count) return false;
|
||||
return (_songs[index] != nullptr);
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *MusicFlex::getAdlibTimbres() {
|
||||
uint32 size;
|
||||
const uint8 *data = getRawObject(259, &size);
|
||||
return new Common::MemoryReadStream(data, size, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
void MusicFlex::loadSongInfo() {
|
||||
uint32 size;
|
||||
const uint8 *buf = getRawObject(0, &size);
|
||||
|
||||
if (!buf || !size) {
|
||||
error("Unable to load song info from sound/music.flx");
|
||||
}
|
||||
Common::MemoryReadStream ds(buf, size);
|
||||
Std::string line;
|
||||
|
||||
// Read first section till we hit a #
|
||||
for (;;) {
|
||||
line = ds.readLine();
|
||||
|
||||
// We have hit the end of the section
|
||||
if (line.at(0) == '#') break;
|
||||
|
||||
Std::string::size_type begIdx, endIdx;
|
||||
|
||||
// Find the first not space, which will get us the name
|
||||
begIdx = line.findFirstNotOf(' ');
|
||||
endIdx = line.findFirstOf(' ', begIdx);
|
||||
Std::string name = line.substr(begIdx, endIdx - begIdx);
|
||||
|
||||
// Now find the first not space after the name, which will get us the num
|
||||
begIdx = line.findFirstNotOf(' ', endIdx);
|
||||
endIdx = line.findFirstOf(' ', begIdx);
|
||||
int num = line.at(begIdx);
|
||||
|
||||
// Now number of measures
|
||||
begIdx = line.findFirstNotOf(' ', endIdx);
|
||||
endIdx = line.findFirstOf(' ', begIdx);
|
||||
int measures = atoi(line.substr(begIdx, endIdx - begIdx).c_str());
|
||||
|
||||
// Now finally _loopJump
|
||||
begIdx = line.findFirstNotOf(' ', endIdx);
|
||||
endIdx = line.findFirstOf(' ', begIdx);
|
||||
int loopJump = atoi(line.substr(begIdx, endIdx - begIdx).c_str());
|
||||
|
||||
// Uh oh
|
||||
if (num < 0 || num > 127)
|
||||
error("Invalid Section 1 song _info data. num out of range");
|
||||
|
||||
if (_info[num])
|
||||
error("Invalid Section 1 song _info data. num already defined");
|
||||
|
||||
_info[num] = new SongInfo();
|
||||
|
||||
strncpy(_info[num]->_filename, name.c_str(), 16);
|
||||
_info[num]->_numMeasures = measures;
|
||||
_info[num]->_loopJump = loopJump;
|
||||
};
|
||||
|
||||
// Read 'Section2', or more like skip it, since it's only trans.xmi
|
||||
// Read first section till we hit a #
|
||||
for (;;) {
|
||||
line = ds.readLine();
|
||||
|
||||
// We have hit the end of the section
|
||||
if (line.at(0) == '#') break;
|
||||
}
|
||||
|
||||
// Skip 'Section3'
|
||||
for (;;) {
|
||||
line = ds.readLine();
|
||||
|
||||
// We have hit the end of the section
|
||||
if (line.at(0) == '#') break;
|
||||
}
|
||||
|
||||
// Read 'Section4' (trans _info)
|
||||
for (;;) {
|
||||
line = ds.readLine();
|
||||
|
||||
// We have hit the end of the section
|
||||
if (line.at(0) == '#') break;
|
||||
|
||||
Std::string::size_type begIdx, endIdx;
|
||||
|
||||
// Get 'from' name
|
||||
begIdx = line.findFirstNotOf(' ');
|
||||
endIdx = line.findFirstOf(' ', begIdx);
|
||||
Std::string from = line.substr(begIdx, endIdx - begIdx);
|
||||
|
||||
// Get 'to' name
|
||||
begIdx = line.findFirstNotOf(' ', endIdx);
|
||||
endIdx = line.findFirstOf(' ', begIdx);
|
||||
Std::string to = line.substr(begIdx, endIdx - begIdx);
|
||||
|
||||
// Find index of from name
|
||||
int fi;
|
||||
for (fi = 0; fi < 128; fi++) {
|
||||
if (_info[fi] && from == _info[fi]->_filename) break;
|
||||
}
|
||||
|
||||
if (fi == 128)
|
||||
error("Invalid Section 4 song _info data. Unable to find 'from' index (%s)", from.c_str());
|
||||
|
||||
// Find index of to name
|
||||
int ti;
|
||||
for (ti = 0; ti < 128; ti++) {
|
||||
if (_info[ti] && to == _info[ti]->_filename) break;
|
||||
}
|
||||
|
||||
if (ti == 128)
|
||||
error("Invalid Section 4 song _info data. Unable to find 'to' index (%s)", to.c_str());
|
||||
|
||||
// Allocate Transition _info
|
||||
_info[fi]->_transitions[ti] = new int[_info[fi]->_numMeasures];
|
||||
|
||||
// Now attempt to read the trans _info for the
|
||||
for (int m = 0; m < _info[fi]->_numMeasures; m++) {
|
||||
// Get trans _info name
|
||||
begIdx = line.findFirstNotOf(' ', endIdx);
|
||||
endIdx = line.findFirstOf(' ', begIdx);
|
||||
|
||||
if (begIdx == Std::string::npos)
|
||||
error("Invalid Section 4 song _info data. Unable to read _transitions for all measures");
|
||||
|
||||
Std::string trans = line.substr(begIdx, endIdx - begIdx);
|
||||
const char *str = trans.c_str();
|
||||
|
||||
int num = 0;
|
||||
|
||||
// Overlayed
|
||||
if (*str == '!')
|
||||
num = 0 - atoi(str + 1);
|
||||
else
|
||||
num = atoi(str);
|
||||
|
||||
_info[fi]->_transitions[ti][m] = num;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip all remaining sections
|
||||
|
||||
delete[] buf;
|
||||
}
|
||||
|
||||
} // End of namespace Ultima8
|
||||
} // End of namespace Ultima
|
||||
Reference in New Issue
Block a user