diff options
author | Max Horn | 2003-11-29 12:11:01 +0000 |
---|---|---|
committer | Max Horn | 2003-11-29 12:11:01 +0000 |
commit | f00cd05b331cb5db1dfee140608d6189385950a4 (patch) | |
tree | db1e0105eb9ef2cd266620357c551c5a058f4d37 /sound | |
parent | 493d64d91b9944cd91da6539cb41ee561ddafd92 (diff) | |
download | scummvm-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.cpp | 152 | ||||
-rw-r--r-- | sound/audiocd.h | 74 | ||||
-rw-r--r-- | sound/module.mk | 5 | ||||
-rw-r--r-- | sound/mp3.cpp | 127 | ||||
-rw-r--r-- | sound/mp3.h | 47 | ||||
-rw-r--r-- | sound/vorbis.cpp | 150 | ||||
-rw-r--r-- | sound/vorbis.h | 49 |
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 |