aboutsummaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorMax Horn2003-11-29 12:11:01 +0000
committerMax Horn2003-11-29 12:11:01 +0000
commitf00cd05b331cb5db1dfee140608d6189385950a4 (patch)
treedb1e0105eb9ef2cd266620357c551c5a058f4d37 /sound
parent493d64d91b9944cd91da6539cb41ee561ddafd92 (diff)
downloadscummvm-rg350-f00cd05b331cb5db1dfee140608d6189385950a4.tar.gz
scummvm-rg350-f00cd05b331cb5db1dfee140608d6189385950a4.tar.bz2
scummvm-rg350-f00cd05b331cb5db1dfee140608d6189385950a4.zip
moved Audio CD (emulation) code from scumm/sound.cpp to sound/, so that it may be reused by other engines in the future
svn-id: r11421
Diffstat (limited to 'sound')
-rw-r--r--sound/audiocd.cpp152
-rw-r--r--sound/audiocd.h74
-rw-r--r--sound/module.mk5
-rw-r--r--sound/mp3.cpp127
-rw-r--r--sound/mp3.h47
-rw-r--r--sound/vorbis.cpp150
-rw-r--r--sound/vorbis.h49
7 files changed, 603 insertions, 1 deletions
diff --git a/sound/audiocd.cpp b/sound/audiocd.cpp
new file mode 100644
index 0000000000..6da8cf28aa
--- /dev/null
+++ b/sound/audiocd.cpp
@@ -0,0 +1,152 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+
+#include "sound/audiocd.h"
+#include "sound/mp3.h"
+#include "sound/vorbis.h"
+#include "base/engine.h"
+#include "common/file.h"
+#include "common/util.h"
+
+
+AudioCDManager::AudioCDManager() {
+ _current_cache = 0;
+}
+
+void AudioCDManager::playCDTrack(int track, int numLoops, int startFrame, int duration) {
+ if (numLoops != 0 || startFrame != 0) {
+ // Try to load the track from a .mp3/.ogg file, and if found, use
+ // that. If not found, attempt to do regular Audio CD playback of
+ // the requested track.
+ int index = getCachedTrack(track);
+ if (index >= 0) {
+ g_engine->_mixer->stopHandle(_cd.handle);
+ _cd.playing = true;
+ _cd.track = track;
+ _cd.numLoops = numLoops;
+ _cd.start = startFrame;
+ _cd.duration = duration;
+ _track_info[index]->play(g_engine->_mixer, &_cd.handle, _cd.start, _cd.duration);
+ } else {
+ g_system->play_cdrom(track, numLoops, startFrame, duration);
+ }
+ }
+}
+
+void AudioCDManager::stopCD() {
+ if (_cd.playing) {
+ g_engine->_mixer->stopHandle(_cd.handle);
+ _cd.playing = false;
+ } else {
+ g_system->stop_cdrom();
+ }
+}
+
+int AudioCDManager::pollCD() const {
+ return _cd.playing || g_system->poll_cdrom();
+}
+
+void AudioCDManager::updateCD() {
+ if (_cd.playing) {
+ // If the sound handle is 0, then playback stopped.
+ if (!_cd.handle) {
+ // If playback just stopped, check if the current track is supposed
+ // to be repeated, and if that's the case, play it again. Else, stop
+ // the CD explicitly.
+ if (_cd.numLoops == -1 || --_cd.numLoops > 0) {
+//FIXME _scumm->VAR(_scumm->VAR_MUSIC_TIMER) = 0;
+//FIXME if (!_soundsPaused) {
+ int index = getCachedTrack(_cd.track);
+ assert(index >= 0);
+ _track_info[index]->play(g_engine->_mixer, &_cd.handle, _cd.start, _cd.duration);
+//FIXME }
+ } else {
+ g_engine->_mixer->stopHandle(_cd.handle);
+ _cd.playing = false;
+ }
+ }
+ } else {
+ g_system->update_cdrom();
+ }
+}
+
+int AudioCDManager::getCachedTrack(int track) {
+ int i;
+#if defined(USE_MAD) || defined(USE_VORBIS)
+ char track_name[1024];
+ File *file = new File();
+#endif
+ int current_index;
+
+ // See if we find the track in the cache
+ for (i = 0; i < CACHE_TRACKS; i++)
+ if (_cached_tracks[i] == track) {
+ if (_track_info[i])
+ return i;
+ else
+ return -1;
+ }
+ current_index = _current_cache++;
+ _current_cache %= CACHE_TRACKS;
+
+ // Not found, see if it exists
+
+ // First, delete the previous track info object
+ delete _track_info[current_index];
+ _track_info[current_index] = NULL;
+
+ _cached_tracks[current_index] = track;
+
+#ifdef USE_MAD
+ sprintf(track_name, "track%d.mp3", track);
+ file->open(track_name, g_engine->getGameDataPath());
+
+ if (file->isOpen()) {
+ _track_info[current_index] = new MP3TrackInfo(file);
+ if (_track_info[current_index]->error()) {
+ delete _track_info[current_index];
+ _track_info[current_index] = NULL;
+ return -1;
+ }
+ return current_index;
+ }
+#endif
+
+#ifdef USE_VORBIS
+ sprintf(track_name, "track%d.ogg", track);
+ file->open(track_name, g_engine->getGameDataPath());
+
+ if (file->isOpen()) {
+ _track_info[current_index] = new VorbisTrackInfo(file);
+ if (_track_info[current_index]->error()) {
+ delete _track_info[current_index];
+ _track_info[current_index] = NULL;
+ return -1;
+ }
+ return current_index;
+ }
+#endif
+
+ debug(2, "Track %d not available in compressed format", track);
+ return -1;
+}
diff --git a/sound/audiocd.h b/sound/audiocd.h
new file mode 100644
index 0000000000..c02e50f4f6
--- /dev/null
+++ b/sound/audiocd.h
@@ -0,0 +1,74 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef SOUND_AUDIOCD_H
+#define SOUND_AUDIOCD_H
+
+#include "stdafx.h"
+#include "common/scummsys.h"
+#include "common/singleton.h"
+#include "sound/mixer.h"
+
+class DigitalTrackInfo {
+public:
+ virtual bool error() = 0;
+ virtual int play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) = 0;
+ virtual ~DigitalTrackInfo() { }
+};
+
+
+class AudioCDManager : public Common::Singleton<AudioCDManager> {
+public:
+ void playCDTrack(int track, int numLoops, int startFrame, int duration);
+ void stopCD();
+ int pollCD() const;
+ void updateCD();
+
+private:
+ friend class Common::Singleton<AudioCDManager>;
+ AudioCDManager();
+
+ int getCachedTrack(int track);
+
+private:
+ /* used for emulated CD music */
+ enum {
+ CACHE_TRACKS = 10
+ };
+ int _cached_tracks[CACHE_TRACKS];
+ DigitalTrackInfo *_track_info[CACHE_TRACKS];
+ int _current_cache;
+
+ struct {
+ PlayingSoundHandle handle;
+ int track;
+ int start;
+ int duration;
+ int numLoops;
+ bool playing;
+ } _cd;
+
+};
+
+/** Shortcut for accessing the audio CD manager. */
+#define AudioCD AudioCDManager::instance()
+
+#endif
diff --git a/sound/module.mk b/sound/module.mk
index e0974162a5..859a8b9975 100644
--- a/sound/module.mk
+++ b/sound/module.mk
@@ -1,6 +1,7 @@
MODULE := sound
MODULE_OBJS := \
+ sound/audiocd.o \
sound/audiostream.o \
sound/fmopl.o \
sound/mididrv.o \
@@ -8,9 +9,11 @@ MODULE_OBJS := \
sound/midiparser_smf.o \
sound/midiparser_xmidi.o \
sound/mixer.o \
+ sound/mp3.o \
sound/mpu401.o \
sound/rate.o \
- sound/voc.o
+ sound/voc.o \
+ sound/vorbis.o
# sound/resample.o \
MODULE_DIRS += \
diff --git a/sound/mp3.cpp b/sound/mp3.cpp
new file mode 100644
index 0000000000..db73f7f394
--- /dev/null
+++ b/sound/mp3.cpp
@@ -0,0 +1,127 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+
+#include "sound/mp3.h"
+#include "common/file.h"
+#include "common/util.h"
+
+#ifdef USE_MAD
+MP3TrackInfo::MP3TrackInfo(File *file) {
+ struct mad_stream stream;
+ struct mad_frame frame;
+ unsigned char buffer[8192];
+ unsigned int buflen = 0;
+ int count = 0;
+
+ // Check the format and bitrate
+ mad_stream_init(&stream);
+ mad_frame_init(&frame);
+
+ while (1) {
+ if (buflen < sizeof(buffer)) {
+ int bytes;
+
+ bytes = file->read(buffer + buflen, sizeof(buffer) - buflen);
+ if (bytes <= 0) {
+ if (bytes == -1) {
+ warning("Invalid file format");
+ goto error;
+ }
+ break;
+ }
+
+ buflen += bytes;
+ }
+
+ mad_stream_buffer(&stream, buffer, buflen);
+
+ while (1) {
+ if (mad_frame_decode(&frame, &stream) == -1) {
+ if (!MAD_RECOVERABLE(stream.error))
+ break;
+
+ if (stream.error != MAD_ERROR_BADCRC)
+ continue;
+ }
+
+ if (count++)
+ break;
+ }
+
+ if (count || stream.error != MAD_ERROR_BUFLEN)
+ break;
+
+ memmove(buffer, stream.next_frame,
+ buflen = &buffer[buflen] - stream.next_frame);
+ }
+
+ if (count)
+ memcpy(&_mad_header, &frame.header, sizeof(mad_header));
+ else {
+ warning("Invalid file format");
+ goto error;
+ }
+
+ mad_frame_finish(&frame);
+ mad_stream_finish(&stream);
+ // Get file size
+ _size = file->size();
+ _file = file;
+ _error_flag = false;
+ return;
+
+error:
+ mad_frame_finish(&frame);
+ mad_stream_finish(&stream);
+ _error_flag = true;
+ delete file;
+}
+
+int MP3TrackInfo::play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) {
+ unsigned int offset;
+ mad_timer_t durationTime;
+
+ // Calc offset. As all bitrates are in kilobit per seconds, the division by 200 is always exact
+ offset = (startFrame * (_mad_header.bitrate / (8 * 25))) / 3;
+ _file->seek(offset, SEEK_SET);
+
+ // Calc delay
+ if (!duration) {
+ // FIXME: Using _size here is a problem if offset (or equivalently
+ // startFrame) is non-zero.
+ mad_timer_set(&durationTime, (_size * 8) / _mad_header.bitrate,
+ (_size * 8) % _mad_header.bitrate, _mad_header.bitrate);
+ } else {
+ mad_timer_set(&durationTime, duration / 75, duration % 75, 75);
+ }
+
+ // Play it
+ return mixer->playMP3CDTrack(handle, _file, durationTime);
+}
+
+MP3TrackInfo::~MP3TrackInfo() {
+ if (! _error_flag)
+ _file->close();
+}
+
+#endif
diff --git a/sound/mp3.h b/sound/mp3.h
new file mode 100644
index 0000000000..fd5be63387
--- /dev/null
+++ b/sound/mp3.h
@@ -0,0 +1,47 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef SOUND_MP3_H
+#define SOUND_MP3_H
+
+#include "sound/audiocd.h"
+
+class File;
+
+#ifdef USE_MAD
+class MP3TrackInfo : public DigitalTrackInfo {
+private:
+ struct mad_header _mad_header;
+ long _size;
+ File *_file;
+ bool _error_flag;
+
+public:
+ MP3TrackInfo(File *file);
+ ~MP3TrackInfo();
+ bool error() { return _error_flag; }
+ int play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration);
+};
+#endif
+
+
+
+#endif
diff --git a/sound/vorbis.cpp b/sound/vorbis.cpp
new file mode 100644
index 0000000000..cd1a84ad08
--- /dev/null
+++ b/sound/vorbis.cpp
@@ -0,0 +1,150 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+
+#include "sound/vorbis.h"
+#include "common/file.h"
+#include "common/util.h"
+
+#ifdef USE_VORBIS
+// These are wrapper functions to allow using a File object to
+// provide data to the OggVorbis_File object.
+
+struct file_info {
+ File *file;
+ int start, curr_pos;
+ size_t len;
+};
+
+static size_t read_wrap(void *ptr, size_t size, size_t nmemb, void *datasource) {
+ file_info *f = (file_info *) datasource;
+ int result;
+
+ nmemb *= size;
+ if (f->curr_pos > (int) f->len)
+ nmemb = 0;
+ else if (nmemb > f->len - f->curr_pos)
+ nmemb = f->len - f->curr_pos;
+ result = f->file->read(ptr, nmemb);
+ if (result == -1) {
+ f->curr_pos = f->file->pos() - f->start;
+ return (size_t) -1;
+ } else {
+ f->curr_pos += result;
+ return result / size;
+ }
+}
+
+static int seek_wrap(void *datasource, ogg_int64_t offset, int whence) {
+ file_info *f = (file_info *) datasource;
+
+ if (whence == SEEK_SET)
+ offset += f->start;
+ else if (whence == SEEK_END) {
+ offset += f->start + f->len;
+ whence = SEEK_SET;
+ }
+
+ f->file->seek(offset, whence);
+ f->curr_pos = f->file->pos() - f->start;
+ return f->curr_pos;
+}
+
+static int close_wrap(void *datasource) {
+ file_info *f = (file_info *) datasource;
+
+ f->file->close();
+ delete f;
+ return 0;
+}
+
+static long tell_wrap(void *datasource) {
+ file_info *f = (file_info *) datasource;
+
+ return f->curr_pos;
+}
+
+static ov_callbacks g_File_wrap = {
+ read_wrap, seek_wrap, close_wrap, tell_wrap
+};
+#endif
+
+#ifdef USE_VORBIS
+
+VorbisTrackInfo::VorbisTrackInfo(File *file) {
+ file_info *f = new file_info;
+
+ f->file = file;
+ f->start = 0;
+ f->len = file->size();
+ f->curr_pos = file->pos();
+
+ if (ov_open_callbacks((void *) f, &_ov_file, NULL, 0, g_File_wrap) < 0) {
+ warning("Invalid file format");
+ _error_flag = true;
+ delete f;
+ delete file;
+ } else {
+ _error_flag = false;
+ _file = file;
+ }
+}
+
+#ifdef CHUNKSIZE
+#define VORBIS_TREMOR
+#endif
+
+int VorbisTrackInfo::play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration) {
+#ifdef VORBIS_TREMOR
+ ov_time_seek(&_ov_file, (ogg_int64_t)(startFrame / 75.0 * 1000));
+#else
+ ov_time_seek(&_ov_file, startFrame / 75.0);
+#endif
+ return mixer->playVorbis(handle, &_ov_file,
+ duration * ov_info(&_ov_file, -1)->rate / 75, true);
+}
+
+VorbisTrackInfo::~VorbisTrackInfo() {
+ if (! _error_flag) {
+ ov_clear(&_ov_file);
+ delete _file;
+ }
+}
+
+void playSfxSound_Vorbis(SoundMixer *mixer, File *file, uint32 size, PlayingSoundHandle *handle) {
+ OggVorbis_File *ov_file = new OggVorbis_File;
+ file_info *f = new file_info;
+
+ f->file = file;
+ f->start = file->pos();
+ f->len = size;
+ f->curr_pos = 0;
+
+ if (ov_open_callbacks((void *) f, ov_file, NULL, 0, g_File_wrap) < 0) {
+ warning("Invalid file format");
+ delete ov_file;
+ delete f;
+ } else
+ mixer->playVorbis(handle, ov_file, 0, false);
+}
+
+#endif
diff --git a/sound/vorbis.h b/sound/vorbis.h
new file mode 100644
index 0000000000..fcffc1c50d
--- /dev/null
+++ b/sound/vorbis.h
@@ -0,0 +1,49 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 The ScummVM project
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#ifndef SOUND_VORBIS_H
+#define SOUND_VORBIS_H
+
+#include "sound/audiocd.h"
+
+class File;
+
+#ifdef USE_VORBIS
+
+class VorbisTrackInfo : public DigitalTrackInfo {
+private:
+ File *_file;
+ OggVorbis_File _ov_file;
+ bool _error_flag;
+
+public:
+ VorbisTrackInfo(File *file);
+ ~VorbisTrackInfo();
+ bool error() { return _error_flag; }
+ int play(SoundMixer *mixer, PlayingSoundHandle *handle, int startFrame, int duration);
+};
+
+
+void playSfxSound_Vorbis(SoundMixer *mixer, File *file, uint32 size, PlayingSoundHandle *handle);
+
+#endif
+
+#endif