44 | | class DigitalMusicInputStream : public Audio::AudioStream { |
45 | | private: |
46 | | Audio::AudioStream *_compressedStream; |
47 | | ResourceContext *_context; |
48 | | ResourceData * resourceData; |
49 | | GameSoundTypes soundType; |
50 | | Common::File *_file; |
51 | | uint32 _filePos; |
52 | | uint32 _startPos; |
53 | | uint32 _endPos; |
54 | | bool _finished; |
55 | | bool _looping; |
56 | | int16 _buf[BUFFER_SIZE]; |
57 | | const int16 *_bufferEnd; |
58 | | const int16 *_pos; |
59 | | MemoryReadStream *_memoryStream; |
60 | | SagaEngine *_vm; |
61 | | |
62 | | void refill(); |
63 | | bool eosIntern() const { |
64 | | return _pos >= _bufferEnd; |
65 | | } |
66 | | |
67 | | public: |
68 | | DigitalMusicInputStream(SagaEngine *vm, ResourceContext *context, uint32 resourceId, bool looping, uint32 loopStart); |
69 | | ~DigitalMusicInputStream(); |
70 | | |
71 | | void createCompressedStream(); |
72 | | |
73 | | int readBuffer(int16 *buffer, const int numSamples); |
74 | | |
75 | | bool endOfData() const { return eosIntern(); } |
76 | | bool isStereo() const { |
77 | | // The digital music in the ITE Mac demo version is not stereo |
78 | | return _vm->getFeatures() & GF_MONO_MUSIC ? false : true; |
79 | | } |
80 | | int getRate() const { return 11025; } |
81 | | }; |
82 | | |
83 | | DigitalMusicInputStream::DigitalMusicInputStream(SagaEngine *vm, ResourceContext *context, uint32 resourceId, bool looping, uint32 loopStart) |
84 | | : _vm(vm), _context(context), _finished(false), _looping(looping), _bufferEnd(_buf + BUFFER_SIZE) { |
85 | | |
86 | | byte compressedHeader[10]; |
87 | | |
88 | | resourceData = context->getResourceData(resourceId); |
89 | | _file = context->getFile(resourceData); |
90 | | |
91 | | _compressedStream = NULL; |
92 | | |
93 | | if (context->isCompressed) { |
94 | | // Read compressed header to determine compression type |
95 | | _file->seek((long)resourceData->offset, SEEK_SET); |
96 | | _file->read(compressedHeader, 9); |
97 | | |
98 | | if (compressedHeader[0] == char(0)) { |
99 | | soundType = kSoundMP3; |
100 | | } else if (compressedHeader[0] == char(1)) { |
101 | | soundType = kSoundOGG; |
102 | | } else if (compressedHeader[0] == char(2)) { |
103 | | soundType = kSoundFLAC; |
104 | | } |
105 | | |
106 | | createCompressedStream(); |
107 | | } |
108 | | |
109 | | // Determine the end position |
110 | | _filePos = resourceData->offset; |
111 | | _endPos = _filePos + resourceData->size; |
112 | | |
113 | | if (_compressedStream != NULL) { |
114 | | _filePos += 9; // skip compressed header |
115 | | _endPos -= 9; // decrease size by the size of the compressed header |
116 | | } |
117 | | |
118 | | _startPos = _filePos + loopStart; |
119 | | if (_startPos >= _endPos) |
120 | | _startPos = _filePos; |
121 | | |
122 | | // Read in initial data |
123 | | refill(); |
124 | | } |
125 | | |
126 | | DigitalMusicInputStream::~DigitalMusicInputStream() { |
127 | | delete _compressedStream; |
128 | | } |
129 | | |
130 | | void DigitalMusicInputStream::createCompressedStream() { |
131 | | #if defined(USE_MAD) || defined(USE_VORBIS) || defined(USE_FLAC) |
132 | | uint numLoops = _looping ? 0 : 1; |
133 | | #endif |
134 | | _memoryStream = _file->readStream(resourceData->size - 9); |
135 | | |
136 | | switch (soundType) { |
137 | | #ifdef USE_MAD |
138 | | case kSoundMP3: |
139 | | debug(1, "Playing MP3 compressed digital music"); |
140 | | _compressedStream = Audio::makeMP3Stream(_memoryStream, true, 0, 0, numLoops); |
141 | | break; |
142 | | #endif |
143 | | #ifdef USE_VORBIS |
144 | | case kSoundOGG: |
145 | | debug(1, "Playing OGG compressed digital music"); |
146 | | _compressedStream = Audio::makeVorbisStream(_memoryStream, true, 0, 0, numLoops); |
147 | | break; |
148 | | #endif |
149 | | #ifdef USE_FLAC |
150 | | case kSoundFLAC: |
151 | | debug(1, "Playing FLAC compressed digital music"); |
152 | | _compressedStream = Audio::makeFlacStream(_memoryStream, true, 0, 0, numLoops); |
153 | | break; |
154 | | #endif |
155 | | default: |
156 | | // Unknown compression |
157 | | error("Trying to play compressed digital music, but the compression is not known"); |
158 | | break; |
159 | | } |
160 | | } |
161 | | |
162 | | int DigitalMusicInputStream::readBuffer(int16 *buffer, const int numSamples) { |
163 | | if (_compressedStream != NULL) |
164 | | return _compressedStream->readBuffer(buffer, numSamples); |
165 | | |
166 | | int samples = 0; |
167 | | int len = 0; |
168 | | |
169 | | while (samples < numSamples && !eosIntern()) { |
170 | | len = MIN(numSamples - samples, (int) (_bufferEnd - _pos)); |
171 | | memcpy(buffer, _pos, len * 2); |
172 | | buffer += len; |
173 | | _pos += len; |
174 | | samples += len; |
175 | | if (_pos >= _bufferEnd) |
176 | | refill(); |
177 | | } |
178 | | return samples; |
179 | | } |
180 | | |
181 | | void DigitalMusicInputStream::refill() { |
182 | | if (_finished) |
183 | | return; |
184 | | |
185 | | uint32 lengthLeft; |
186 | | byte *ptr = (byte *) _buf; |
187 | | |
188 | | _file->seek(_filePos, SEEK_SET); |
189 | | |
190 | | if (_looping) |
191 | | lengthLeft = 2 * BUFFER_SIZE; |
192 | | else |
193 | | lengthLeft = MIN((uint32) (2 * BUFFER_SIZE), _endPos - _filePos); |
194 | | |
195 | | while (lengthLeft > 0) { |
196 | | uint32 len = _file->read(ptr, MIN(lengthLeft, _endPos - _file->pos())); |
197 | | |
198 | | if (len & 1) |
199 | | len--; |
200 | | |
201 | | #ifdef SCUMM_BIG_ENDIAN |
202 | | if (!_context->isBigEndian) { |
203 | | #else |
204 | | if (_context->isBigEndian) { |
205 | | #endif |
206 | | uint16 *ptr16 = (uint16 *)ptr; |
207 | | for (uint32 i = 0; i < (len / 2); i++) |
208 | | ptr16[i] = SWAP_BYTES_16(ptr16[i]); |
209 | | } |
210 | | |
211 | | lengthLeft -= len; |
212 | | ptr += len; |
213 | | |
214 | | if (lengthLeft > 0) |
215 | | _file->seek(_startPos); |
216 | | } |
217 | | |
218 | | _filePos = _file->pos(); |
219 | | _pos = _buf; |
220 | | _bufferEnd = (int16 *)ptr; |
221 | | |
222 | | if (!_looping && _filePos >= _endPos) { |
223 | | _finished = true; |
224 | | } |
225 | | } |
226 | | |
227 | | |
484 | | // digital music |
485 | | audioStream = new DigitalMusicInputStream(_vm, _digitalMusicContext, resourceId - 9, flags == MUSIC_LOOP, loopStart); |
| 282 | // Digital music |
| 283 | ResourceData *resourceData = _digitalMusicContext->getResourceData(resourceId - 9); |
| 284 | Common::File *musicFile = _digitalMusicContext->getFile(resourceData); |
| 285 | musicFile->seek((long)resourceData->offset, SEEK_SET); |
| 286 | |
| 287 | if (!_digitalMusicContext->isCompressed) { |
| 288 | // Preload the music buffer |
| 289 | // TODO: Stream music from disk instead of preloading it |
| 290 | byte *buffer = new byte[resourceData->size]; |
| 291 | musicFile->read(buffer, resourceData->size); |
| 292 | byte musicFlags = Audio::Mixer::FLAG_AUTOFREE | Audio::Mixer::FLAG_STEREO | |
| 293 | Audio::Mixer::FLAG_16BITS | Audio::Mixer::FLAG_LITTLE_ENDIAN; |
| 294 | if (flags == MUSIC_LOOP) |
| 295 | musicFlags |= Audio::Mixer::FLAG_LOOP; |
| 296 | |
| 297 | audioStream = Audio::makeLinearInputStream(buffer, resourceData->size, 11025, musicFlags, loopStart, 0); |
| 298 | } else { |
| 299 | // Read compressed header to determine compression type |
| 300 | byte identifier = musicFile->readByte(); |
| 301 | musicFile->readUint16LE(); // skip frequency |
| 302 | musicFile->readUint32LE(); // skip sample size |
| 303 | musicFile->readUint16LE(); // skip sample bits and stereo flag |
| 304 | |
| 305 | Common::SeekableSubReadStream *musicStream = new Common::SeekableSubReadStream(musicFile, |
| 306 | (uint32)resourceData->offset + 9, (uint32)resourceData->offset + resourceData->size - 9); |
| 307 | |
| 308 | if (identifier == byte(0)) { // MP3 |
| 309 | #ifdef USE_MAD |
| 310 | audioStream = Audio::makeMP3Stream(musicStream, false, 0, 0, (flags == MUSIC_LOOP ? 0 : 1)); |
| 311 | #endif |
| 312 | } else if (identifier == byte(1)) { // OGG |
| 313 | #ifdef USE_VORBIS |
| 314 | audioStream = Audio::makeVorbisStream(musicStream, false, 0, 0, (flags == MUSIC_LOOP ? 0 : 1)); |
| 315 | #endif |
| 316 | } else if (identifier == byte(2)) { // FLAC |
| 317 | #ifdef USE_FLAC |
| 318 | audioStream = Audio::makeFlacStream(musicStream, false, 0, 0, (_looping ? 0 : 1)); |
| 319 | #endif |
| 320 | } |
| 321 | } |