Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "common/stream.h"
00024 #include "common/mutex.h"
00025 #include "common/textconsole.h"
00026 #include "audio/audiostream.h"
00027 #include "audio/mixer.h"
00028 #include "audio/decoders/raw.h"
00029 #include "engines/grim/debug.h"
00030 #include "engines/grim/resource.h"
00031 #include "engines/grim/imuse/imuse_mcmp_mgr.h"
00032 #include "engines/grim/emi/sound/vimatrack.h"
00033
00034 namespace Grim {
00035
00036 struct Region {
00037 int32 offset;
00038 int32 length;
00039 };
00040
00041 struct SoundDesc {
00042 uint16 freq;
00043 byte channels;
00044 byte bits;
00045 int numRegions;
00046 Region *region;
00047 bool endFlag;
00048 bool inUse;
00049 char name[32];
00050 McmpMgr *mcmpMgr;
00051 int type;
00052 int volGroupId;
00053 bool mcmpData;
00054 uint32 headerSize;
00055 Common::SeekableReadStream *inStream;
00056 };
00057
00058 bool VimaTrack::isPlaying() {
00059
00060
00061 if (!_handle)
00062 return false;
00063
00064 if (g_system->getMixer()->isSoundHandleActive(*_handle)) {
00065 if (_stream->endOfData()) {
00066 g_system->getMixer()->stopHandle(*_handle);
00067 return false;
00068 } else {
00069 return true;
00070 }
00071 }
00072 return false;
00073 }
00074
00075 bool VimaTrack::openSound(const Common::String &filename, const Common::String &voiceName, const Audio::Timestamp *start) {
00076 Common::SeekableReadStream *file = g_resourceloader->openNewStreamFile(filename);
00077 if (!file) {
00078 Debug::debug(Debug::Sound, "Stream for %s not open", voiceName.c_str());
00079 return false;
00080 }
00081 _soundName = voiceName;
00082 _mcmp = new McmpMgr();
00083 _desc = new SoundDesc();
00084 _desc->inStream = file;
00085 _desc->mcmpData = true;
00086 _desc->mcmpMgr = _mcmp;
00087 int headerSize = 0;
00088
00089 if (_mcmp->openSound(voiceName.c_str(), file, headerSize)) {
00090 parseSoundHeader(_desc, headerSize);
00091
00092 _stream = Audio::makeQueuingAudioStream(_desc->freq, (false));
00093
00094 playTrack(start);
00095 return true;
00096 } else {
00097 return false;
00098 }
00099 }
00100 void VimaTrack::parseSoundHeader(SoundDesc *sound, int &headerSize) {
00101 Common::SeekableReadStream *data = sound->inStream;
00102
00103 uint32 tag = data->readUint32BE();
00104 if (tag == MKTAG('R','I','F','F')) {
00105 sound->endFlag = false;
00106 sound->region = new Region[1];
00107 sound->numRegions = 1;
00108 sound->region[0].offset = 0;
00109 data->seek(18, SEEK_CUR);
00110 sound->channels = data->readByte();
00111 data->readByte();
00112 sound->freq = data->readUint32LE();
00113 data->seek(6, SEEK_CUR);
00114 sound->bits = data->readByte();
00115 data->seek(5, SEEK_CUR);
00116 sound->region[0].length = data->readUint32LE();
00117 headerSize = 44;
00118 } else {
00119 assert(tag != MKTAG('i','M','U','S'));
00120 error("VimaTrack::parseSoundHeader() Unknown sound format");
00121 }
00122 }
00123
00124 int32 VimaTrack::getDataFromRegion(SoundDesc *sound, int region, byte **buf, int32 offset, int32 size) {
00125
00126 assert(buf && offset >= 0 && size >= 0);
00127 assert(region >= 0 && region < sound->numRegions);
00128
00129 int32 region_offset = sound->region[region].offset;
00130 int32 region_length = sound->region[region].length;
00131
00132 if (offset + size > region_length) {
00133 size = region_length - offset;
00134 sound->endFlag = true;
00135 } else {
00136 sound->endFlag = false;
00137 }
00138
00139 if (sound->mcmpData) {
00140 size = sound->mcmpMgr->decompressSample(region_offset + offset, size, buf);
00141 } else {
00142 *buf = new byte[size];
00143 sound->inStream->seek(region_offset + offset + sound->headerSize, SEEK_SET);
00144 sound->inStream->read(*buf, size);
00145 }
00146
00147 return size;
00148 }
00149 void VimaTrack::playTrack(const Audio::Timestamp *start) {
00150
00151 if (!_stream) {
00152 error("Stream not loaded");
00153 }
00154 byte *data = nullptr;
00155 int32 result = 0;
00156
00157 int32 curRegion = -1;
00158 int32 regionOffset = 0;
00159 int32 mixerFlags = Audio::FLAG_16BITS;
00160
00161 curRegion++;
00162
00163 int channels = _desc->channels;
00164
00165
00166 int32 mixer_size = _desc->freq * channels * 2;
00167
00168 if (start) {
00169 regionOffset = (start->msecs() * mixer_size) / 1000;
00170 regionOffset = (regionOffset / 2) * 2;
00171 while (regionOffset > _desc->region[curRegion].length) {
00172 regionOffset -= _desc->region[curRegion].length;
00173 ++curRegion;
00174 }
00175
00176 if (curRegion > _desc->numRegions - 1)
00177 return;
00178 }
00179
00180 if (_stream->endOfData()) {
00181 mixer_size *= 8;
00182 }
00183
00184 if (channels == 1)
00185 mixer_size &= ~1;
00186 if (channels == 2)
00187 mixer_size &= ~3;
00188
00189 if (mixer_size == 0)
00190 return;
00191
00192 do {
00193 result = getDataFromRegion(_desc, curRegion, &data, regionOffset, mixer_size);
00194 if (channels == 1) {
00195 result &= ~1;
00196 }
00197 if (channels == 2) {
00198 result &= ~3;
00199 }
00200
00201 if (result > mixer_size)
00202 result = mixer_size;
00203
00204 if (g_system->getMixer()->isReady()) {
00205 ((Audio::QueuingAudioStream *)_stream)->queueBuffer(data, result, DisposeAfterUse::YES, mixerFlags);
00206 regionOffset += result;
00207 } else
00208 delete[] data;
00209
00210 if (curRegion >= 0 && curRegion < _desc->numRegions - 1) {
00211 curRegion++;
00212 regionOffset = 0;
00213
00214 if (!_stream) {
00215 return;
00216 }
00217 }
00218 mixer_size -= result;
00219 assert(mixer_size >= 0);
00220 } while (mixer_size && !_desc->endFlag);
00221 if (g_system->getMixer()->isReady()) {
00222
00223
00224 }
00225 }
00226
00227 Audio::Timestamp VimaTrack::getPos() {
00228
00229 return g_system->getMixer()->getSoundElapsedTime(*_handle);
00230 }
00231
00232 VimaTrack::VimaTrack() {
00233 _soundType = Audio::Mixer::kSpeechSoundType;
00234 _handle = new Audio::SoundHandle();
00235 _file = nullptr;
00236 _mcmp = nullptr;
00237 _desc = nullptr;
00238 }
00239
00240 VimaTrack::~VimaTrack() {
00241 stop();
00242
00243 delete _mcmp;
00244
00245 if (_desc) {
00246 delete[] _desc->region;
00247 delete _desc->inStream;
00248 }
00249
00250 if (_handle) {
00251 g_system->getMixer()->stopHandle(*_handle);
00252 delete _handle;
00253 }
00254 delete _desc;
00255 }
00256
00257 }