[Scummvm-cvs-logs] SF.net SVN: scummvm:[45923] scummvm/trunk/engines/sci

thebluegr at users.sourceforge.net thebluegr at users.sourceforge.net
Sun Nov 15 15:14:49 CET 2009


Revision: 45923
          http://scummvm.svn.sourceforge.net/scummvm/?rev=45923&view=rev
Author:   thebluegr
Date:     2009-11-15 14:14:49 +0000 (Sun, 15 Nov 2009)

Log Message:
-----------
- Started importing the music code from Greg's SCI engine
- Simplified some sound version checks

Modified Paths:
--------------
    scummvm/trunk/engines/sci/module.mk
    scummvm/trunk/engines/sci/sfx/soundcmd.cpp
    scummvm/trunk/engines/sci/sfx/soundcmd.h

Added Paths:
-----------
    scummvm/trunk/engines/sci/sfx/music.cpp
    scummvm/trunk/engines/sci/sfx/music.h

Modified: scummvm/trunk/engines/sci/module.mk
===================================================================
--- scummvm/trunk/engines/sci/module.mk	2009-11-15 12:22:21 UTC (rev 45922)
+++ scummvm/trunk/engines/sci/module.mk	2009-11-15 14:14:49 UTC (rev 45923)
@@ -70,6 +70,7 @@
 	sfx/audio.o \
 	sfx/core.o \
 	sfx/iterator.o \
+	sfx/music.o \
 	sfx/songlib.o \
 	sfx/soundcmd.o \
 	sfx/seq/gm.o \

Added: scummvm/trunk/engines/sci/sfx/music.cpp
===================================================================
--- scummvm/trunk/engines/sci/sfx/music.cpp	                        (rev 0)
+++ scummvm/trunk/engines/sci/sfx/music.cpp	2009-11-15 14:14:49 UTC (rev 45923)
@@ -0,0 +1,705 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "sci/sci.h"
+#include "sci/resource.h"
+#include "sci/sfx/music.h"
+#include "sound/audiostream.h"
+#include "common/config-manager.h"
+
+namespace Sci {
+
+static const int nMidiParams[] = { 2, 2, 2, 2, 1, 1, 2, 0 };
+
+static int f_compare(const void *arg1, const void *arg2) {
+	return ((sciSound *)arg2)->prio - ((sciSound *)arg1)->prio;
+}
+
+SciMusic::SciMusic() {
+}
+
+SciMusic::~SciMusic() {
+	if (_pMidiDrv) {
+		_pMidiDrv->close();
+		delete _pMidiDrv;
+	}
+}
+//----------------------------------------
+void SciMusic::init() {
+	// system init
+	_pMixer = g_system->getMixer();
+	_pMixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt(
+			"sfx_volume"));
+	_pMixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType,
+			ConfMan.getInt("speech_volume"));
+	_pMixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType,
+			ConfMan.getInt("music_volume"));
+	// SCI sound init
+	_dwTempo = 0;
+	_midiType = MidiDriver::detectMusicDriver(MDT_MIDI | MDT_ADLIB | MDT_PCSPK
+			| MDT_PREFER_MIDI);
+	_pMidiDrv = MidiDriver::createMidi(_midiType);
+	if (_pMidiDrv) {
+		_pMidiDrv->open();
+		_pMidiDrv->setTimerCallback(this, &miditimerCallback);
+		_dwTempo = _pMidiDrv->getBaseTempo();
+	} else
+		warning("Can't initialise music driver");
+	_bMultiMidi = ConfMan.getBool("multi_midi");
+}
+//----------------------------------------
+bool SciMusic::saveState(Common::OutSaveFile *pFile) {
+	// TODO
+#if 0
+	pFile->writeString("AUDIO\n");
+	// palylist
+	int sz = _playList.size();
+	pFile->writeUint16LE(sz);
+	for(int i = 0; i < sz; i++) {
+		pFile->writeUint16LE(ptr2heap((byte*)_playList[i]));
+		// member variable
+		pFile->writeUint16LE(_audVolNum);
+		pFile->writeByte(_langID);
+		pFile->writeUint16LE(_audioType);
+		pFile->writeUint16LE(_audioRate);
+		// TODO: current playing stream (hCurrentAud) info
+	}
+#endif
+	return true;
+}
+
+//----------------------------------------
+bool SciMusic::restoreState(Common::InSaveFile *pFile){
+	// TODO
+#if 0
+	if (pFile->readLine() != "AUDIO")
+		return false;
+#endif
+	return true;
+}
+//----------------------------------------
+void SciMusic::stopAll() {
+	_pMixer->stopAll();
+	//audioStop();
+	for(uint i = 0; i < _playList.size(); i++){
+		soundStop(_playList[i]);
+		soundKill(_playList[i]);
+	}
+}
+//----------------------------------------
+void SciMusic::miditimerCallback(void *p) {
+	SciMusic* aud = (SciMusic *)p;
+	aud->onTimer();
+}
+//----------------------------------------
+uint16 SciMusic::soundGetVoices() {
+	uint16 res;
+	switch (_midiType) {
+	case MD_PCSPK:
+		res = 1;
+		break;
+	case MD_PCJR:
+		res = 3;
+		break;
+	case MD_ADLIB:
+		res = 8;
+		break;
+	case MD_MT32:
+		res = 16;
+		break;
+	default:
+		res = 1;
+		break;
+	}
+	return res;
+}
+//----------------------------------------
+void SciMusic::sortPlayList() {
+	sciSound ** pData = _playList.begin();
+	qsort(pData, _playList.size(), sizeof(sciSound *), &f_compare);
+}
+
+void SciMusic::patchSysEx(byte * addr, byte *pdata, int len) {
+	byte *buff = new byte[7 + len + 1];
+	uint16 chk = 0;
+	int i;
+
+	buff[0] = 0x41;
+	buff[1] = 0x10;
+	buff[2] = 0x16;
+	buff[3] = 0x12;
+	buff[4] = addr[0];
+	buff[5] = addr[1];
+	buff[6] = addr[2];
+	for (i = 0; i < len; i++) {
+		buff[7 + i] = pdata[i];
+		chk += pdata[i];
+	}
+	chk += addr[0] + addr[1] + addr[2];
+	buff[7 + i] = 128 - chk % 128;
+	_pMidiDrv->sysEx(buff, len + 8);
+	delete[] buff;
+}
+
+void SciMusic::patchUpdateAddr(byte *addr, int len) {
+	addr[2] += len;
+	if (addr[2] >= 0x7F) {
+		addr[1]++;
+		addr[2] -= 0x80;
+	}
+}
+void SciMusic::loadPatch() {
+	if (_midiType == MD_MT32)
+		loadPatchMT32();
+}
+
+// currently loads patch 1.pat for Roland/MT-32 device
+void SciMusic::loadPatchMT32() {
+	//byte sysText[] = { 0x20, 0, 0 };
+	byte sysMem[] = { 0x5, 0, 0 }; // patch memory
+	byte sysRhytm[] = { 0x3, 0x1, 0x10 }; // rhytm
+	byte sysMsg3[15] = { 0x41, 0x10, 0x16, 0x12, 0x52, 0, 0xA, 0x16, 0x16,
+			0x16, 0x16, 0x16, 0x16, 0x20, 0x80 };
+	byte sysTimbre[] = { 0x8, 0, 0 }; // timbre memory
+	byte sysSystem[] = { 0x10, 0, 4 }; // partial reserve & midi channel
+	byte arr[3][11];
+
+	Resource *res = ((SciEngine *)g_engine)->getResourceManager()->findResource(ResourceId(kResourceTypePatch, 1), 0);
+
+	if (res) {
+		byte *pData = res->data, *p;
+		// welcome message
+		//patchSysEx(sysText, pData + 20, 20);
+		// reading reverb mode, time and level
+		p = pData + 74;
+		for (int i = 0; i < 11; i++) {
+			arr[0][i] = *p++;
+			arr[1][i] = *p++;
+			arr[2][i] = *p++;
+		}
+		// sub_657 - patch memory
+		for (int i = 0; i < 48; i++) {
+			patchSysEx(sysMem, p, 8);
+			patchUpdateAddr(sysMem, 8);
+			p += 8;
+		}
+		// sub_696 - timbre
+		byte dl = *p++, cl = 0;
+		while (dl--) {
+			patchSysEx(sysTimbre, p, 14); // common area
+			patchUpdateAddr(sysTimbre, 14);
+			patchSysEx(sysTimbre, p + 14, 58);// partial 1
+			patchUpdateAddr(sysTimbre, 58);
+			patchSysEx(sysTimbre, p + 72, 58);// partial 2
+			patchUpdateAddr(sysTimbre, 58);
+			patchSysEx(sysTimbre, p + 130, 58);// partial 3
+			patchUpdateAddr(sysTimbre, 58);
+			patchSysEx(sysTimbre, p + 188, 58);// partial 4
+			patchUpdateAddr(sysTimbre, 58);
+			p += 246;
+			cl += 2;
+			sysTimbre[1] = cl;
+			sysTimbre[2] = 0;
+		}
+		// patch memory or rhytm
+		uint16 flag = READ_BE_UINT16(p);
+		p += 2;
+		if (flag == 0xABCD) {
+			// sub_657
+			for (int i = 0; i < 48; i++) {
+				patchSysEx(sysMem, p, 8);
+				patchUpdateAddr(sysMem, 8);
+				p += 8;
+			}
+		} else if (flag == 0xDCBA) {
+			// sub_756
+			for (int i = 0; i < 64; i++) {
+				patchSysEx(sysRhytm, p, 4);
+				patchUpdateAddr(sysRhytm, 4);
+				p += 4;
+			}
+			patchSysEx(sysSystem, p, 18);
+		}
+		// after-init text message
+		//patchSysEx(sysText, pData, 20);
+		// some final sysex
+		_pMidiDrv->sysEx(sysMsg3, 15);
+		// releasing patch resource
+		//g_sci->ResMgr.ResUnload(SCI_RES_PATCH, 1);
+	debug("MT-32 patch loaded");
+	}
+}
+//----------------------------------------
+void SciMusic::soundInitSnd(SoundRes*res, sciSound *pSnd) {
+	//_mutex.lock();
+	SoundRes::tagTrack *pTrack = NULL;
+	switch (_midiType) {
+	case MD_PCSPK:
+		pTrack = res->getTrackByType(SoundRes::kTrackSpeaker);
+		break;
+	case MD_PCJR:
+		pTrack = res->getTrackByType(SoundRes::kTrackTandy);
+		break;
+	case MD_ADLIB:
+		pTrack = res->getTrackByType(SoundRes::kTrackAdlib);
+		break;
+	case MD_MT32:
+		pTrack = res->getTrackByType(SoundRes::kTrackMT32);
+		break;
+	}
+	// attempting to select default MT-32/Roland track
+	if (!pTrack)
+		pTrack = res->getTrackByType(SoundRes::kTrackMT32);
+	if (pTrack) {
+		// if MIDI device is selected but there is no digital track in sound resource
+		// try to use adlib's digital sample if possible
+		if (_midiType <= MD_MT32 && pTrack->nDigital == 0xFF && _bMultiMidi) {
+			if (res->getTrackByType(SoundRes::kTrackAdlib)->nDigital != 0xFF)
+				pTrack = res->getTrackByType(SoundRes::kTrackAdlib);
+		}
+		// play digital sample
+		if (pTrack->nDigital != 0xFF) {
+			byte *pdata = pTrack->aChannels[pTrack->nDigital].ptr;
+			int rate = READ_LE_UINT16(pdata);
+			uint32 size = READ_LE_UINT16(pdata + 2);
+			assert(READ_LE_UINT16(pdata + 4) == 0);	// Possibly a compression flag
+			//assert(READ_LE_UINT16(pdata + 6) == size);
+			if (pSnd->pStreamAud)
+				delete pSnd->pStreamAud;
+			pSnd->pStreamAud = Audio::makeLinearInputStream(pdata + 8, size, rate,
+					Audio::Mixer::FLAG_UNSIGNED, 0, 0);
+			pSnd->hCurrentAud = Audio::SoundHandle();
+		} else {// play MIDI track
+			if (pSnd->pMidiParser == NULL) {
+				pSnd->pMidiParser = new MidiParser_SCI();
+				pSnd->pMidiParser->setMidiDriver(_pMidiDrv);
+				pSnd->pMidiParser->setTimerRate(_dwTempo);
+			}
+			pSnd->pMidiParser->loadMusic(pTrack, pSnd);
+		}
+	}
+	//_mutex.unlock();
+}
+//----------------------------------------
+void SciMusic::onTimer() {
+	_mutex.lock();
+	uint sz = _playList.size();
+	for (uint i = 0; i < sz; i++) {
+		if (_playList[i]->sndStatus != kPlaying)
+			continue;
+		if (_playList[i]->pMidiParser) {
+			if (_playList[i]->FadeStep)
+				doFade(_playList[i]);
+			_playList[i]->pMidiParser->onTimer();
+			_playList[i]->ticker = (uint16)_playList[i]->pMidiParser->getTick();
+		} else if (_playList[i]->pStreamAud) {
+			if (_pMixer->isSoundHandleActive(_playList[i]->hCurrentAud)
+					== false) {
+				_playList[i]->ticker = 0xFFFF;
+				_playList[i]->signal = 0xFFFF;
+				_playList[i]->sndStatus = kStopped;
+			} else
+				_playList[i]->ticker = (uint16)(_pMixer->getSoundElapsedTime(
+						_playList[i]->hCurrentAud) * 0.06);
+		}
+	}//for()
+	_mutex.unlock();
+}
+//---------------------------------------------
+void SciMusic::doFade(sciSound *pSnd) {
+	if (pSnd->FadeTicker)
+		pSnd->FadeTicker--;
+	else {
+		pSnd->FadeTicker = pSnd->FadeTickerStep;
+		if (pSnd->volume + pSnd->FadeStep > pSnd->FadeTo) {
+			pSnd->volume = pSnd->FadeTo;
+			pSnd->FadeStep = 0;
+		} else
+			pSnd->volume += pSnd->FadeStep;
+		pSnd->pMidiParser->setVolume(pSnd->volume);
+	}
+}
+
+//---------------------------------------------
+void SciMusic::soundPlay(sciSound *pSnd) {
+	//_mutex.lock();
+	uint sz = _playList.size(), i;
+	// searching if sound is already in _playList
+	for (i = 0; i < sz && _playList[i] != pSnd; i++)
+		;
+	if (i == sz) {// not found
+		_playList.push_back(pSnd);
+		sortPlayList();
+	}
+
+	if (pSnd->pStreamAud && _pMixer->isSoundHandleActive(pSnd->hCurrentAud)
+			== false)
+		_pMixer->playInputStream(Audio::Mixer::kSFXSoundType, &pSnd->hCurrentAud,
+				pSnd->pStreamAud, -1, pSnd->volume, 0, false);
+	else if (pSnd->pMidiParser) {
+		pSnd->pMidiParser->setVolume(pSnd->volume);
+		if (pSnd->sndStatus == kStopped)
+			pSnd->pMidiParser->jumpToTick(0);
+	}
+	pSnd->sndStatus = kPlaying;
+	//_mutex.unlock();
+}
+//---------------------------------------------
+void SciMusic::soundStop(sciSound *pSnd) {
+	//_mutex.lock();
+	pSnd->sndStatus = kStopped;
+	if (pSnd->pStreamAud)
+		_pMixer->stopHandle(pSnd->hCurrentAud);
+	if (pSnd->pMidiParser)
+		pSnd->pMidiParser->stop();
+	//_mutex.unlock();
+}
+//---------------------------------------------
+void SciMusic::soundSetVolume(sciSound *pSnd, byte volume) {
+	if (pSnd->pStreamAud)
+		_pMixer->setChannelVolume(pSnd->hCurrentAud, volume);
+	else if (pSnd->pMidiParser)
+		pSnd->pMidiParser->setVolume(volume);
+}
+//---------------------------------------------
+void SciMusic::soundSetPriority(sciSound *pSnd, byte prio) {
+	pSnd->prio = prio;
+	sortPlayList();
+}
+//---------------------------------------------
+void SciMusic::soundKill(sciSound *pSnd) {
+	//_mutex.lock();
+	pSnd->sndStatus = kStopped;
+	if (pSnd->pMidiParser) {
+		pSnd->pMidiParser->unloadMusic();
+		delete pSnd->pMidiParser;
+		pSnd->pMidiParser = NULL;
+	}
+	if (pSnd->pStreamAud) {
+		_pMixer->stopHandle(pSnd->hCurrentAud);
+		pSnd->pStreamAud = NULL;
+	}
+
+	uint sz = _playList.size(), i;
+	// searching if sound is already in _playList
+	for (i = 0; i < sz; i++) {
+		if (_playList[i] == pSnd) {
+			_playList.remove_at(i);
+			break;
+		}
+	}
+	//_mutex.unlock();
+}
+//---------------------------------------------
+void SciMusic::soundPause(sciSound *pSnd) {
+	pSnd->sndStatus = kPaused;
+	if (pSnd->pStreamAud)
+		_pMixer->pauseHandle(pSnd->hCurrentAud, true);
+	else if (pSnd->pMidiParser)
+		pSnd->pMidiParser->pause();
+}
+
+//---------------------------------------------
+uint16 SciMusic::soundGetMasterVolume() {
+	return _pMixer->getVolumeForSoundType(Audio::Mixer::kMusicSoundType) * 0xF
+			/ Audio::Mixer::kMaxMixerVolume;
+}
+//---------------------------------------------
+void SciMusic::soundSetMasterVolume(uint16 vol) {
+	vol = vol & 0xF; // 0..15
+	vol = vol * Audio::Mixer::kMaxMixerVolume / 0xF;
+	// TODO:balance volume to prevent music to be too loud
+	_pMixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, vol);
+	_pMixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, vol);
+	_pMixer->setVolumeForSoundType(Audio::Mixer::kSpeechSoundType, vol);
+	_pMixer->setVolumeForSoundType(Audio::Mixer::kPlainSoundType, vol);
+}
+
+//---------------------------------------------
+//  MidiParser_SCI
+//
+MidiParser_SCI::MidiParser_SCI() :
+	MidiParser() {
+	_pMidiData = NULL;
+	// mididata contains delta in 1/60th second
+	// values of ppqn and tempo are found experimentally and may be wrong
+	_ppqn = 1;
+	setTempo(16667);
+}
+//---------------------------------------------
+MidiParser_SCI::~MidiParser_SCI() {
+	unloadMusic();
+}
+//---------------------------------------------
+bool MidiParser_SCI::loadMusic(SoundRes::tagTrack *ptrack, sciSound *psnd) {
+	unloadMusic();
+	_pTrack = ptrack;
+	_pSnd = psnd;
+	setVolume(psnd->volume);
+	midiMixChannels();
+
+	_num_tracks = 1;
+	_tracks[0] = _pMidiData;
+	setTrack(0);
+	_loopTick = 0;
+	return true;
+}
+
+void MidiParser_SCI::unloadMusic() {
+	allNotesOff();
+	resetTracking();
+	_num_tracks = 0;
+	if (_pMidiData) {
+		delete[] _pMidiData;
+		_pMidiData = NULL;
+	}
+}
+
+void MidiParser_SCI::parseNextEvent(EventInfo &info) {
+	info.start = _position._play_pos;
+	info.delta = *(_position._play_pos++);
+
+	// Process the next info.
+	if ((_position._play_pos[0] & 0xF0) >= 0x80)
+		info.event = *(_position._play_pos++);
+	else
+		info.event = _position._running_status;
+	if (info.event < 0x80)
+		return;
+
+	_position._running_status = info.event;
+	switch (info.command()) {
+	case 0xC:
+		info.basic.param1 = *(_position._play_pos++);
+		info.basic.param2 = 0;
+		if (info.channel() == 0xF) {// SCI special case
+			if (info.basic.param1 != 0x7F)
+				_pSnd->signal = info.basic.param1;
+			else
+				_loopTick = _position._play_tick;
+		}
+		break;
+	case 0xD:
+		info.basic.param1 = *(_position._play_pos++);
+		info.basic.param2 = 0;
+		break;
+
+	case 0xB:
+		info.basic.param1 = *(_position._play_pos++);
+		info.basic.param2 = *(_position._play_pos++);
+		if (info.channel() == 0xF) {// SCI special
+			if (info.basic.param1 == 0x60)
+				_pSnd->dataInc++;
+			// BF 50 x - set reverb to x
+			// BF 60 x - dataInc++
+			// BF 52 x - bHold=x
+		}
+		if (info.basic.param1 == 7) // channel volume change -scale it
+			info.basic.param2 = info.basic.param2 * _volume / 0x7F;
+		info.length = 0;
+		break;
+
+	case 0x8:
+	case 0x9:
+	case 0xA:
+	case 0xE:
+		info.basic.param1 = *(_position._play_pos++);
+		info.basic.param2 = *(_position._play_pos++);
+		if (info.command() == 0x9 && info.basic.param2 == 0)
+			info.event = info.channel() | 0x80;
+		info.length = 0;
+		break;
+
+	case 0xF: // System Common, Meta or SysEx event
+		switch (info.event & 0x0F) {
+		case 0x2: // Song Position Pointer
+			info.basic.param1 = *(_position._play_pos++);
+			info.basic.param2 = *(_position._play_pos++);
+			break;
+
+		case 0x3: // Song Select
+			info.basic.param1 = *(_position._play_pos++);
+			info.basic.param2 = 0;
+			break;
+
+		case 0x6:
+		case 0x8:
+		case 0xA:
+		case 0xB:
+		case 0xC:
+		case 0xE:
+			info.basic.param1 = info.basic.param2 = 0;
+			break;
+
+		case 0x0: // SysEx
+			info.length = readVLQ(_position._play_pos);
+			info.ext.data = _position._play_pos;
+			_position._play_pos += info.length;
+			break;
+
+		case 0xF: // META event
+			info.ext.type = *(_position._play_pos++);
+			info.length = readVLQ(_position._play_pos);
+			info.ext.data = _position._play_pos;
+			_position._play_pos += info.length;
+			if (info.ext.type == 0x2F) {// end of track reached
+				if (_pSnd->loop) {
+					jumpToTick(_loopTick);
+					_pSnd->loop--;
+				} else {
+					_pSnd->sndStatus = kStopped;
+					_pSnd->signal = 0xFFFF;
+				}
+			}
+			break;
+		default:
+			warning(
+					"MidiParser_SCI::parseNextEvent: Unsupported event code %x",
+					info.event);
+		} // // System Common, Meta or SysEx event
+	}// switch (info.command())
+}
+
+//----------------------------------------
+byte MidiParser_SCI::midiGetNextChannel(long ticker) {
+	byte curr = 0xFF;
+	long closest = ticker + 1000000, next = 0;
+	for (int i = 0; i < _pTrack->nChannels; i++) {
+		if (_pTrack->aChannels[i].time == -1) // channel ended
+			continue;
+		next = *_pTrack->aChannels[i].ptr; // when the next event shoudl occur
+		if (next == 0xF8) // 0xF8 means 240 ticks delay
+			next = 240;
+		next += _pTrack->aChannels[i].time;
+		if (next < closest) {
+			curr = i;
+			closest = next;
+		}
+	}
+	return curr;
+}
+//----------------------------------------
+byte *MidiParser_SCI::midiMixChannels() {
+	int lSize = 0;
+	byte **pDataPtr = new byte *[_pTrack->nChannels];
+	for (int i = 0; i < _pTrack->nChannels; i++) {
+		pDataPtr[i] = _pTrack->aChannels[i].ptr;
+		_pTrack->aChannels[i].time = 0;
+		_pTrack->aChannels[i].prev = 0;
+		lSize += _pTrack->aChannels[i].size;
+	}
+	byte *pOutData = new byte[lSize * 2]; // FIXME: creates overhead and still may be not enough to hold all data
+	_pMidiData = pOutData;
+	long ticker = 0;
+	byte curr, delta;
+	byte cmd, par1, global_prev = 0;
+	long new_delta;
+	SoundRes::tagChannel *pCh;
+	while ((curr = midiGetNextChannel(ticker)) != 0xFF) { // there is still active channel
+		pCh = &_pTrack->aChannels[curr];
+		delta = *pCh->ptr++;
+		pCh->time += (delta == 0xF8 ? 240 : delta); // when the comamnd is supposed to occur
+		if (delta == 0xF8)
+			continue;
+		new_delta = pCh->time - ticker;
+		ticker += new_delta;
+
+		cmd = *pCh->ptr++;
+		if (cmd != 0xFC) {
+			// output new delta
+			while (new_delta > 240) {
+				*pOutData++ = 0xF8;
+				new_delta -= 240;
+			}
+			*pOutData++ = (byte)new_delta;
+		}
+		switch (cmd) {
+		case 0xF0: // sysEx
+			*pOutData++ = cmd;
+			do {
+				par1 = *pCh->ptr++;
+				*pOutData++ = par1; // out
+			} while (par1 != 0xF7);
+			break;
+		case 0xFC: // end channel
+			pCh->time = -1; // FIXME
+			break;
+		default: // MIDI command
+			if (cmd & 0x80)
+				par1 = *pCh->ptr++;
+			else {// running status
+				par1 = cmd;
+				cmd = pCh->prev;
+			}
+			if (cmd != global_prev)
+				*pOutData++ = cmd; // out cmd
+			*pOutData++ = par1;// pout par1
+			if (nMidiParams[(cmd >> 4) - 8] == 2)
+				*pOutData++ = *pCh->ptr++; // out par2
+			pCh->prev = cmd;
+			global_prev = cmd;
+		}// switch(cmd)
+	}// while (curr)
+	// mixing finished. inserting stop event
+	*pOutData++ = 0;
+	*pOutData++ = 0xFF;
+	*pOutData++ = 0x2F;
+	*pOutData++ = 0x00;
+	*pOutData++ = 0x00;
+
+	for (int i = 0; i < _pTrack->nChannels; i++)
+		_pTrack->aChannels[i].ptr = pDataPtr[i];
+	delete[] pDataPtr;
+	return _pMidiData;
+}
+
+void MidiParser_SCI::setVolume(byte bVolume) {
+	if (bVolume > 0x7F)
+		bVolume = 0x7F;
+	if (_volume != bVolume) {
+		_volume = bVolume;
+		// sending volume change to all active channels
+		for (int i = 0; i < _pTrack->nChannels; i++)
+			if (_pTrack->aChannels[i].number <= 0xF)
+				_driver->send(0xB0 + _pTrack->aChannels[i].number, 7, _volume);
+	}
+}
+
+//---------------------------
+
+SoundRes::tagTrack* SoundRes::getTrackByNumber(uint16 number) {
+	if (/*number >= 0 &&*/number < nTracks)
+		return &aTracks[number];
+	return NULL;
+}
+
+SoundRes::tagTrack* SoundRes::getTrackByType(kTrackType type) {
+	for (int i = 0; i < nTracks; i++)
+		if (aTracks[i].type == type)
+			return &aTracks[i];
+	return NULL;
+}
+
+} // end of namespace SCI


Property changes on: scummvm/trunk/engines/sci/sfx/music.cpp
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Added: scummvm/trunk/engines/sci/sfx/music.h
===================================================================
--- scummvm/trunk/engines/sci/sfx/music.h	                        (rev 0)
+++ scummvm/trunk/engines/sci/sfx/music.h	2009-11-15 14:14:49 UTC (rev 45923)
@@ -0,0 +1,207 @@
+/* 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 2
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef SCI_MUSIC_H
+#define SCI_MUSIC_H
+
+#include "sound/mixer.h"
+#include "sound/audiostream.h"
+#include "sound/mididrv.h"
+#include "sound/midiparser.h"
+#include "common/mutex.h"
+#include "common/savefile.h"
+
+#include "sci/sci.h"
+
+/*
+ Sound drivers info: (from driver cmd0)
+ Adlib/SB  : track 0 , voices 9 , patch 3	ah=1
+ ProAudioSp: track 0 , voices 9 , patch 3	ah=17
+ GenerlMIDI: track 7 , voices 32, patch 4	ah=1   SCI1.1
+ Game Blast: track 9 , voices 12, patch 101	ah=1
+ MT-32	  : track 12, voices 32, patch 1	ah=1
+ PC Speaker: track 18, voices 1 , patch 0xFF ah=1
+ Tandy	  : track 19, voices 3 , patch 101	ah=1
+ IBM PS/1  : track 19, voices 3 , patch 101	ah=1
+
+ */
+
+namespace Sci {
+
+typedef uint16 SCIHANDLE;
+typedef uint16 HEAPHANDLE;
+
+class SoundRes {
+public:
+	enum kTrackType {
+		kTrackAdlib = 0,
+		kTrackGameBlaster = 9,
+		kTrackMT32 = 12,
+		kTrackSpeaker = 18,
+		kTrackTandy = 19
+	};
+
+	struct tagChannel {
+		byte number;
+		byte poly;
+		uint16 unk;
+		uint16 size;
+		byte *ptr;
+		long time;
+		byte prev;
+	};
+
+	struct tagTrack {
+		kTrackType type;
+		byte nDigital;
+		byte nChannels;
+		tagChannel *aChannels;
+		uint sz;
+	};
+public:
+	SoundRes(SCIHANDLE handle, uint32 ResId);
+	~SoundRes();
+	tagTrack *getTrackByNumber(uint16 number);
+	tagTrack *getTrackByType(kTrackType type);
+
+protected:
+	byte nTracks;
+	tagTrack *aTracks;
+};
+
+enum kSndStatus {
+	kStopped = 0, kPaused, kPlaying
+};
+
+// script-used struct to manipulate sound (358 bytes)
+class MidiParser_SCI;
+
+struct sciSound {
+	//sciNode node; // [0-5]	// we use a Common::List
+	uint16 resnum;// [6-7]
+	//  byte * pMidiData;
+	Audio::AudioStream* pStreamAud;
+	MidiParser_SCI *pMidiParser;
+	Audio::SoundHandle hCurrentAud;
+	kSndStatus sndStatus;
+
+	uint16 dataInc; //[338-339]
+	uint16 ticker;
+	uint16 signal; //[344]
+	byte prio; // 348
+	byte loop; // 349
+	byte volume; // 350
+
+	byte FadeTo;
+	short FadeStep;
+	uint32 FadeTicker;
+	uint32 FadeTickerStep;
+
+	//  byte unk7[7];
+};
+
+class SciMusic {
+public:
+	SciMusic();
+	~SciMusic();
+
+	void init();
+	void loadPatch();
+	void onTimer();
+	bool saveState(Common::OutSaveFile *pFile);
+	bool restoreState(Common::InSaveFile *pFile);
+	void stopAll();
+	void clearPlaylist() {
+		_playList.clear();
+	}
+	// sound and midi functions
+	void soundInitSnd(SoundRes *res, sciSound *pSnd);
+	void soundPlay(sciSound *pSnd);
+	void soundStop(sciSound *pSnd);
+	void soundKill(sciSound *pSnd);
+	void soundPause(sciSound *pSnd);
+	void soundSetVolume(sciSound *pSnd, byte volume);
+	void soundSetPriority(sciSound *pSnd, byte prio);
+	uint16 soundGetMasterVolume();
+	void soundSetMasterVolume(uint16 vol);
+	uint16 soundGetVoices();
+	uint32 soundGetTempo() {
+		return _dwTempo;
+	}
+
+	uint16 _savelen;
+protected:
+	byte findAudEntry(uint16 nAud, byte&oVolume, uint32& oOffset, uint32&oSize);
+	void sortPlayList();
+	void loadPatchMT32();
+	void patchSysEx(byte * addr, byte *pdata, int len);
+	void patchUpdateAddr(byte *addr, int len);
+	void doFade(sciSound *pSnd);
+
+	Audio::Mixer *_pMixer;
+	MidiDriver *_pMidiDrv;
+	int _midiType;
+	Common::Mutex _mutex;
+
+	Common::Array<sciSound *> _playList;
+	uint32 _dwTempo;
+	bool _bMultiMidi; // use adlib's digital track if midi track don't have one
+
+private:
+	static void miditimerCallback(void *p);
+
+};
+
+class MidiParser_SCI : public MidiParser {
+public:
+	MidiParser_SCI();
+	~MidiParser_SCI();
+	bool loadMusic(SoundRes::tagTrack *ptrack, sciSound *psnd);
+	bool loadMusic(byte *, uint32) {
+		return false;
+	}
+	void unloadMusic();
+	void setVolume(byte bVolume);
+	void stop() {
+		_abort_parse = true;/*hangAllActiveNotes();*/
+	}
+	void pause() {
+		_abort_parse = true; /*hangAllActiveNotes();*/
+	}
+
+protected:
+	void parseNextEvent(EventInfo &info);
+	byte *midiMixChannels();
+	byte midiGetNextChannel(long ticker);
+	byte *_pMidiData;
+	SoundRes::tagTrack *_pTrack;
+	sciSound *_pSnd;
+	uint32 _loopTick;
+	byte _volume;
+};
+
+} // end of namespace
+
+#endif


Property changes on: scummvm/trunk/engines/sci/sfx/music.h
___________________________________________________________________
Added: svn:mime-type
   + text/plain
Added: svn:keywords
   + Date Rev Author URL Id
Added: svn:eol-style
   + native

Modified: scummvm/trunk/engines/sci/sfx/soundcmd.cpp
===================================================================
--- scummvm/trunk/engines/sci/sfx/soundcmd.cpp	2009-11-15 12:22:21 UTC (rev 45922)
+++ scummvm/trunk/engines/sci/sfx/soundcmd.cpp	2009-11-15 14:14:49 UTC (rev 45923)
@@ -24,10 +24,13 @@
  */
 
 #include "sci/sfx/iterator.h"	// for SongIteratorStatus
+#include "sci/sfx/music.h"
 #include "sci/sfx/soundcmd.h"
 
 namespace Sci {
 
+#define USE_OLD_MUSIC_FUNCTIONS
+
 #define SCI1_SOUND_FLAG_MAY_PAUSE        1 /* Only here for completeness; The interpreter doesn't touch this bit */
 #define SCI1_SOUND_FLAG_SCRIPTED_PRI     2 /* but does touch this */
 
@@ -126,6 +129,13 @@
 SoundCommandParser::SoundCommandParser(ResourceManager *resMan, SegManager *segMan, SfxState *state, AudioPlayer *audio, SciVersion doSoundVersion) : 
 	_resMan(resMan), _segMan(segMan), _state(state), _audio(audio), _doSoundVersion(doSoundVersion) {
 
+	_hasNodePtr = (_doSoundVersion != SCI_VERSION_0_EARLY);
+
+#ifndef USE_OLD_MUSIC_FUNCTIONS
+	_music = new SciMusic();
+	_music->init();
+#endif
+
 	switch (doSoundVersion) {
 	case SCI_VERSION_0_EARLY:
 		SOUNDCOMMAND(cmdInitHandle);
@@ -220,10 +230,11 @@
 	if (!obj.segment)
 		return;
 
+#ifdef USE_OLD_MUSIC_FUNCTIONS
 	SongIteratorType type = (_doSoundVersion == SCI_VERSION_0_EARLY) ? SCI_SONG_ITERATOR_TYPE_SCI0 : SCI_SONG_ITERATOR_TYPE_SCI1;
 	int number = GET_SEL32V(_segMan, obj, number);
 
-	if (_doSoundVersion != SCI_VERSION_0_EARLY) {
+	if (_hasNodePtr) {
 		if (GET_SEL32V(_segMan, obj, nodePtr)) {
 			_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
 			_state->sfx_remove_song(handle);
@@ -238,13 +249,36 @@
 
 	_state->sfx_add_song(build_iterator(_resMan, number, type, handle), 0, handle, number);
 
-	if (_doSoundVersion == SCI_VERSION_0_EARLY) {
+	if (!_hasNodePtr)
 		PUT_SEL32V(_segMan, obj, state, _K_SOUND_STATUS_INITIALIZED);
-	} else {
+	else
 		PUT_SEL32(_segMan, obj, nodePtr, obj);
+
+	PUT_SEL32(_segMan, obj, handle, obj);
+#else
+
+	uint16 resnum = GET_SEL32V(_segMan, obj, number);
+	Resource *res = resnum ? _resMan->findResource(ResourceId(kResourceTypeSound, resnum), true) : NULL;
+
+	if (!GET_SEL32V(_segMan, obj, nodePtr)) {
+		PUT_SEL32(_segMan, obj, nodePtr, obj);
+		_soundList.push_back(obj.toUint16());
 	}
 
-	PUT_SEL32(_segMan, obj, handle, obj);
+	// TODO
+	/*
+	sciSound *pSnd = (sciSound *)heap2Ptr(hptr);
+	pSnd->resnum = resnum;
+	pSnd->loop = (GET_SEL32V(_segMan, obj, loop) == 0xFFFF ? 1 : 0);
+	pSnd->prio = GET_SEL32V(_segMan, obj, pri) & 0xFF; // priority
+	pSnd->volume = GET_SEL32V(_segMan, obj, vol) & 0xFF; // volume
+	pSnd->signal = pSnd->dataInc = 0;
+
+	_music->soundKill(pSnd);
+	if (res)
+		_music->soundInitSnd(res, pSnd);
+	*/
+#endif
 }
 
 void SoundCommandParser::cmdPlayHandle(reg_t obj, SongHandle handle, int value) {
@@ -332,7 +366,7 @@
 	if (obj.segment) {
 		_state->sfx_remove_song(handle);
 
-		if (_doSoundVersion == SCI_VERSION_0_EARLY)
+		if (!_hasNodePtr)
 			PUT_SEL32V(_segMan, obj, handle, 0x0000);
 	}
 }
@@ -340,12 +374,12 @@
 void SoundCommandParser::cmdStopHandle(reg_t obj, SongHandle handle, int value) {
 	changeHandleStatus(obj, handle, SOUND_STATUS_STOPPED);
 
-	if (_doSoundVersion != SCI_VERSION_0_EARLY)
+	if (_hasNodePtr)
 		PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET);
 }
 
 void SoundCommandParser::cmdSuspendHandle(reg_t obj, SongHandle handle, int value) {
-	if (_doSoundVersion == SCI_VERSION_0_EARLY)
+	if (!_hasNodePtr)
 		changeHandleStatus(obj, handle, SOUND_STATUS_SUSPENDED);
 	else
 		changeHandleStatus(obj, handle, value ? SOUND_STATUS_SUSPENDED : SOUND_STATUS_PLAYING);
@@ -387,7 +421,7 @@
 	** than fading it! */
 	if (obj.segment) {
 		_state->sfx_song_set_status(handle, SOUND_STATUS_STOPPED);
-		if (_doSoundVersion == SCI_VERSION_0_EARLY)
+		if (!_hasNodePtr)
 			PUT_SEL32V(_segMan, obj, state, SOUND_STATUS_STOPPED);
 		PUT_SEL32V(_segMan, obj, signal, SIGNAL_OFFSET);
 	}

Modified: scummvm/trunk/engines/sci/sfx/soundcmd.h
===================================================================
--- scummvm/trunk/engines/sci/sfx/soundcmd.h	2009-11-15 12:22:21 UTC (rev 45922)
+++ scummvm/trunk/engines/sci/sfx/soundcmd.h	2009-11-15 14:14:49 UTC (rev 45923)
@@ -26,10 +26,12 @@
 #ifndef SCI_SOUNDCMD_H
 #define SCI_SOUNDCMD_H
 
+#include "common/list.h"
 #include "sci/engine/state.h"
 
 namespace Sci {
 
+class SciMusic;
 class SoundCommandParser;
 typedef void (SoundCommandParser::*SoundCommand)(reg_t obj, SongHandle handle, int value);
 
@@ -47,15 +49,19 @@
 	reg_t parseCommand(int argc, reg_t *argv, reg_t acc);
 
 private:
+	SciMusic *_music;
 	Common::Array<SciSoundCommand*> _soundCommands;
 	ResourceManager *_resMan;
 	SegManager *_segMan;
 	SfxState *_state;
 	AudioPlayer *_audio;
+	bool _hasNodePtr;
 	SciVersion _doSoundVersion;
 	reg_t _acc;
 	int _midiCmd, _controller, _param;
 
+	Common::List<uint16> _soundList;
+
 	void cmdInitHandle(reg_t obj, SongHandle handle, int value);
 	void cmdPlayHandle(reg_t obj, SongHandle handle, int value);
 	void cmdDummy(reg_t obj, SongHandle handle, int value);


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Scummvm-git-logs mailing list