aboutsummaryrefslogtreecommitdiff
path: root/backends/audiocd
diff options
context:
space:
mode:
authorMatthew Hoops2012-12-30 13:38:56 -0500
committerJohannes Schickel2016-03-13 13:53:55 +0100
commit47a82f2d1b776ec46d98715c9af3e7ec37a3d206 (patch)
tree13c78700b58900f6b2a672d7674ca2b8c3203cc0 /backends/audiocd
parent55a87c59b61fe6758faee3a3e388b2a8979c7cb8 (diff)
downloadscummvm-rg350-47a82f2d1b776ec46d98715c9af3e7ec37a3d206.tar.gz
scummvm-rg350-47a82f2d1b776ec46d98715c9af3e7ec37a3d206.tar.bz2
scummvm-rg350-47a82f2d1b776ec46d98715c9af3e7ec37a3d206.zip
BACKENDS: Add a custom Mac OS X CD audio manager
Since Mac OS X Carbon/Cocoa API isn't stable (in that it's changed multiple times over the years). Maintaining two versions of the same code (one in some foreign language with overly long names) isn't very appealing to me.
Diffstat (limited to 'backends/audiocd')
-rw-r--r--backends/audiocd/macosx/macosx-audiocd.cpp239
-rw-r--r--backends/audiocd/macosx/macosx-audiocd.h39
2 files changed, 278 insertions, 0 deletions
diff --git a/backends/audiocd/macosx/macosx-audiocd.cpp b/backends/audiocd/macosx/macosx-audiocd.cpp
new file mode 100644
index 0000000000..a8ba712621
--- /dev/null
+++ b/backends/audiocd/macosx/macosx-audiocd.cpp
@@ -0,0 +1,239 @@
+/* Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+#include <sys/stat.h>
+#include <sys/mount.h>
+
+#include "common/scummsys.h"
+
+#include "audio/audiostream.h"
+#include "audio/decoders/aiff.h"
+#include "audio/timestamp.h"
+#include "common/config-manager.h"
+#include "common/debug.h"
+#include "common/fs.h"
+#include "common/hashmap.h"
+#include "common/textconsole.h"
+#include "backends/audiocd/default/default-audiocd.h"
+#include "backends/audiocd/macosx/macosx-audiocd.h"
+#include "backends/fs/stdiostream.h"
+
+// Partially based on SDL's code
+
+/**
+ * The Mac OS X audio cd manager. Implements real audio cd playback.
+ */
+class MacOSXAudioCDManager : public DefaultAudioCDManager {
+public:
+ MacOSXAudioCDManager() {}
+ ~MacOSXAudioCDManager();
+
+ void playCD(int track, int num_loops, int start_frame, int duration);
+ void closeCD();
+
+protected:
+ bool openCD(int drive);
+
+private:
+ struct Drive {
+ Drive(const Common::String &m, const Common::String &d, const Common::String &f) :
+ mountPoint(m), deviceName(d), fsType(f) {}
+
+ Common::String mountPoint;
+ Common::String deviceName;
+ Common::String fsType;
+ };
+
+ typedef Common::Array<Drive> DriveList;
+ DriveList detectAllDrives();
+ DriveList detectCDDADrives();
+
+ bool findTrackNames(const Common::String &drivePath);
+
+ Common::HashMap<uint, Common::String> _trackMap;
+};
+
+MacOSXAudioCDManager::~MacOSXAudioCDManager() {
+ closeCD();
+}
+
+/**
+ * Find the base disk number of device name.
+ * Returns -1 if mount point is not /dev/disk*
+ */
+static int findBaseDiskNumber(const Common::String &diskName) {
+ if (!diskName.hasPrefix("/dev/disk"))
+ return -1;
+
+ const char *startPtr = diskName.c_str() + 9;
+ char *endPtr;
+ int baseDiskNumber = strtol(startPtr, &endPtr, 10);
+ if (startPtr == endPtr)
+ return -1;
+
+ return baseDiskNumber;
+}
+
+bool MacOSXAudioCDManager::openCD(int drive) {
+ closeCD();
+
+ DriveList allDrives = detectAllDrives();
+ if (allDrives.empty())
+ return false;
+
+ DriveList cddaDrives;
+
+ // Try to get the volume related to the game's path
+ if (ConfMan.hasKey("path")) {
+ Common::String gamePath = ConfMan.get("path");
+ struct statfs gamePathStat;
+ if (statfs(gamePath.c_str(), &gamePathStat) == 0) {
+ int baseDiskNumber = findBaseDiskNumber(gamePathStat.f_mntfromname);
+ if (baseDiskNumber >= 0) {
+ // Look for a CDDA drive with the same base disk number
+ for (uint32 i = 0; i < allDrives.size(); i++) {
+ if (allDrives[i].fsType == "cddafs" && findBaseDiskNumber(allDrives[i].deviceName) == baseDiskNumber) {
+ debug(1, "Preferring drive '%s'", allDrives[i].mountPoint.c_str());
+ cddaDrives.push_back(allDrives[i]);
+ allDrives.remove_at(i);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ // Add the remaining CDDA drives to the CDDA list
+ for (uint32 i = 0; i < allDrives.size(); i++)
+ if (allDrives[i].fsType == "cddafs")
+ cddaDrives.push_back(allDrives[i]);
+
+ if (drive >= (int)cddaDrives.size())
+ return false;
+
+ debug(1, "Using '%s' as the CD drive", cddaDrives[drive].mountPoint.c_str());
+
+ return findTrackNames(cddaDrives[drive].mountPoint);
+}
+
+void MacOSXAudioCDManager::closeCD() {
+ stop();
+ _trackMap.clear();
+}
+
+enum {
+ // Some crazy high number that we'll never actually hit
+ kMaxDriveCount = 256
+};
+
+MacOSXAudioCDManager::DriveList MacOSXAudioCDManager::detectAllDrives() {
+ // Fetch the lists of drives
+ struct statfs driveStats[kMaxDriveCount];
+ int foundDrives = getfsstat(driveStats, sizeof(driveStats), MNT_WAIT);
+ if (foundDrives <= 0)
+ return DriveList();
+
+ DriveList drives;
+ for (int i = 0; i < foundDrives; i++)
+ drives.push_back(Drive(driveStats[i].f_mntonname, driveStats[i].f_mntfromname, driveStats[i].f_fstypename));
+
+ return drives;
+}
+
+void MacOSXAudioCDManager::playCD(int track, int numLoops, int startFrame, int duration) {
+ if (!_trackMap.contains(track) || (!numLoops && !startFrame))
+ return;
+
+ // Now load the AIFF track from the name
+ Common::String fileName = _trackMap[track];
+ Common::SeekableReadStream *stream = StdioStream::makeFromPath(fileName.c_str(), false);
+
+ if (!stream) {
+ warning("Failed to open track '%s'", fileName.c_str());
+ return;
+ }
+
+ Audio::AudioStream *audioStream = Audio::makeAIFFStream(stream, DisposeAfterUse::YES);
+ if (!audioStream) {
+ warning("Track '%s' is not an AIFF track", fileName.c_str());
+ return;
+ }
+
+ Audio::SeekableAudioStream *seekStream = dynamic_cast<Audio::SeekableAudioStream *>(audioStream);
+ if (!seekStream) {
+ warning("Track '%s' is not seekable", fileName.c_str());
+ return;
+ }
+
+ Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
+ Audio::Timestamp end = duration ? Audio::Timestamp(0, startFrame + duration, 75) : seekStream->getLength();
+
+ // Fake emulation since we're really playing an AIFF file
+ _emulating = true;
+
+ _mixer->playStream(Audio::Mixer::kMusicSoundType, &_handle,
+ Audio::makeLoopingAudioStream(seekStream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance);
+}
+
+bool MacOSXAudioCDManager::findTrackNames(const Common::String &drivePath) {
+ Common::FSNode directory(drivePath);
+
+ if (!directory.exists()) {
+ warning("Directory '%s' does not exist", drivePath.c_str());
+ return false;
+ }
+
+ if (!directory.isDirectory()) {
+ warning("'%s' is not a directory", drivePath.c_str());
+ return false;
+ }
+
+ Common::FSList children;
+ if (!directory.getChildren(children, Common::FSNode::kListFilesOnly)) {
+ warning("Failed to find children for '%s'", drivePath.c_str());
+ return false;
+ }
+
+ for (uint32 i = 0; i < children.size(); i++) {
+ if (!children[i].isDirectory()) {
+ Common::String fileName = children[i].getName();
+
+ if (fileName.hasSuffix(".aiff") || fileName.hasSuffix(".cdda")) {
+ uint trackID = 0, j = 0;
+
+ for (; j < fileName.size() && !Common::isDigit(fileName[j]); j++)
+ ;
+
+ for (; j < fileName.size() && Common::isDigit(fileName[j]); j++)
+ trackID = trackID * 10 + (fileName[j] - '0');
+
+ _trackMap[trackID - 1] = drivePath + '/' + fileName;
+ }
+ }
+ }
+
+ return true;
+}
+
+AudioCDManager *createMacOSXAudioCDManager() {
+ return new MacOSXAudioCDManager();
+}
diff --git a/backends/audiocd/macosx/macosx-audiocd.h b/backends/audiocd/macosx/macosx-audiocd.h
new file mode 100644
index 0000000000..cfa979e2c2
--- /dev/null
+++ b/backends/audiocd/macosx/macosx-audiocd.h
@@ -0,0 +1,39 @@
+/* Cabal - Legacy Game Implementations
+ *
+ * Cabal 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.
+ *
+ */
+
+#ifndef BACKENDS_AUDIOCD_MACOSX_H
+#define BACKENDS_AUDIOCD_MACOSX_H
+
+#include "common/scummsys.h"
+
+#ifdef MACOSX
+
+class AudioCDManager;
+
+/**
+ * Create an audio CD manager for Mac OS X
+ */
+AudioCDManager *createMacOSXAudioCDManager();
+
+#endif
+
+#endif //