scummvm/engines/lab/labmusic.cpp

524 lines
12 KiB
C++
Raw Normal View History

2014-10-06 14:50:05 +02:00
/* 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.
*
*/
/*
* This code is based on Labyrinth of Time code with assistance of
*
* Copyright (c) 1993 Terra Nova Development
* Copyright (c) 2004 The Wyrmkeep Entertainment Co.
*
*/
#include "lab/stddefines.h"
#include "lab/labfun.h"
#include "lab/timing.h"
#include "lab/mouse.h"
2014-12-28 00:09:24 +01:00
#include "lab/vga.h"
2014-10-06 14:50:05 +02:00
namespace Lab {
#define MUSICBUFSIZE (2 * 65536L)
#define SAMPLESPEED 15000L
extern bool EffectPlaying;
Music *g_music;
Music::Music() {
_file = 0;
_tFile = 0;
_musicPaused = false;
_tMusicOn = false;
_tFileLength = 0;
_tLeftInFile = 0;
_manyBuffers = MANYBUFFERS;
_musicFilledTo = 0;
_musicPlaying = 0;
_musicOnBuffer = 0;
_filelength = 0;
_leftinfile = 0;
_musicOn = false;
_turnMusicOn = false;
_winmusic = false;
_doNotFileFlushAudio = false;
}
/*****************************************************************************/
/* Figures out which buffer is currently playing based on messages sent to */
/* it from the Audio device. */
/*****************************************************************************/
void Music::updateMusic() {
2014-10-06 14:50:05 +02:00
uint16 i;
2014-12-28 00:09:24 +01:00
WSDL_ProcessInput(0);
2014-10-06 14:50:05 +02:00
updateMouse();
if (EffectPlaying)
updateSoundBuffers();
else if (_musicOn) {
for (i = 0; i < 2; i++) {
if (musicBufferEmpty(i)) {
playMusicBlock(_musicBuffer[_musicPlaying], MUSICBUFSIZE, i, SAMPLESPEED);
if (_musicPlaying)
_musicOnBuffer = _musicPlaying - 1;
else
_musicOnBuffer = _manyBuffers - 1;
_musicPlaying++;
if (_musicPlaying >= _manyBuffers)
_musicPlaying = 0;
}
}
}
}
void Music::fillbuffer(uint16 unit) {
2014-12-14 17:46:40 +01:00
return;
warning("STUB: Music::fillbuffer");
2014-10-06 14:50:05 +02:00
uint32 Size = MUSICBUFSIZE;
void *ptr = _musicBuffer[unit];
if (Size < _leftinfile) {
_file->read(ptr, Size);
_leftinfile -= Size;
} else {
_file->read(ptr, _leftinfile);
memset((char *)ptr + _leftinfile, 0, Size - _leftinfile);
_file->seek(0);
_leftinfile = _filelength;
}
}
/*****************************************************************************/
/* Figures out how many *complete* buffers of music left to play. */
/*****************************************************************************/
uint16 Music::getManyBuffersLeft() {
2014-10-06 14:50:05 +02:00
uint16 mp = _musicOnBuffer;
if (mp == _musicFilledTo) /* Already filled */
return _manyBuffers;
else if (mp > _musicFilledTo)
return _manyBuffers - (mp - _musicFilledTo);
else
return _musicFilledTo - mp;
}
/*****************************************************************************/
/* Fills up the buffers that have already been played if necessary; if doit */
/* is set to TRUE then it will fill up all empty buffers. Otherwise, it */
/* Check if there are MINBUFFERS or less buffers that are playing. */
/*****************************************************************************/
void Music::fillUpMusic(bool doit) {
int16 ManyLeft, ManyFill;
updateMusic();
if (!_musicOn)
return;
ManyLeft = getManyBuffersLeft();
if (ManyLeft < MINBUFFERS)
doit = true;
else if (ManyLeft == _manyBuffers) /* All the buffers are already full */
doit = false;
if (doit && (ManyLeft < _manyBuffers) && ManyLeft) {
ManyFill = _manyBuffers - ManyLeft - 1;
while (ManyFill > 0) {
_musicFilledTo++;
if (_musicFilledTo >= _manyBuffers)
_musicFilledTo = 0;
fillbuffer(_musicFilledTo);
updateMusic();
ManyFill--;
}
updateMusic();
ManyLeft = getManyBuffersLeft();
if (ManyLeft < _manyBuffers) {
ManyFill = _manyBuffers - ManyLeft - 1;
while (ManyFill > 0) {
_musicFilledTo++;
if (_musicFilledTo >= _manyBuffers)
_musicFilledTo = 0;
fillbuffer(_musicFilledTo);
updateMusic();
ManyFill--;
}
}
}
updateMusic();
/* NYI: A check for dirty cds; for instance, if lots of buffers already
played */
}
/*****************************************************************************/
/* Starts up the music initially. */
/*****************************************************************************/
void Music::startMusic(bool startatbegin) {
uint16 counter;
if (!_musicOn)
return;
flushAudio();
if (startatbegin) {
_file->seek(0);
_leftinfile = _filelength;
}
_musicPlaying = 0;
_musicOnBuffer = 0;
_musicFilledTo = _manyBuffers - 1;
_musicOn = false;
for (counter = 0; counter < _manyBuffers; counter++)
fillbuffer(counter);
_musicOn = true;
updateMusic();
}
/*****************************************************************************/
/* Initializes the music buffers. */
/*****************************************************************************/
bool Music::initMusic() {
2014-10-06 14:50:05 +02:00
uint16 counter;
if (!_turnMusicOn)
return true;
_musicOn = true;
_musicPaused = false;
const char *filename;
if (_winmusic)
filename = "Music:WinGame";
else
filename = "Music:BackGrou";
if (_musicBuffer[0] == NULL) {
for (counter = 0; counter < _manyBuffers; counter++)
2014-12-20 21:39:27 +01:00
_musicBuffer[counter] = malloc(MUSICBUFSIZE);
2014-10-06 14:50:05 +02:00
}
2014-12-20 21:39:27 +01:00
_filelength = sizeOfFile(filename);
_file = openPartial(filename);
2014-10-06 14:50:05 +02:00
2014-12-20 21:39:27 +01:00
if (_file) {
startMusic(true);
return true;
2014-10-06 14:50:05 +02:00
}
_musicOn = false;
return false;
}
/*****************************************************************************/
/* Frees up the music buffers and closes the file. */
/*****************************************************************************/
void Music::freeMusic() {
2014-10-06 14:50:05 +02:00
_musicOn = false;
if (_file->isOpen())
_file->close();
_file = 0;
}
/*****************************************************************************/
/* Pauses the background music. */
/*****************************************************************************/
void Music::pauseBackMusic() {
2014-10-06 14:50:05 +02:00
if (!_musicPaused && _musicOn) {
updateMusic();
_musicOn = false;
flushAudio();
if (_musicPlaying)
_musicPlaying--;
else
_musicPlaying = _manyBuffers - 1;
_musicPaused = true;
}
}
/*****************************************************************************/
/* Restarts the paused background music. */
/*****************************************************************************/
void Music::restartBackMusic() {
2014-10-06 14:50:05 +02:00
if (_musicPaused) {
flushAudio();
_musicOn = true;
updateMusic();
_musicPaused = false;
}
}
/*****************************************************************************/
/* Checks to see if need to fill buffers fill of music. */
/*****************************************************************************/
void Music::checkMusic() {
2014-10-06 14:50:05 +02:00
updateMusic();
if (!_musicOn)
return;
fillUpMusic(false);
}
/*****************************************************************************/
/* Checks to see if need to fill buffers fill of music. */
/*****************************************************************************/
void Music::newCheckMusic() {
2014-10-06 14:50:05 +02:00
checkMusic();
}
/*****************************************************************************/
/* Turns the music on and off. */
/*****************************************************************************/
void Music::setMusic(bool on) {
flushAudio();
if (on && !_musicOn) {
_musicOn = true;
startMusic(true);
} else if (!on && _musicOn) {
_musicOn = false;
updateMusic();
} else
_musicOn = on;
}
/*****************************************************************************/
/* Changes the background music to something else. */
/*****************************************************************************/
void Music::changeMusic(const char *newmusic) {
if (!_tFile) {
_tFile = _file;
_tMusicOn = _musicOn;
_tFileLength = _filelength;
#if defined(DOSCODE)
_tLeftInFile = _leftinfile;
#else
_tLeftInFile = _leftinfile + 65536L;
if (_tLeftInFile > _tFileLength)
_tLeftInFile = _leftinfile;
#endif
}
_file = openPartial(newmusic);
if (_file) {
_musicOn = true; /* turn it off */
setMusic(false);
_filelength = sizeOfFile(newmusic);
_musicOn = false; /* turn it back on */
setMusic(true);
} else {
_file = _tFile;
_tFile = 0;
}
}
/*****************************************************************************/
/* Changes the background music to the original piece playing. */
/*****************************************************************************/
void Music::resetMusic() {
2014-10-06 14:50:05 +02:00
if (!_tFile)
return;
if (_file->isOpen())
_file->close();
_file = _tFile;
_filelength = _tFileLength;
_leftinfile = _tLeftInFile;
_file->seek(_filelength - _leftinfile);
_musicOn = true;
setMusic(false);
updateMusic();
if (!_tMusicOn) {
_tFile = 0;
return;
}
_musicOn = _tMusicOn;
startMusic(false);
_tFile = 0;
}
#define FUDGEFACTOR 5L
#define READSPEED (2 * 130000L)
/*****************************************************************************/
/* Checks whether or note enough memory in music buffer before loading any */
/* files. Fills it if not. Does not take into account the current buffer */
/* playing; a built in fudge factor. We've also got another FUDGEFACTOR */
/* defined above in case things go wrong. */
/* */
/* Here, the seconds are multipled by 10. */
/*****************************************************************************/
byte **Music::newOpen(const char *name) {
uint32 filelength, LeftSecs, Time;
byte **file;
if (name == NULL) {
return NULL;
}
if ((strcmp(name, "") == 0) || (strcmp(name, " ") == 0)) {
return NULL;
}
if ((file = isBuffered(name))) {
return file;
}
if (_musicOn) {
updateMusic();
2015-02-20 21:31:03 +02:00
LeftSecs = (getManyBuffersLeft() * MUSICBUFSIZE * 10) / (2 * SAMPLESPEED); // Windows (16-bit)
//LeftSecs = (getManyBuffersLeft() * MUSICBUFSIZE * 10) / SAMPLESPEED; // DOS (8-bit) - TODO
2014-10-06 14:50:05 +02:00
filelength = sizeOfFile(name) * 10;
Time = 10 + /* Seek time for the music and the file */
(filelength / READSPEED) + /* Read time for the file */
FUDGEFACTOR;
if (Time >= LeftSecs)
fillUpMusic(true);
}
if (!_doNotFileFlushAudio && EffectPlaying)
flushAudio();
file = openFile(name);
checkMusic();
return file;
}
/*****************************************************************************/
/* Checks whether or note enough memory in music buffer to continue loading */
/* in a file. Fills the music buffer if not. Does not take into account */
/* the current buffer playing; a built in fudge factor. We've also got */
/* another FUDGEFACTOR defined above in case things go wrong. */
/* */
/* Here, the seconds are multipled by 10. */
/*****************************************************************************/
void Music::fileCheckMusic(uint32 filelength) {
uint32 LeftSecs, Time;
if (_musicOn) {
updateMusic();
2015-02-20 21:31:03 +02:00
LeftSecs = (getManyBuffersLeft() * MUSICBUFSIZE * 10) / (2 * SAMPLESPEED); // Windows (16-bit)
//LeftSecs = (getManyBuffersLeft() * MUSICBUFSIZE * 10) / SAMPLESPEED; // DOS (8-bit) - TODO
2014-10-06 14:50:05 +02:00
filelength *= 10;
Time = 5 + /* Seek time for the music */
(filelength / READSPEED) + /* Read time for the file */
FUDGEFACTOR;
if (Time >= LeftSecs)
fillUpMusic(true);
}
}
} // End of namespace Lab