Ticket #9066: saga-itecd-music-v2.patch

File saga-itecd-music-v2.patch, 9.7 KB (added by bluegr, 15 years ago)

SAGA ITE CD music patch v2, with streaming of compressed audio from disk

  • music.cpp

     
    4141#define BUFFER_SIZE 4096
    4242#define MUSIC_SUNSPOT 26
    4343
    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 
    22844MusicPlayer::MusicPlayer(MidiDriver *driver) : _parser(0), _driver(driver), _looping(false), _isPlaying(false), _passThrough(false), _isGM(false) {
    22945        memset(_channel, 0, sizeof(_channel));
    23046        _masterVolume = 0;
     
    455271                realTrackNumber = resourceId + 1;
    456272        }
    457273
    458         // Try to open standalone digital track
    459         char trackName[2][16];
    460         sprintf(trackName[0], "track%d", realTrackNumber);
    461         sprintf(trackName[1], "track%02d", realTrackNumber);
    462         Audio::AudioStream *stream = 0;
    463         for (int i = 0; i < 2; ++i) {
    464                 // We multiply by 40 / 3 = 1000 / 75 to convert frames to milliseconds
    465                 // FIXME: Do we really want a duration of 10000 frames = 133 seconds, or is that just a random value?
    466                 stream = Audio::AudioStream::openStreamFile(trackName[i], 0, 10000 * 40 / 3, (flags == MUSIC_LOOP) ? 0 : 1);
    467                 if (stream) {
    468                         _mixer->playInputStream(Audio::Mixer::kMusicSoundType, &_musicHandle, stream);
    469                         _digitalMusic = true;
    470                         return;
    471                 }
    472         }
    473 
    474274        if (_vm->getGameId() == GID_ITE) {
    475275                if (resourceId >= 9 && resourceId <= 34) {
    476276                        if (_digitalMusicContext != NULL) {
    477                                 //TODO: check resource size
    478277                                loopStart = 0;
    479278                                // fix ITE sunstatm/sunspot score
    480                                 if ((_vm->getGameId() == GID_ITE) && (resourceId == MUSIC_SUNSPOT)) {
     279                                if (resourceId == MUSIC_SUNSPOT)
    481280                                        loopStart = 4 * 18727;
    482                                 }
    483281
    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                                }
    486322                        }
    487323                }
    488324        }
  • sound.cpp

     
    9292                                        buffer.size, buffer.frequency, flags, -1, volume);
    9393        } else {
    9494                Audio::AudioStream *stream = NULL;
    95 #if defined(USE_MAD) || defined(USE_VORBIS) || defined(USE_FLAC)
    96                 MemoryReadStream *tmp = NULL;
    97 #endif
     95                Common::SeekableSubReadStream *soundStream =
     96                                new Common::SeekableSubReadStream(buffer.soundFile, (uint32)buffer.fileOffset + 9,
     97                                (uint32)buffer.fileOffset + buffer.size - 9);
    9898
    9999                switch (buffer.soundType) {
    100100#ifdef USE_MAD
    101101                        case kSoundMP3:
    102                                 debug(1, "Playing MP3 compressed sound");
    103                                 buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET);
    104                                 tmp = buffer.soundFile->readStream(buffer.size);
    105                                 assert(tmp);
    106                                 stream = Audio::makeMP3Stream(tmp, true);
     102                                stream = Audio::makeMP3Stream(soundStream, true);
    107103                                break;
    108104#endif
    109105#ifdef USE_VORBIS
    110106                        case kSoundOGG:
    111                                 debug(1, "Playing OGG compressed sound");
    112                                 buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET);
    113                                 tmp = buffer.soundFile->readStream(buffer.size);
    114                                 assert(tmp);
    115                                 stream = Audio::makeVorbisStream(tmp, true);
     107                                stream = Audio::makeVorbisStream(soundStream, true);
    116108                                break;
    117109#endif
    118110#ifdef USE_FLAC
    119111                        case kSoundFLAC:
    120                                 debug(1, "Playing FLAC compressed sound");
    121                                 buffer.soundFile->seek((long)buffer.fileOffset, SEEK_SET);
    122                                 tmp = buffer.soundFile->readStream(buffer.size);
    123                                 assert(tmp);
    124                                 stream = Audio::makeFlacStream(tmp, true);
     112                                stream = Audio::makeFlacStream(soundStream, true);
    125113                                break;
    126114#endif
    127115                        default: