1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "backends/audiocd/default/default-audiocd.h"
24 #include "audio/audiostream.h"
25 #include "common/config-manager.h"
26 #include "common/system.h"
27 
DefaultAudioCDManager()28 DefaultAudioCDManager::DefaultAudioCDManager() {
29 	_cd.playing = false;
30 	_cd.track = 0;
31 	_cd.start = 0;
32 	_cd.duration = 0;
33 	_cd.numLoops = 0;
34 	_cd.volume = Audio::Mixer::kMaxChannelVolume;
35 	_cd.balance = 0;
36 	_mixer = g_system->getMixer();
37 	_emulating = false;
38 	assert(_mixer);
39 }
40 
~DefaultAudioCDManager()41 DefaultAudioCDManager::~DefaultAudioCDManager() {
42 	// Subclasses should call close as well
43 	close();
44 }
45 
open()46 bool DefaultAudioCDManager::open() {
47 	// For emulation, opening is always valid
48 	close();
49 	return true;
50 }
51 
close()52 void DefaultAudioCDManager::close() {
53 	// Only need to stop for emulation
54 	stop();
55 }
56 
play(int track,int numLoops,int startFrame,int duration,bool onlyEmulate,Audio::Mixer::SoundType soundType)57 bool DefaultAudioCDManager::play(int track, int numLoops, int startFrame, int duration, bool onlyEmulate,
58 		Audio::Mixer::SoundType soundType) {
59 	stop();
60 
61 	if (numLoops != 0 || startFrame != 0) {
62 		_cd.track = track;
63 		_cd.numLoops = numLoops;
64 		_cd.start = startFrame;
65 		_cd.duration = duration;
66 
67 		// Try to load the track from a compressed data file, and if found, use
68 		// that. If not found, attempt to start regular Audio CD playback of
69 		// the requested track.
70 		char trackName[2][16];
71 		sprintf(trackName[0], "track%d", track);
72 		sprintf(trackName[1], "track%02d", track);
73 		Audio::SeekableAudioStream *stream = 0;
74 
75 		for (int i = 0; !stream && i < 2; ++i)
76 			stream = Audio::SeekableAudioStream::openStreamFile(trackName[i]);
77 
78 		if (stream != 0) {
79 			Audio::Timestamp start = Audio::Timestamp(0, startFrame, 75);
80 			Audio::Timestamp end = duration ? Audio::Timestamp(0, startFrame + duration, 75) : stream->getLength();
81 
82 			/*
83 			FIXME: Seems numLoops == 0 and numLoops == 1 both indicate a single repetition,
84 			while all other positive numbers indicate precisely the number of desired
85 			repetitions. Finally, -1 means infinitely many
86 			*/
87 			_emulating = true;
88 			_mixer->playStream(soundType, &_handle,
89 			                        Audio::makeLoopingAudioStream(stream, start, end, (numLoops < 1) ? numLoops + 1 : numLoops), -1, _cd.volume, _cd.balance);
90 			return true;
91 		}
92 	}
93 
94 	return false;
95 }
96 
stop()97 void DefaultAudioCDManager::stop() {
98 	if (_emulating) {
99 		// Audio CD emulation
100 		_mixer->stopHandle(_handle);
101 		_emulating = false;
102 	}
103 }
104 
isPlaying() const105 bool DefaultAudioCDManager::isPlaying() const {
106 	// Audio CD emulation
107 	if (_emulating)
108 		return _mixer->isSoundHandleActive(_handle);
109 
110 	// The default class only handles emulation
111 	return false;
112 }
113 
setVolume(byte volume)114 void DefaultAudioCDManager::setVolume(byte volume) {
115 	_cd.volume = volume;
116 
117 	// Audio CD emulation
118 	if (_emulating && isPlaying())
119 		_mixer->setChannelVolume(_handle, _cd.volume);
120 }
121 
setBalance(int8 balance)122 void DefaultAudioCDManager::setBalance(int8 balance) {
123 	_cd.balance = balance;
124 
125 	// Audio CD emulation
126 	if (_emulating && isPlaying())
127 		_mixer->setChannelBalance(_handle, _cd.balance);
128 }
129 
update()130 void DefaultAudioCDManager::update() {
131 	if (_emulating) {
132 		// Check whether the audio track stopped playback
133 		if (!_mixer->isSoundHandleActive(_handle)) {
134 			// FIXME: We do not update the numLoops parameter here (and in fact,
135 			// currently can't do that). Luckily, only one engine ever checks
136 			// this part of the AudioCD status, namely the SCUMM engine; and it
137 			// only checks whether the track is currently set to infinite looping
138 			// or not.
139 			_emulating = false;
140 		}
141 	}
142 }
143 
getStatus() const144 DefaultAudioCDManager::Status DefaultAudioCDManager::getStatus() const {
145 	Status info = _cd;
146 	info.playing = isPlaying();
147 	return info;
148 }
149 
openRealCD()150 bool DefaultAudioCDManager::openRealCD() {
151 	Common::String cdrom = ConfMan.get("cdrom");
152 
153 	// Try to parse it as an int
154 	char *endPos;
155 	int drive = strtol(cdrom.c_str(), &endPos, 0);
156 
157 	// If not an integer, treat as a drive path
158 	if (endPos == cdrom.c_str())
159 		return openCD(cdrom);
160 
161 	if (drive < 0)
162 		return false;
163 
164 	return openCD(drive);
165 }
166 
167