Ticket #8460: kyra_sound_v2.patch

File kyra_sound_v2.patch, 14.3 KB (added by lordhoto, 15 years ago)

patch against todays cvs

  • kyra/kyra.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/kyra/kyra.cpp ./scummvm/kyra/kyra.cpp
    old new  
    142142                _system->initSize(320, 200);
    143143        _system->endGFXTransaction();
    144144
    145         int midiDrv = MidiDriver::detectMusicDriver(MDT_NATIVE | MDT_ADLIB | MDT_PREFER_NATIVE);
     145        // for now we prefer MIDI-to-Adlib conversion over native midi
     146        int midiDrv = MidiDriver::detectMusicDriver(MDT_NATIVE | MDT_ADLIB/* | MDT_PREFER_NATIVE*/);
    146147        bool native_mt32 = (ConfMan.getBool("native_mt32") || (midiDrv == MD_MT32));
    147148
    148149        MidiDriver *driver = MidiDriver::createMidi(midiDrv);
     
    158159        assert(_midi);
    159160        _midi->hasNativeMT32(native_mt32);
    160161        _midi->setVolume(255);
    161 
     162       
    162163        _res = new Resource(this);
    163164        assert(_res);
    164165        _screen = new Screen(this, _system);
     
    504505        _skipIntroFlag = true; // only true if user already played the game once
    505506        _seq_copyViewOffs = true;
    506507        _screen->setFont(Screen::FID_8_FNT);
    507 //      snd_kyraPlayTheme(0);
     508        snd_playTheme(MIDI_INTRO, 2);
     509        snd_setSoundEffectFile(MIDI_INTRO);
    508510        setTalkCoords(144);
    509511        for (int i = 0; i < ARRAYSIZE(introProcTable) && !seq_skipSequence(); ++i) {
    510512                (this->*introProcTable[i])();
     
    947949                        }
    948950                        break;
    949951                case 24: { // sound related
    950                                 seqData++;
    951                                 warning("Sequence opcode 24 skipped");
     952                                uint8 param = *seqData++;
     953                                waitTicks(3);
     954                                snd_playSoundEffect(param);
    952955                        }
    953956                        break;
    954957                case 25: { // sound related
    955                                 seqData++;
    956                                 warning("Sequence opcode 25 skipped");
     958                                uint8 param = *seqData++;
     959                                snd_seqMessage(param);
    957960                        }
    958961                        break;
    959962                case 26:
  • kyra/kyra.h

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/kyra/kyra.h ./scummvm/kyra/kyra.h
    old new  
    8888class Screen;
    8989
    9090class KyraEngine : public Engine {
     91        friend class MusicPlayer;
    9192public:
    9293
    9394        enum {
     
    109110
    110111        typedef void (KyraEngine::*IntroProc)();
    111112
     113        enum {
     114                MIDI_INTRO = 0,
     115                MIDI_KYRAMISC = 11
     116        };
     117
    112118protected:
    113119
    114120        int go();
     
    149155        uint16 wsa_getNumFrames(WSAMovieV1 *wsa) const;
    150156        void wsa_play(WSAMovieV1 *wsa, int frameNum, int x, int y, int pageNum);
    151157        void wsa_processFrame(WSAMovieV1 *wsa, int frameNum, uint8 *dst);
     158
     159        void snd_playTheme(int file, int track = 0);
     160        void snd_playTrack(int track);
     161        void snd_startTrack();
     162        void snd_haltTrack();
     163        void snd_setSoundEffectFile(int file);
     164        void snd_playSoundEffect(int track);
     165        void snd_seqMessage(int msg);
    152166               
    153167        uint8 _game;
    154168        bool _fastMode;
  • kyra/sound.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/kyra/sound.cpp ./scummvm/kyra/sound.cpp
    old new  
    2222#include "common/stdafx.h"
    2323#include "kyra/resource.h"
    2424#include "kyra/sound.h"
     25#include "common/system.h"
    2526
    2627namespace Kyra {
    2728
    28 MusicPlayer::MusicPlayer(MidiDriver* driver, KyraEngine* engine) {
     29MusicPlayer::MusicPlayer(MidiDriver *driver, KyraEngine *engine) {
    2930        _engine = engine;
    3031        _driver = driver;
    3132        _passThrough = false;
    32         _isPlaying = _nativeMT32 = false;
    33 
    34         memset(_channel, 0, sizeof(MidiChannel*) * 16);
    35         memset(_channelVolume, 255, sizeof(uint8) * 16);
     33        _eventFromMusic = false;
     34        _fadeMusicOut = _sfxIsPlaying = false;
     35        _isPlaying = _isLooping = _nativeMT32 = false;
     36        _soundEffect = _parser = 0;
     37        _soundEffectSource = _parserSource = 0;
     38
     39        memset(_channel, 0, sizeof(MidiChannel*) * 32);
     40        memset(_channelVolume, 50, sizeof(uint8) * 16);
     41        _channelVolume[10] = 100;
     42        for (int i = 0; i < 16; ++i) {
     43                _virChannel[i] = i;
     44        }
    3645        _volume = 0;
    3746
    3847        int ret = open();
     
    5665                return;
    5766
    5867        _volume = volume;
    59         for (int i = 0; i < 16; ++i) {
     68        for (int i = 0; i < 32; ++i) {
    6069                if (_channel[i]) {
    61                         _channel[i]->volume(_channelVolume[i] * _volume / 255);
     70                        if (i >= 16) {
     71                                _channel[i]->volume(_channelVolume[i - 16] * _volume / 255);
     72                        } else {
     73                                _channel[i]->volume(_channelVolume[i] * _volume / 255);
     74                        }
    6275                }
    6376        }
    6477}
     
    8497
    8598void MusicPlayer::send(uint32 b) {
    8699        if (_passThrough) {
     100                if ((b & 0xFFF0) == 0x007BB0)
     101                        return;
    87102                _driver->send(b);
    88103                return;
    89104        }
    90105
    91106        uint8 channel = (byte)(b & 0x0F);
     107        if (((b & 0xFFF0) == 0x6FB0 || (b & 0xFFF0) == 0x6EB0) && channel != 9) {
     108                if (_virChannel[channel] == channel) {
     109                        _virChannel[channel] = channel + 16;
     110                        if (!_channel[_virChannel[channel]])
     111                                _channel[_virChannel[channel]] = _driver->allocateChannel();
     112                        _channel[_virChannel[channel]]->volume(_channelVolume[channel] * _volume / 255);
     113                }
     114                return;
     115        }
     116
    92117        if ((b & 0xFFF0) == 0x07B0) {
    93118                // Adjust volume changes by master volume
    94119                uint8 volume = (uint8)((b >> 16) & 0x7F);
     
    104129                        return;
    105130        }
    106131
    107         if (!_channel[channel])
    108                 _channel[channel] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
    109         if (_channel[channel])
    110                 _channel[channel]->send(b);
     132        if (!_channel[_virChannel[channel]]) {
     133                _channel[_virChannel[channel]] = (channel == 9) ? _driver->getPercussionChannel() : _driver->allocateChannel();
     134                _channel[_virChannel[channel]]->volume(_channelVolume[channel] * _volume / 255);
     135        }
     136        if (_channel[_virChannel[channel]])
     137                _channel[_virChannel[channel]]->send(b);
    111138}
    112139
    113140void MusicPlayer::metaEvent(byte type, byte *data, uint16 length) {
    114141        switch (type) {
    115142        case 0x2F:      // End of Track
    116                 _parser->jumpToTick(0);
     143                if (_eventFromMusic) {
     144                        if (!_isLooping) {
     145                                _isPlaying = false;
     146                        }
     147
     148                        // remap all channels
     149                        for (int i = 0; i < 16; ++i) {
     150                                _virChannel[i] = i;
     151                        }
     152
     153                } else {
     154                        _sfxIsPlaying = false;
     155                }
    117156                break;
    118157        default:
    119                 warning("Unhandled meta event: 0x%02x", type);
     158                _driver->metaEvent(type, data, length);
    120159                break;
    121160        }
    122161}
    123162
    124 void MusicPlayer::playMusic(const char* file) {
     163void MusicPlayer::playMusic(const char *file) {
    125164        uint32 size;
    126165        uint8 *data = (_engine->resource())->fileData(file, &size);
    127166
     
    133172        playMusic(data, size);
    134173}
    135174
    136 void MusicPlayer::playMusic(uint8* data, uint32 size) {
    137         if (_isPlaying)
    138                 stopMusic();
     175void MusicPlayer::playMusic(uint8 *data, uint32 size) {
     176        stopMusic();
    139177
     178        _parserSource = data;
    140179        _parser = MidiParser::createParser_XMIDI();
    141180        assert(_parser);
    142181
     
    150189        _parser->setTrack(0);
    151190        _parser->setMidiDriver(this);
    152191        _parser->setTimerRate(getBaseTempo());
     192        _parser->property(MidiParser::mpAutoLoop, false);
     193}
     194
     195void MusicPlayer::loadSoundEffectFile(const char *file) {
     196        uint32 size;
     197        uint8 *data = (_engine->resource())->fileData(file, &size);
     198
     199        if (!data) {
     200                warning("couldn't load '%s'", file);
     201                return;
     202        }
     203
     204        loadSoundEffectFile(data, size);
     205}
     206
     207void MusicPlayer::loadSoundEffectFile(uint8 *data, uint32 size) {
     208        stopSoundEffect();
     209
     210        _soundEffectSource = data;
     211        _soundEffect = MidiParser::createParser_XMIDI();
     212        assert(_soundEffect);
     213
     214        if (!_soundEffect->loadMusic(data, size)) {
     215                warning("Error reading track!");
     216                delete _parser;
     217                _parser = 0;
     218                return;
     219        }
    153220
    154         _isPlaying = true;
     221        _soundEffect->setTrack(0);
     222        _soundEffect->setMidiDriver(this);
     223        _soundEffect->setTimerRate(getBaseTempo());
     224        _soundEffect->property(MidiParser::mpAutoLoop, false);
    155225}
    156226
    157227void MusicPlayer::stopMusic() {
     228        _isLooping = false;
    158229        _isPlaying = false;
    159230        if (_parser) {
    160231                _parser->unloadMusic();
    161232                delete _parser;
    162                 _parser = NULL;
     233                _parser = 0;
     234                delete [] _parserSource;
     235                _parserSource = 0;
     236        }
     237}
     238
     239void MusicPlayer::stopSoundEffect() {
     240        _sfxIsPlaying = false;
     241        if (_soundEffect) {
     242                _soundEffect->unloadMusic();
     243                delete _soundEffect;
     244                _soundEffect = 0;
     245                delete [] _soundEffectSource;
     246                _soundEffectSource = 0;
    163247        }
    164248}
    165249
    166250void MusicPlayer::onTimer(void *refCon) {
    167251        MusicPlayer *music = (MusicPlayer *)refCon;
    168         if (music->_isPlaying)
    169                 music->_parser->onTimer();
     252
     253        // this should be set to the fadeToBlack value
     254        const static uint32 musicFadeTime = 2 * 1000;
     255        if (music->_fadeMusicOut && music->_fadeStartTime + musicFadeTime > music->_engine->_system->getMillis()) {
     256                byte volume = (byte)((musicFadeTime - (music->_engine->_system->getMillis() - music->_fadeStartTime)) * 255 / musicFadeTime);
     257                music->setVolume(volume);
     258        } else if(music->_fadeStartTime) {
     259                music->setVolume(255);
     260                music->_fadeStartTime = 0;
     261                music->_fadeMusicOut = false;
     262        }
     263
     264        if (music->_isPlaying) {
     265                if (music->_parser) {
     266                        music->_eventFromMusic = true;
     267                        music->_parser->onTimer();
     268                }
     269        }
     270
     271        if (music->_sfxIsPlaying) {
     272                if (music->_soundEffect) {
     273                        music->_eventFromMusic = false;
     274                        music->_soundEffect->onTimer();
     275                }
     276        }
    170277}
    171278
    172 void MusicPlayer::playTrack(uint8 track) {
     279void MusicPlayer::playTrack(uint8 track, bool loop) {
    173280        if (_parser) {
    174281                _isPlaying = true;
     282                _isLooping = loop;
    175283                _parser->setTrack(track);
    176284                _parser->jumpToTick(0);
     285                _parser->setTempo(1);
     286                _parser->property(MidiParser::mpAutoLoop, loop);
     287        }
     288}
     289
     290void MusicPlayer::playSoundEffect(uint8 track) {
     291        if (_soundEffect) {
     292                _sfxIsPlaying = true;
     293                _soundEffect->setTrack(track);
     294                _soundEffect->jumpToTick(0);
     295                _soundEffect->property(MidiParser::mpAutoLoop, false);
     296        }
     297}
     298
     299void MusicPlayer::beginFadeOut() {
     300        // this should be something like fade out...
     301        _fadeMusicOut = true;
     302        _fadeStartTime = _engine->_system->getMillis();
     303}
     304
     305void KyraEngine::snd_playTheme(int file, int track) {
     306        debug(9, "snd_playTheme(%d)", file);
     307        switch(file) {
     308                case MIDI_INTRO:
     309                        _midi->playMusic("INTRO.XMI");
     310                        break;
     311
     312                default:
     313                        warning("Unkown music file: %d", file);
     314                        break;
     315        }
     316
     317        _midi->playTrack(track, false);
     318}
     319
     320void KyraEngine::snd_playTrack(int track) {
     321        debug(9, "snd_playTrack(%d)", track);
     322        _midi->playTrack(track, false);
     323}
     324
     325void KyraEngine::snd_setSoundEffectFile(int file) {
     326        debug(9, "snd_setSoundEffectFile(%d)", file);
     327        switch(file) {
     328                case MIDI_INTRO:
     329                        _midi->loadSoundEffectFile("INTRO.XMI");
     330                        break;
     331
     332                case MIDI_KYRAMISC:
     333                        _midi->loadSoundEffectFile("KYRAMISC.XMI");
     334                        break;
     335
     336                default:
     337                        break;
     338        }
     339}
     340
     341void KyraEngine::snd_playSoundEffect(int track) {
     342        debug(9, "snd_playSoundEffect(%d)", track);
     343        _midi->playSoundEffect(track);
     344}
     345
     346void KyraEngine::snd_startTrack() {
     347        _midi->startTrack();
     348}
     349
     350void KyraEngine::snd_haltTrack() {
     351        _midi->haltTrack();
     352}
     353
     354void KyraEngine::snd_seqMessage(int msg) {
     355        debug(9, "snd_seqMessage(%.02d)", msg);
     356        switch(msg) {
     357                case 0:
     358                        // nothing to do here...
     359                        break;
     360
     361                case 1:
     362                        _midi->beginFadeOut();
     363                        break;
     364
     365                case 56:
     366                        snd_playTheme(MIDI_INTRO, 3);
     367                        break;
     368
     369                case 57:
     370                        snd_playTheme(MIDI_INTRO, 4);
     371                        break;
     372
     373                case 58:
     374                        snd_playTheme(MIDI_INTRO, 5);
     375                        break;
     376
     377                default:
     378                        warning("Unknown seq. message: %.02d", msg);
     379                        break;
    177380        }
    178381}
    179382
  • kyra/sound.h

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/kyra/sound.h ./scummvm/kyra/sound.h
    old new  
    2929#include "kyra/kyra.h"
    3030
    3131namespace Kyra {
    32         class MusicPlayer : public MidiDriver {
    3332
    34         public:
     33class MusicPlayer : public MidiDriver {
    3534
    36                 MusicPlayer(MidiDriver* driver, KyraEngine* engine);
    37                 ~MusicPlayer();
     35public:
    3836
    39                 void setVolume(int volume);
    40                 int getVolume() { return _volume; }
     37        MusicPlayer(MidiDriver *driver, KyraEngine *engine);
     38        ~MusicPlayer();
    4139
    42                 void hasNativeMT32(bool nativeMT32) { _nativeMT32 = nativeMT32; }
     40        void setVolume(int volume);
     41        int getVolume() { return _volume; }
     42
     43        void hasNativeMT32(bool nativeMT32) { _nativeMT32 = nativeMT32; }
     44        bool isMT32() { return _nativeMT32; }
     45
     46        void playMusic(const char* file);
     47        void playMusic(uint8* data, uint32 size);
     48        void stopMusic();
     49
     50        void playTrack(uint8 track, bool looping = true);
     51        void haltTrack() { _isPlaying = false; }
     52        void startTrack() { _isPlaying = true; }
     53        void setPassThrough(bool b)     { _passThrough = b; }
     54
     55        void loadSoundEffectFile(const char* file);
     56        void loadSoundEffectFile(uint8* data, uint32 size);
     57        void stopSoundEffect();
     58
     59        void playSoundEffect(uint8 track);
     60
     61        void beginFadeOut();
     62
     63        //MidiDriver interface implementation
     64        int open();
     65        void close();
     66        void send(uint32 b);
     67        void metaEvent(byte type, byte *data, uint16 length);
     68
     69        void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
     70        uint32 getBaseTempo(void) { return _driver ? _driver->getBaseTempo() : 0; }
     71
     72        //Channel allocation functions
     73        MidiChannel *allocateChannel()          { return 0; }
     74        MidiChannel *getPercussionChannel()     { return 0; }
     75
     76protected:
     77
     78        static void onTimer(void *data);
     79
     80        MidiChannel* _channel[32];
     81        int _virChannel[16];
     82        uint8 _channelVolume[16];
     83        MidiDriver* _driver;
     84        bool _nativeMT32;
     85        bool _passThrough;
     86        uint8 _volume;
     87        bool _isPlaying;
     88        bool _sfxIsPlaying;
     89        uint32 _fadeStartTime;
     90        bool _fadeMusicOut;
     91        bool _isLooping;
     92        bool _eventFromMusic;
     93        MidiParser *_parser;
     94        byte *_parserSource;
     95        MidiParser *_soundEffect;
     96        byte *_soundEffectSource;
     97        KyraEngine *_engine;
    4398
    44                 void playMusic(const char* file);
    45                 void playMusic(uint8* data, uint32 size);
    46                 void stopMusic();
     99};
    47100
    48                 void playTrack(uint8 track);
    49                 void setPassThrough(bool b)     { _passThrough = b; }
    50 
    51                 //MidiDriver interface implementation
    52                 int open();
    53                 void close();
    54                 void send(uint32 b);
    55                 void metaEvent(byte type, byte *data, uint16 length);
    56 
    57                 void setTimerCallback(void *timerParam, void (*timerProc)(void *)) { }
    58                 uint32 getBaseTempo(void) { return _driver ? _driver->getBaseTempo() : 0; }
    59 
    60                 //Channel allocation functions
    61                 MidiChannel *allocateChannel()          { return 0; }
    62                 MidiChannel *getPercussionChannel()     { return 0; }
    63 
    64         protected:
    65 
    66                 static void onTimer(void *data);
    67 
    68                 MidiChannel* _channel[16];
    69                 uint8 _channelVolume[16];
    70                 MidiDriver* _driver;
    71                 bool _nativeMT32;
    72                 bool _passThrough;
    73                 uint8 _volume;
    74                 bool _isPlaying;
    75                 MidiParser* _parser;
    76                 KyraEngine* _engine;
    77 
    78         };
    79101} // end of namespace Kyra
    80102
    81103#endif
  • sound/midiparser_xmidi.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/sound/midiparser_xmidi.cpp ./scummvm/sound/midiparser_xmidi.cpp
    old new  
    5353        uint32 value = 0;
    5454        int i;
    5555
    56         for (i = 0; i < 4; ++i) {
     56        // Kyra seems to handle it like this
     57        // not only with 4 bytes at maximum
     58        for (i = 0; true; ++i) {
    5759                if (pos[0] & 0x80)
    5860                        break;
    5961                value += *pos++;