Initial commit
This commit is contained in:
116
engines/zvision/sound/midi.cpp
Normal file
116
engines/zvision/sound/midi.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "audio/mididrv.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/textconsole.h"
|
||||
#include "zvision/detection.h"
|
||||
#include "zvision/sound/midi.h"
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
MidiManager::MidiManager() {
|
||||
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(MDT_MIDI | MDT_ADLIB);
|
||||
_driver = MidiDriver::createMidi(dev);
|
||||
if (_driver->open()) {
|
||||
warning("Can't open MIDI, no MIDI output!");
|
||||
_available = false;
|
||||
} else {
|
||||
Common::String driverName = MidiDriver::getDeviceString(dev, MidiDriver::DeviceStringType::kDriverName);
|
||||
Common::String deviceName = MidiDriver::getDeviceString(dev, MidiDriver::DeviceStringType::kDeviceName);
|
||||
_mt32 = MidiDriver::getMusicType(dev) == MT_MT32;
|
||||
debugC(1, kDebugSound, "MIDI opened, driver type: %s, device name: %s", driverName.c_str(), deviceName.c_str());
|
||||
_available = true;
|
||||
_maxChannels = _driver->MIDI_CHANNEL_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
MidiManager::~MidiManager() {
|
||||
stop();
|
||||
_driver->close();
|
||||
delete _driver;
|
||||
}
|
||||
|
||||
void MidiManager::send(uint8 status, uint8 data1, uint8 data2) {
|
||||
assert(status & 0x80 && "Malformed MIDI status byte");
|
||||
assert(!(data1 & 0x80) && "Malformed MIDI data byte 1");
|
||||
assert(!(data2 & 0x80) && "Malformed MIDI data byte 2");
|
||||
_driver->send(status | (data1 << 8) | (data2 << 16));
|
||||
}
|
||||
|
||||
void MidiManager::stop() {
|
||||
for (uint8 i = 0; i < 16; i++)
|
||||
noteOff(i);
|
||||
}
|
||||
|
||||
void MidiManager::noteOn(uint8 channel, uint8 note, uint8 velocity) {
|
||||
assert(channel <= 15);
|
||||
|
||||
_activeChannels[channel].playing = true;
|
||||
_activeChannels[channel].note = note;
|
||||
send(0x90 | channel, note, velocity);
|
||||
debugC(1, kDebugSound, "MIDI note on, channel %d, note %d, velocity %d", channel, note, velocity);
|
||||
}
|
||||
|
||||
void MidiManager::noteOff(uint8 channel) {
|
||||
assert(channel <= 15);
|
||||
|
||||
if (_activeChannels[channel].playing) {
|
||||
_activeChannels[channel].playing = false;
|
||||
send(0x80 | channel, _activeChannels[channel].note);
|
||||
}
|
||||
}
|
||||
|
||||
int8 MidiManager::getFreeChannel() {
|
||||
uint8 start = _mt32 ? 1 : 0; // MT-32 can be used for MIDI, but does not play anything on MIDI channel 0
|
||||
for (uint8 i = start; i < 16; i++)
|
||||
if (!_activeChannels[i].playing)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
void MidiManager::setVolume(uint8 channel, uint8 volume) {
|
||||
assert(channel <= 15);
|
||||
debugC(1, kDebugSound, "MIDI volume out %d", volume >> 1);
|
||||
send(0xB0 | channel, 0x07, volume >> 1);
|
||||
}
|
||||
|
||||
void MidiManager::setBalance(uint8 channel, int8 balance) {
|
||||
assert(channel <= 15);
|
||||
uint8 _balance = (uint8)(balance + 128);
|
||||
debugC(1, kDebugSound, "MIDI balance out %d", _balance >> 1);
|
||||
send(0xB0 | channel, 0x08, _balance >> 1);
|
||||
}
|
||||
|
||||
void MidiManager::setPan(uint8 channel, int8 pan) {
|
||||
assert(channel <= 15);
|
||||
uint8 _pan = (uint8)(pan + 128);
|
||||
debugC(1, kDebugSound, "MIDI pan in %d, out %d", pan, _pan >> 1);
|
||||
send(0xB0 | channel, 0x0A, _pan >> 1);
|
||||
}
|
||||
|
||||
void MidiManager::setProgram(uint8 channel, uint8 prog) {
|
||||
assert(channel <= 15);
|
||||
send(0xC0 | channel, prog);
|
||||
}
|
||||
|
||||
} // End of namespace ZVision
|
||||
65
engines/zvision/sound/midi.h
Normal file
65
engines/zvision/sound/midi.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ZVISION_MIDI_H
|
||||
#define ZVISION_MIDI_H
|
||||
|
||||
class MidiDriver;
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
class MidiManager {
|
||||
public:
|
||||
MidiManager();
|
||||
~MidiManager();
|
||||
|
||||
void stop();
|
||||
void noteOn(uint8 channel, uint8 noteNumber, uint8 velocity);
|
||||
void noteOff(uint8 channel);
|
||||
void setVolume(uint8 channel, uint8 volume);
|
||||
void setBalance(uint8 channel, int8 balance);
|
||||
void setPan(uint8 channel, int8 pan);
|
||||
void setProgram(uint8 channel, uint8 prog);
|
||||
|
||||
int8 getFreeChannel(); // Negative if none available
|
||||
bool isAvailable() const {
|
||||
return _available;
|
||||
}
|
||||
|
||||
protected:
|
||||
bool _available = false;
|
||||
bool _mt32 = false;
|
||||
struct chan {
|
||||
bool playing;
|
||||
uint8 note;
|
||||
|
||||
chan() : playing(false), note(0) {}
|
||||
};
|
||||
void send(uint8 status, uint8 data1 = 0x00, uint8 data2 = 0x00);
|
||||
uint8 _startChannel = 0;
|
||||
uint8 _maxChannels = 16;
|
||||
MidiDriver *_driver;
|
||||
chan _activeChannels[16];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
291
engines/zvision/sound/volume_manager.cpp
Normal file
291
engines/zvision/sound/volume_manager.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "zvision/detection.h"
|
||||
#include "zvision/scripting/script_manager.h"
|
||||
#include "zvision/sound/volume_manager.h"
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
// Power law with exponent 1.5.
|
||||
static constexpr uint8 powerLaw[256] = {
|
||||
0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4,
|
||||
4, 4, 5, 5, 6, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11,
|
||||
11, 12, 12, 13, 14, 14, 15, 15, 16, 16, 17, 18, 18, 19, 20, 20,
|
||||
21, 21, 22, 23, 23, 24, 25, 26, 26, 27, 28, 28, 29, 30, 31, 31,
|
||||
32, 33, 34, 34, 35, 36, 37, 37, 38, 39, 40, 41, 41, 42, 43, 44,
|
||||
45, 46, 46, 47, 48, 49, 50, 51, 52, 53, 53, 54, 55, 56, 57, 58,
|
||||
59, 60, 61, 62, 63, 64, 65, 65, 66, 67, 68, 69, 70, 71, 72, 73,
|
||||
74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 88, 89, 90,
|
||||
91, 92, 93, 94, 95, 96, 97, 98, 99,100,102,103,104,105,106,107,
|
||||
108,109,110,112,113,114,115,116,117,119,120,121,122,123,124,126,
|
||||
127,128,129,130,132,133,134,135,136,138,139,140,141,142,144,145,
|
||||
146,147,149,150,151,152,154,155,156,158,159,160,161,163,164,165,
|
||||
167,168,169,171,172,173,174,176,177,178,180,181,182,184,185,187,
|
||||
188,189,191,192,193,195,196,197,199,200,202,203,204,206,207,209,
|
||||
210,211,213,214,216,217,218,220,221,223,224,226,227,228,230,231,
|
||||
233,234,236,237,239,240,242,243,245,246,248,249,251,252,254,255
|
||||
};
|
||||
|
||||
static constexpr uint8 logPower[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
|
||||
3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 8,
|
||||
8, 9, 9, 10, 10, 11, 11, 12, 13, 13, 14, 15, 16, 17, 18, 19,
|
||||
20, 21, 22, 23, 24, 26, 27, 29, 30, 32, 34, 36, 38, 40, 42, 45,
|
||||
47, 50, 52, 55, 58, 62, 65, 69, 73, 77, 81, 86, 90, 96,101,107,
|
||||
113,119,126,133,140,148,156,165,174,184,194,205,217,229,241,255
|
||||
};
|
||||
|
||||
// */
|
||||
static constexpr uint8 logAmplitude[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5,
|
||||
5, 5, 5, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8,
|
||||
8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 12, 12,
|
||||
2, 13, 13, 13, 14, 14, 15, 15, 15, 16, 16, 17, 17, 18, 18, 19,
|
||||
19, 20, 20, 21, 21, 22, 23, 23, 24, 24, 25, 26, 27, 27, 28, 29,
|
||||
30, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45,
|
||||
46, 47, 48, 50, 51, 52, 54, 55, 57, 58, 60, 62, 63, 65, 67, 69,
|
||||
71, 73, 75, 77, 79, 81, 83, 86, 88, 90, 93, 96, 98,101,104,107,
|
||||
110,113,116,119,122,126,129,133,136,140,144,148,152,156,160,165,
|
||||
169,174,179,184,189,194,200,205,211,217,222,229,235,241,248,255
|
||||
};
|
||||
/*/
|
||||
// Old system; this is wrong, caused bug #7176; cloister fountain (value 50 in-game, 127/255) inaudible
|
||||
// Using linear volume served as a temporary fix, but causes other sounds not to play at correct amplitudes (e.g. beehive, door singing in ZGI)
|
||||
static constexpr uint8 logAmplitude[256] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
|
||||
4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
|
||||
8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13, 13, 14,
|
||||
14, 15, 15, 16, 16, 17, 18, 18, 19, 20, 21, 21, 22, 23, 24, 25,
|
||||
26, 27, 28, 29, 30, 31, 32, 33, 34, 36, 37, 38, 40, 41, 43, 45,
|
||||
46, 48, 50, 52, 53, 55, 57, 60, 62, 64, 67, 69, 72, 74, 77, 80,
|
||||
83, 86, 89, 92, 96, 99,103,107,111,115,119,123,128,133,137,143,
|
||||
148,153,159,165,171,177,184,191,198,205,212,220,228,237,245,255
|
||||
};
|
||||
// */
|
||||
|
||||
/*
|
||||
Estimated relative amplitude of a point sound source as it circles the listener's head from front to rear, due to ear pinna shape.
|
||||
Maximum attenuation -5dB when fully to rear. Seems to give a reasonably realistic effect when tested on the Nemesis cloister fountain.
|
||||
Should be applied AFTER volume profile is applied to script files.
|
||||
Generating function:
|
||||
for 0 < theta < 90, amp = 255;
|
||||
for 90 < theta < 180, amp = 255*10^(1-(cos(2*(theta-90))/4))
|
||||
where theta is the azimuth, in degrees, of the sound source relative to straight ahead of listener
|
||||
Source: Own work; crude and naive model that is probably not remotely scientifically accurate, but good enough for a 30-year-old game.
|
||||
*/
|
||||
static constexpr uint8 directionalAmplitude[181] = {
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,255,255,255,254,254,253,
|
||||
252,251,249,248,246,245,243,241,238,236,234,231,228,226,223,220,
|
||||
217,214,211,208,204,201,198,195,191,188,185,181,178,175,171,168,
|
||||
165,162,158,155,152,149,146,143,141,138,135,132,130,127,125,122,
|
||||
120,118,116,113,111,109,108,106,104,102,101, 99, 98, 96, 95, 93,
|
||||
92, 91, 90, 89, 88, 87, 86, 85, 85, 84, 83, 83, 82, 82, 82, 81,
|
||||
81, 81, 81, 81, 81
|
||||
};
|
||||
|
||||
VolumeManager::VolumeManager(ZVision *engine, volumeScaling mode) :
|
||||
_mode(mode) {
|
||||
}
|
||||
|
||||
uint8 VolumeManager::convert(uint8 inputValue) {
|
||||
return convert(inputValue, _mode);
|
||||
}
|
||||
|
||||
uint8 VolumeManager::convert(uint8 inputValue, Math::Angle azimuth, uint8 directionality) {
|
||||
return convert(inputValue, _mode, azimuth, directionality);
|
||||
}
|
||||
|
||||
uint8 VolumeManager::convert(uint8 inputValue, volumeScaling &mode, Math::Angle azimuth, uint8 directionality) {
|
||||
uint8 index = abs(round(azimuth.getDegrees(-180)));
|
||||
uint32 output = convert(inputValue, mode);
|
||||
uint32 directionalOutput = (output * directionalAmplitude[index]) * directionality;
|
||||
directionalOutput /= 0xFF;
|
||||
output *= (0xFF - directionality);
|
||||
output = (output + directionalOutput) / 0xFF;
|
||||
debugC(4, kDebugSound, "Directionally converted output %d", output);
|
||||
return output;
|
||||
}
|
||||
|
||||
uint8 VolumeManager::convert(uint8 inputValue, volumeScaling &mode) {
|
||||
if (inputValue > _scriptScale)
|
||||
inputValue = _scriptScale;
|
||||
uint32 scaledInput = inputValue * 0xFF;
|
||||
scaledInput /= _scriptScale;
|
||||
uint8 output = 0;
|
||||
switch (mode) {
|
||||
case kVolumeLogPower:
|
||||
output = logPower[scaledInput];
|
||||
break;
|
||||
case kVolumeLogAmplitude:
|
||||
output = logAmplitude[scaledInput];
|
||||
break;
|
||||
case kVolumePowerLaw:
|
||||
output = powerLaw[scaledInput];
|
||||
break;
|
||||
case kVolumeParabolic:
|
||||
scaledInput *= scaledInput;
|
||||
output = scaledInput / 0xFF;
|
||||
break;
|
||||
case kVolumeCubic:
|
||||
scaledInput *= scaledInput * scaledInput;
|
||||
output = scaledInput / 0xFE01;
|
||||
break;
|
||||
case kVolumeQuartic:
|
||||
scaledInput *= scaledInput;
|
||||
scaledInput *= scaledInput;
|
||||
output = scaledInput / 0xFD02FF;
|
||||
break;
|
||||
case kVolumeLinear:
|
||||
default:
|
||||
output = scaledInput;
|
||||
break;
|
||||
}
|
||||
debugC(4, kDebugSound, "Scripted volume %d, scaled volume %d, converted output %d", inputValue, scaledInput, output);
|
||||
return output;
|
||||
}
|
||||
|
||||
#if defined(USE_MPEG2) && defined(USE_A52)
|
||||
double VolumeManager::getVobAmplification(Common::String fileName) const {
|
||||
// For some reason, we get much lower volume in the hi-res videos than
|
||||
// in the low-res ones. So we artificially boost the volume. This is an
|
||||
// approximation, but I've tried to match the old volumes reasonably
|
||||
// well.
|
||||
//
|
||||
// Some of these will cause audio clipping. Hopefully not enough to be
|
||||
// noticeable.
|
||||
double amplification = 0.0;
|
||||
if (fileName == "em00d011.vob") {
|
||||
// The finale.
|
||||
amplification = 10.0;
|
||||
} else if (fileName == "em00d021.vob") {
|
||||
// Jack's escape and arrival at Flathead Mesa.
|
||||
amplification = 9.0;
|
||||
} else if (fileName == "em00d032.vob") {
|
||||
// The Grand Inquisitor's speech.
|
||||
amplification = 11.0;
|
||||
} else if (fileName == "em00d122.vob") {
|
||||
// Jack orders you to the radio tower.
|
||||
amplification = 17.0;
|
||||
} else if (fileName == "em3ed012.vob") {
|
||||
// The Grand Inquisitor gets the Coconut of Quendor.
|
||||
amplification = 12.0;
|
||||
} else if (fileName == "g000d101.vob") {
|
||||
// Griff gets captured.
|
||||
amplification = 11.0;
|
||||
} else if (fileName == "g000d111.vob") {
|
||||
// Brog gets totemized. The music seems to be mixed much softer
|
||||
// in this than in the low-resolution version.
|
||||
amplification = 12.0;
|
||||
} else if (fileName == "g000d122.vob") {
|
||||
// Lucy gets captured.
|
||||
amplification = 14.0;
|
||||
} else if (fileName == "g000d302.vob") {
|
||||
// The Grand Inquisitor visits Jack in his cell.
|
||||
amplification = 13.0;
|
||||
} else if (fileName == "g000d312.vob") {
|
||||
// You get captured.
|
||||
amplification = 14.0;
|
||||
} else if (fileName == "g000d411.vob") {
|
||||
// Propaganda On Parade. No need to make it as loud as the
|
||||
// low-resolution version.
|
||||
amplification = 11.0;
|
||||
} else if (fileName == "pe1ed012.vob") {
|
||||
// Jack lets you in with the lantern.
|
||||
amplification = 14.0;
|
||||
} else if (fileName.hasPrefix("pe1ed")) {
|
||||
// Jack answers the door. Several different ways.
|
||||
amplification = 17.0;
|
||||
} else if (fileName == "pe5ed052.vob") {
|
||||
// You get killed by the guards
|
||||
amplification = 12.0;
|
||||
} else if (fileName == "pe6ed012.vob") {
|
||||
// Jack gets captured by the guards
|
||||
amplification = 17.0;
|
||||
} else if (fileName == "pp1ed022.vob") {
|
||||
// Jack examines the lantern
|
||||
amplification = 10.0;
|
||||
} else if (fileName == "qb1ed012.vob") {
|
||||
// Lucy gets invited to the back room
|
||||
amplification = 17.0;
|
||||
} else if (fileName.hasPrefix("qe1ed")) {
|
||||
// Floyd answers the door. Several different ways.
|
||||
amplification = 17.0;
|
||||
} else if (fileName == "qs1ed011.vob") {
|
||||
// Jack explains the rules of the game.
|
||||
amplification = 16.0;
|
||||
} else if (fileName == "qs1ed021.vob") {
|
||||
// Jack loses the game.
|
||||
amplification = 14.0;
|
||||
} else if (fileName == "uc1gd012.vob") {
|
||||
// Y'Gael appears.
|
||||
amplification = 12.0;
|
||||
} else if (fileName == "ue1ud012.vob") {
|
||||
// Jack gets totemized... or what?
|
||||
amplification = 12.0;
|
||||
} else if (fileName == "ue2qd012.vob") {
|
||||
// Jack agrees to totemization.
|
||||
amplification = 10.0;
|
||||
} else if (fileName == "g000d981.vob") {
|
||||
// The Enterprise logo. Has no low-res version. Its volume is
|
||||
// louder than the other logo animations.
|
||||
amplification = 6.2;
|
||||
} else if (fileName.hasPrefix("g000d")) {
|
||||
// The Dolby Digital and Activision logos. They have no low-res
|
||||
// versions, but I've used the low-resolution Activision logo
|
||||
// (slightly different) as reference.
|
||||
amplification = 8.5;
|
||||
}
|
||||
return amplification;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // End of namespace ZVision
|
||||
66
engines/zvision/sound/volume_manager.h
Normal file
66
engines/zvision/sound/volume_manager.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "math/angle.h"
|
||||
#include "zvision/zvision.h"
|
||||
|
||||
#ifndef ZVISION_VOLUME_MANAGER
|
||||
#define ZVISION_VOLUME_MANAGER
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
enum volumeScaling {
|
||||
kVolumeLinear,
|
||||
kVolumePowerLaw,
|
||||
kVolumeParabolic,
|
||||
kVolumeCubic,
|
||||
kVolumeQuartic,
|
||||
kVolumeLogPower,
|
||||
kVolumeLogAmplitude
|
||||
};
|
||||
|
||||
class VolumeManager {
|
||||
public:
|
||||
VolumeManager(ZVision *engine, volumeScaling mode);
|
||||
~VolumeManager() {};
|
||||
volumeScaling getMode() const {
|
||||
return _mode;
|
||||
}
|
||||
void setMode(volumeScaling mode) {
|
||||
_mode = mode;
|
||||
}
|
||||
uint8 convert(uint8 inputValue);
|
||||
uint8 convert(uint8 inputValue, volumeScaling &mode);
|
||||
uint8 convert(uint8 inputValue, Math::Angle azimuth, uint8 directionality = 255);
|
||||
uint8 convert(uint8 inputValue, volumeScaling &mode, Math::Angle azimuth, uint8 directionality = 255);
|
||||
#if defined(USE_MPEG2) && defined(USE_A52)
|
||||
double getVobAmplification(Common::String fileName) const;
|
||||
#endif
|
||||
|
||||
private:
|
||||
uint _scriptScale = 100; // Z-Vision scripts internally use a volume scale of 0-100; ScummVM uses a scale of 0-255.
|
||||
volumeScaling _mode = kVolumeLinear;
|
||||
};
|
||||
|
||||
} // End of namespace ZVision
|
||||
|
||||
#endif
|
||||
278
engines/zvision/sound/zork_raw.cpp
Normal file
278
engines/zvision/sound/zork_raw.cpp
Normal file
@@ -0,0 +1,278 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
#include "common/bufferedstream.h"
|
||||
#include "common/file.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/str.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/tokenizer.h"
|
||||
#include "common/util.h"
|
||||
#include "zvision/zvision.h"
|
||||
#include "zvision/file/file_manager.h"
|
||||
#include "zvision/sound/zork_raw.h"
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
const int16 RawChunkStream::_stepAdjustmentTable[8] = { -1, -1, -1, 1, 4, 7, 10, 12};
|
||||
|
||||
const int32 RawChunkStream::_amplitudeLookupTable[89] = {
|
||||
0x0007, 0x0008, 0x0009, 0x000A, 0x000B, 0x000C, 0x000D, 0x000E,
|
||||
0x0010, 0x0011, 0x0013, 0x0015, 0x0017, 0x0019, 0x001C, 0x001F,
|
||||
0x0022, 0x0025, 0x0029, 0x002D, 0x0032, 0x0037, 0x003C, 0x0042,
|
||||
0x0049, 0x0050, 0x0058, 0x0061, 0x006B, 0x0076, 0x0082, 0x008F,
|
||||
0x009D, 0x00AD, 0x00BE, 0x00D1, 0x00E6, 0x00FD, 0x0117, 0x0133,
|
||||
0x0151, 0x0173, 0x0198, 0x01C1, 0x01EE, 0x0220, 0x0256, 0x0292,
|
||||
0x02D4, 0x031C, 0x036C, 0x03C3, 0x0424, 0x048E, 0x0502, 0x0583,
|
||||
0x0610, 0x06AB, 0x0756, 0x0812, 0x08E0, 0x09C3, 0x0ABD, 0x0BD0,
|
||||
0x0CFF, 0x0E4C, 0x0FBA, 0x114C, 0x1307, 0x14EE, 0x1706, 0x1954,
|
||||
0x1BDC, 0x1EA5, 0x21B6, 0x2515, 0x28CA, 0x2CDF, 0x315B, 0x364B,
|
||||
0x3BB9, 0x41B2, 0x4844, 0x4F7E, 0x5771, 0x602F, 0x69CE, 0x7462, 0x7FFF
|
||||
};
|
||||
|
||||
RawChunkStream::RawChunkStream(bool stereo) {
|
||||
if (stereo)
|
||||
_stereo = 1;
|
||||
else
|
||||
_stereo = 0;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
void RawChunkStream::init() {
|
||||
_lastSample[0].index = 0;
|
||||
_lastSample[0].sample = 0;
|
||||
_lastSample[1].index = 0;
|
||||
_lastSample[1].sample = 0;
|
||||
}
|
||||
|
||||
RawChunkStream::RawChunk RawChunkStream::readNextChunk(Common::SeekableReadStream *stream) {
|
||||
RawChunk tmp;
|
||||
tmp.size = 0;
|
||||
tmp.data = NULL;
|
||||
|
||||
if (!stream || stream->size() == 0 || stream->eos())
|
||||
return tmp;
|
||||
|
||||
tmp.size = (stream->size() - stream->pos()) * 2;
|
||||
tmp.data = (int16 *)calloc(tmp.size, 1);
|
||||
|
||||
readBuffer(tmp.data, stream, stream->size() - stream->pos());
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int RawChunkStream::readBuffer(int16 *buffer, Common::SeekableReadStream *stream, const int numSamples) {
|
||||
int32 bytesRead = 0;
|
||||
|
||||
// 0: Left, 1: Right
|
||||
uint channel = 0;
|
||||
|
||||
while (bytesRead < numSamples) {
|
||||
byte encodedSample = stream->readByte();
|
||||
if (stream->eos()) {
|
||||
return bytesRead;
|
||||
}
|
||||
bytesRead++;
|
||||
|
||||
int16 index = _lastSample[channel].index;
|
||||
uint32 lookUpSample = _amplitudeLookupTable[index];
|
||||
|
||||
int32 sample = 0;
|
||||
|
||||
if (encodedSample & 0x40)
|
||||
sample += lookUpSample;
|
||||
if (encodedSample & 0x20)
|
||||
sample += lookUpSample >> 1;
|
||||
if (encodedSample & 0x10)
|
||||
sample += lookUpSample >> 2;
|
||||
if (encodedSample & 8)
|
||||
sample += lookUpSample >> 3;
|
||||
if (encodedSample & 4)
|
||||
sample += lookUpSample >> 4;
|
||||
if (encodedSample & 2)
|
||||
sample += lookUpSample >> 5;
|
||||
if (encodedSample & 1)
|
||||
sample += lookUpSample >> 6;
|
||||
if (encodedSample & 0x80)
|
||||
sample = -sample;
|
||||
|
||||
sample += _lastSample[channel].sample;
|
||||
sample = CLIP<int32>(sample, -32768, 32767);
|
||||
|
||||
buffer[bytesRead - 1] = (int16)sample;
|
||||
|
||||
index += _stepAdjustmentTable[(encodedSample >> 4) & 7];
|
||||
index = CLIP<int16>(index, 0, 88);
|
||||
|
||||
_lastSample[channel].sample = sample;
|
||||
_lastSample[channel].index = index;
|
||||
|
||||
// Increment and wrap the channel
|
||||
channel = (channel + 1) & _stereo;
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
const SoundParams RawZorkStream::_zNemSoundParamLookupTable[32] = {
|
||||
{'0', 0x1F40, false, false, false},
|
||||
{'1', 0x1F40, true, false, false},
|
||||
{'2', 0x1F40, false, false, true},
|
||||
{'3', 0x1F40, true, false, true},
|
||||
{'4', 0x2B11, false, false, false},
|
||||
{'5', 0x2B11, true, false, false},
|
||||
{'6', 0x2B11, false, false, true},
|
||||
{'7', 0x2B11, true, false, true},
|
||||
{'8', 0x5622, false, false, false},
|
||||
{'9', 0x5622, true, false, false},
|
||||
{'a', 0x5622, false, false, true},
|
||||
{'b', 0x5622, true, false, true},
|
||||
{'c', 0xAC44, false, false, false},
|
||||
{'d', 0xAC44, true, false, false},
|
||||
{'e', 0xAC44, false, false, true},
|
||||
{'f', 0xAC44, true, false, true},
|
||||
{'g', 0x1F40, false, true, false},
|
||||
{'h', 0x1F40, true, true, false},
|
||||
{'j', 0x1F40, false, true, true},
|
||||
{'k', 0x1F40, true, true, true},
|
||||
{'l', 0x2B11, false, true, false},
|
||||
{'m', 0x2B11, true, true, false},
|
||||
{'n', 0x2B11, false, true, true},
|
||||
{'p', 0x2B11, true, true, true},
|
||||
{'q', 0x5622, false, true, false},
|
||||
{'r', 0x5622, true, true, false},
|
||||
{'s', 0x5622, false, true, true},
|
||||
{'t', 0x5622, true, true, true},
|
||||
{'u', 0xAC44, false, true, false},
|
||||
{'v', 0xAC44, true, true, false},
|
||||
{'w', 0xAC44, false, true, true},
|
||||
{'x', 0xAC44, true, true, true}
|
||||
};
|
||||
|
||||
const SoundParams RawZorkStream::_zgiSoundParamLookupTable[24] = {
|
||||
{'4', 0x2B11, false, false, false},
|
||||
{'5', 0x2B11, true, false, false},
|
||||
{'6', 0x2B11, false, false, true},
|
||||
{'7', 0x2B11, true, false, true},
|
||||
{'8', 0x5622, false, false, false},
|
||||
{'9', 0x5622, true, false, false},
|
||||
{'a', 0x5622, false, false, true},
|
||||
{'b', 0x5622, true, false, true},
|
||||
{'c', 0xAC44, false, false, false},
|
||||
{'d', 0xAC44, true, false, false},
|
||||
{'e', 0xAC44, false, false, true},
|
||||
{'f', 0xAC44, true, false, true},
|
||||
{'g', 0x2B11, false, true, false},
|
||||
{'h', 0x2B11, true, true, false},
|
||||
{'j', 0x2B11, false, true, true},
|
||||
{'k', 0x2B11, true, true, true},
|
||||
{'m', 0x5622, false, true, false},
|
||||
{'n', 0x5622, true, true, false},
|
||||
{'p', 0x5622, false, true, true},
|
||||
{'q', 0x5622, true, true, true},
|
||||
{'r', 0xAC44, false, true, false},
|
||||
{'s', 0xAC44, true, true, false},
|
||||
{'t', 0xAC44, false, true, true},
|
||||
{'u', 0xAC44, true, true, true}
|
||||
};
|
||||
|
||||
RawZorkStream::RawZorkStream(uint32 rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream)
|
||||
: _rate(rate),
|
||||
_stereo(0),
|
||||
_stream(stream, disposeStream),
|
||||
_endOfData(false),
|
||||
_streamReader(stereo) {
|
||||
if (stereo)
|
||||
_stereo = 1;
|
||||
|
||||
// Calculate the total playtime of the stream
|
||||
if (stereo)
|
||||
_playtime = Audio::Timestamp(0, _stream->size() / 2, rate);
|
||||
else
|
||||
_playtime = Audio::Timestamp(0, _stream->size(), rate);
|
||||
}
|
||||
|
||||
int RawZorkStream::readBuffer(int16 *buffer, const int numSamples) {
|
||||
int32 bytesRead = _streamReader.readBuffer(buffer, _stream.get(), numSamples);
|
||||
|
||||
if (_stream->eos())
|
||||
_endOfData = true;
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
bool RawZorkStream::rewind() {
|
||||
_stream->seek(0, 0);
|
||||
_stream->clearErr();
|
||||
_endOfData = false;
|
||||
_streamReader.init();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream,
|
||||
int rate,
|
||||
bool stereo,
|
||||
DisposeAfterUse::Flag disposeAfterUse) {
|
||||
if (stereo)
|
||||
assert(stream->size() % 2 == 0);
|
||||
|
||||
return new RawZorkStream(rate, stereo, disposeAfterUse, stream);
|
||||
}
|
||||
|
||||
Audio::RewindableAudioStream *makeRawZorkStream(const Common::Path &filePath, ZVision *engine) {
|
||||
Common::String baseName = filePath.baseName();
|
||||
Common::File *file = engine->getFileManager()->open(filePath);
|
||||
|
||||
const SoundParams *soundParams = NULL;
|
||||
|
||||
if (engine->getGameId() == GID_NEMESIS) {
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
if (RawZorkStream::_zNemSoundParamLookupTable[i].identifier == (baseName[6]))
|
||||
soundParams = &RawZorkStream::_zNemSoundParamLookupTable[i];
|
||||
}
|
||||
} else if (engine->getGameId() == GID_GRANDINQUISITOR) {
|
||||
for (int i = 0; i < 24; ++i) {
|
||||
if (RawZorkStream::_zgiSoundParamLookupTable[i].identifier == (baseName[7]))
|
||||
soundParams = &RawZorkStream::_zgiSoundParamLookupTable[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (soundParams == NULL)
|
||||
return NULL;
|
||||
|
||||
if (soundParams->packed) {
|
||||
return makeRawZorkStream(wrapBufferedSeekableReadStream(file, 2048, DisposeAfterUse::YES), soundParams->rate, soundParams->stereo, DisposeAfterUse::YES);
|
||||
} else {
|
||||
byte flags = 0;
|
||||
if (soundParams->bits16)
|
||||
flags |= Audio::FLAG_16BITS | Audio::FLAG_LITTLE_ENDIAN;
|
||||
if (soundParams->stereo)
|
||||
flags |= Audio::FLAG_STEREO;
|
||||
|
||||
return Audio::makeRawStream(file, soundParams->rate, flags, DisposeAfterUse::YES);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace ZVision
|
||||
141
engines/zvision/sound/zork_raw.h
Normal file
141
engines/zvision/sound/zork_raw.h
Normal file
@@ -0,0 +1,141 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef ZVISION_ZORK_RAW_H
|
||||
#define ZVISION_ZORK_RAW_H
|
||||
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
namespace Common {
|
||||
class SeekableReadStream;
|
||||
}
|
||||
|
||||
namespace ZVision {
|
||||
|
||||
class ZVision;
|
||||
|
||||
struct SoundParams {
|
||||
char identifier;
|
||||
uint32 rate;
|
||||
bool stereo;
|
||||
bool packed;
|
||||
bool bits16;
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a ADPCM stream-reader, this class holds context for multi-chunk reading and no buffers.
|
||||
*/
|
||||
class RawChunkStream {
|
||||
public:
|
||||
RawChunkStream(bool stereo);
|
||||
|
||||
~RawChunkStream() {
|
||||
}
|
||||
private:
|
||||
uint _stereo;
|
||||
|
||||
/**
|
||||
* Holds the frequency and index from the last sample
|
||||
* 0 holds the left channel, 1 holds the right channel
|
||||
*/
|
||||
struct {
|
||||
int32 sample;
|
||||
int16 index;
|
||||
} _lastSample[2];
|
||||
|
||||
static const int16 _stepAdjustmentTable[8];
|
||||
static const int32 _amplitudeLookupTable[89];
|
||||
|
||||
public:
|
||||
|
||||
struct RawChunk {
|
||||
int16 *data;
|
||||
uint32 size;
|
||||
};
|
||||
|
||||
void init();
|
||||
//Read next audio portion in new stream (needed for avi), return structure with buffer
|
||||
RawChunk readNextChunk(Common::SeekableReadStream *stream);
|
||||
//Read numSamples from stream to buffer
|
||||
int readBuffer(int16 *buffer, Common::SeekableReadStream *stream, const int numSamples);
|
||||
};
|
||||
|
||||
/**
|
||||
* This is a stream, which allows for playing raw ADPCM data from a stream.
|
||||
*/
|
||||
class RawZorkStream : public Audio::RewindableAudioStream {
|
||||
public:
|
||||
RawZorkStream(uint32 rate, bool stereo, DisposeAfterUse::Flag disposeStream, Common::SeekableReadStream *stream);
|
||||
|
||||
~RawZorkStream() override {
|
||||
}
|
||||
|
||||
public:
|
||||
static const SoundParams _zNemSoundParamLookupTable[32];
|
||||
static const SoundParams _zgiSoundParamLookupTable[24];
|
||||
|
||||
private:
|
||||
const int _rate; // Sample rate of stream
|
||||
Audio::Timestamp _playtime; // Calculated total play time
|
||||
Common::DisposablePtr<Common::SeekableReadStream> _stream; // Stream to read data from
|
||||
bool _endOfData; // Whether the stream end has been reached
|
||||
uint _stereo;
|
||||
|
||||
RawChunkStream _streamReader;
|
||||
|
||||
public:
|
||||
int readBuffer(int16 *buffer, const int numSamples) override;
|
||||
|
||||
bool isStereo() const override {
|
||||
return _stereo;
|
||||
}
|
||||
bool endOfData() const override {
|
||||
return _endOfData;
|
||||
}
|
||||
|
||||
int getRate() const override {
|
||||
return _rate;
|
||||
}
|
||||
Audio::Timestamp getLength() const {
|
||||
return _playtime;
|
||||
}
|
||||
|
||||
bool rewind() override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates an audio stream, which plays from the given stream.
|
||||
*
|
||||
* @param stream Stream object to play from.
|
||||
* @param rate Rate of the sound data.
|
||||
* @param dispose AfterUse Whether to delete the stream after use.
|
||||
* @return The new SeekableAudioStream (or 0 on failure).
|
||||
*/
|
||||
Audio::RewindableAudioStream *makeRawZorkStream(Common::SeekableReadStream *stream,
|
||||
int rate,
|
||||
bool stereo,
|
||||
DisposeAfterUse::Flag disposeAfterUse = DisposeAfterUse::YES);
|
||||
|
||||
Audio::RewindableAudioStream *makeRawZorkStream(const Common::Path &filePath, ZVision *engine);
|
||||
|
||||
} // End of namespace ZVision
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user