Initial commit
This commit is contained in:
89
engines/ultima/nuvie/sound/decoder/adlib_sfx_stream.cpp
Normal file
89
engines/ultima/nuvie/sound/decoder/adlib_sfx_stream.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/* Created by Eric Fry
|
||||
* Copyright (C) 2011 The Nuvie Team
|
||||
*
|
||||
* 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/>.
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/nuvie/core/nuvie_defs.h"
|
||||
#include "ultima/nuvie/sound/adplug/opl_class.h"
|
||||
#include "ultima/nuvie/sound/origin_fx_adib_driver.h"
|
||||
#include "ultima/nuvie/conf/configuration.h"
|
||||
#include "ultima/nuvie/sound/decoder/adlib_sfx_stream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
AdLibSfxStream::AdLibSfxStream(const Configuration *cfg, int rate, uint8 channel, sint8 note, uint8 velocity, uint8 program_number, uint32 d) {
|
||||
interrupt_samples_left = 0;
|
||||
opl = new OplClass(rate, true, true); // 16bit stereo
|
||||
driver = new OriginFXAdLibDriver(cfg, opl);
|
||||
if (program_number != 0xff) {
|
||||
driver->program_change(channel, program_number);
|
||||
}
|
||||
driver->control_mode_change(channel, 0x7, 0x7f);
|
||||
driver->play_note(channel, note, velocity);
|
||||
duration = d;
|
||||
interrupt_rate = (int)(opl->getRate() / 60);
|
||||
total_samples_played = 0;
|
||||
}
|
||||
|
||||
AdLibSfxStream::~AdLibSfxStream() {
|
||||
delete driver;
|
||||
delete opl;
|
||||
}
|
||||
|
||||
int AdLibSfxStream::readBuffer(sint16 *buffer, const int numSamples) {
|
||||
|
||||
//sint32 i, j;
|
||||
short *data = (short *)buffer;
|
||||
|
||||
int len = numSamples / 2;
|
||||
total_samples_played += numSamples;
|
||||
|
||||
if (interrupt_samples_left > 0) {
|
||||
if (interrupt_samples_left > len) {
|
||||
opl->update(data, len);
|
||||
interrupt_samples_left -= len;
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
opl->update(data, interrupt_samples_left);
|
||||
data += interrupt_samples_left * 2;
|
||||
len -= interrupt_samples_left;
|
||||
interrupt_samples_left = 0;
|
||||
}
|
||||
|
||||
for (int i = len; i > 0;) {
|
||||
driver->interrupt_vector();
|
||||
|
||||
int j = interrupt_rate;
|
||||
if (j > i) {
|
||||
interrupt_samples_left = j - i;
|
||||
j = i;
|
||||
}
|
||||
opl->update(data, j);
|
||||
|
||||
data += j * 2;
|
||||
i -= j;
|
||||
}
|
||||
|
||||
|
||||
//driver->play_note(8, 0x40, 0);
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
94
engines/ultima/nuvie/sound/decoder/adlib_sfx_stream.h
Normal file
94
engines/ultima/nuvie/sound/decoder/adlib_sfx_stream.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/* 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 NUVIE_SOUND_MIXER_DECODER_ADLIB_SFX_STREAM_H
|
||||
#define NUVIE_SOUND_MIXER_DECODER_ADLIB_SFX_STREAM_H
|
||||
|
||||
#include "ultima/shared/std/string.h"
|
||||
#include "ultima/nuvie/sound/adplug/opl_class.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
class OriginFXAdLibDriver;
|
||||
class Configuration;
|
||||
|
||||
|
||||
using Std::string;
|
||||
|
||||
class AdLibSfxStream : public Audio::RewindableAudioStream {
|
||||
public:
|
||||
AdLibSfxStream() {
|
||||
opl = nullptr;
|
||||
duration = 0;
|
||||
}
|
||||
|
||||
AdLibSfxStream(const Configuration *cfg, int rate, uint8 channel, sint8 note, uint8 velocity, uint8 program_number, uint32 d);
|
||||
~AdLibSfxStream() override;
|
||||
|
||||
int readBuffer(sint16 *buffer, const int numSamples) override;
|
||||
|
||||
/** Is this a stereo stream? */
|
||||
bool isStereo() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Sample rate of the stream. */
|
||||
int getRate() const override {
|
||||
return opl->getRate();
|
||||
}
|
||||
|
||||
bool rewind() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of data reached? If this returns true, it means that at this
|
||||
* time there is no data available in the stream. However there may be
|
||||
* more data in the future.
|
||||
* This is used by e.g. a rate converter to decide whether to keep on
|
||||
* converting data or stop.
|
||||
*/
|
||||
bool endOfData() const override {
|
||||
if (total_samples_played >= duration) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32 getLengthInMsec() {
|
||||
return (uint32)(duration / (getRate() / 1000.0f));
|
||||
}
|
||||
protected:
|
||||
|
||||
OplClass *opl;
|
||||
OriginFXAdLibDriver *driver;
|
||||
uint32 duration;
|
||||
int interrupt_samples_left;
|
||||
int interrupt_rate;
|
||||
uint32 total_samples_played;
|
||||
};
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
101
engines/ultima/nuvie/sound/decoder/fm_towns_decoder_stream.cpp
Normal file
101
engines/ultima/nuvie/sound/decoder/fm_towns_decoder_stream.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/* Created by Eric Fry
|
||||
* Copyright (C) 2011 The Nuvie Team
|
||||
*
|
||||
* 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/>.
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/nuvie/core/nuvie_defs.h"
|
||||
#include "ultima/nuvie/files/nuvie_io.h"
|
||||
#include "ultima/nuvie/files/u6_lib_n.h"
|
||||
#include "ultima/nuvie/files/u6_lzw.h"
|
||||
#include "ultima/nuvie/sound/decoder/fm_towns_decoder_stream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
inline sint16 convert_sample(uint16 raw_sample);
|
||||
|
||||
FMtownsDecoderStream::FMtownsDecoderStream(unsigned char *buf, uint32 len) {
|
||||
raw_audio_buf = buf;
|
||||
buf_len = len;
|
||||
buf_pos = 0;
|
||||
should_free_raw_data = false;
|
||||
}
|
||||
|
||||
FMtownsDecoderStream::FMtownsDecoderStream(const Common::Path &filename, uint16 sample_num, bool isCompressed) {
|
||||
unsigned char *item_data;
|
||||
uint32 decomp_size;
|
||||
U6Lib_n sam_file;
|
||||
U6Lzw lzw;
|
||||
|
||||
sam_file.open(filename, 4);
|
||||
|
||||
item_data = sam_file.get_item(sample_num, nullptr);
|
||||
|
||||
if (isCompressed) {
|
||||
raw_audio_buf = lzw.decompress_buffer(item_data, sam_file.get_item_size(sample_num), decomp_size);
|
||||
|
||||
free(item_data);
|
||||
|
||||
buf_len = decomp_size;
|
||||
} else {
|
||||
raw_audio_buf = item_data;
|
||||
buf_len = sam_file.get_item_size(sample_num);
|
||||
}
|
||||
|
||||
buf_pos = 0;
|
||||
should_free_raw_data = true;
|
||||
}
|
||||
|
||||
FMtownsDecoderStream::~FMtownsDecoderStream() {
|
||||
if (raw_audio_buf && should_free_raw_data)
|
||||
free(raw_audio_buf);
|
||||
}
|
||||
|
||||
uint32 FMtownsDecoderStream::getLengthInMsec() {
|
||||
return (uint32)(buf_len / (getRate() / 1000.0f));
|
||||
}
|
||||
|
||||
int FMtownsDecoderStream::readBuffer(sint16 *buffer, const int numSamples) {
|
||||
int j = 0;
|
||||
uint32 i = buf_pos;
|
||||
//DEBUG(0,LEVEL_INFORMATIONAL, "numSamples = %d. buf_pos = %d, buf_len = %d\n", numSamples, buf_pos, buf_len);
|
||||
|
||||
for (; j < numSamples && i < buf_len;) {
|
||||
buffer[j] = convertSample(static_cast<uint16>(raw_audio_buf[i]));
|
||||
j++;
|
||||
i++;
|
||||
}
|
||||
|
||||
buf_pos += j;
|
||||
//DEBUG(0,LEVEL_INFORMATIONAL, "read %d samples.\n", j);
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
inline sint16 FMtownsDecoderStream::convertSample(uint16 rawSample) const {
|
||||
sint16 sample;
|
||||
|
||||
if (rawSample & 128)
|
||||
sample = ((sint16)(ABS(128 - rawSample) * 256) ^ 0xffff) + 1;
|
||||
else
|
||||
sample = rawSample * 256;
|
||||
|
||||
return sample;
|
||||
}
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
86
engines/ultima/nuvie/sound/decoder/fm_towns_decoder_stream.h
Normal file
86
engines/ultima/nuvie/sound/decoder/fm_towns_decoder_stream.h
Normal file
@@ -0,0 +1,86 @@
|
||||
#ifndef __FMtownsDecoderStream_h__
|
||||
#define __FMtownsDecoderStream_h__
|
||||
/* Created by Eric Fry
|
||||
* Copyright (C) 2011 The Nuvie Team
|
||||
*
|
||||
* 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/>.
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/nuvie/sound/decoder/random_collection_audio_stream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
class U6Lib_n;
|
||||
class U6Lzw;
|
||||
class NuvieIOBuffer;
|
||||
|
||||
class FMtownsDecoderStream : public Audio::RewindableAudioStream {
|
||||
public:
|
||||
FMtownsDecoderStream() {
|
||||
should_free_raw_data = false;
|
||||
raw_audio_buf = nullptr;
|
||||
}
|
||||
|
||||
FMtownsDecoderStream(unsigned char *buf, uint32 len);
|
||||
FMtownsDecoderStream(const Common::Path &filename, uint16 sample_num, bool isCompressed = true);
|
||||
~FMtownsDecoderStream() override;
|
||||
|
||||
uint32 getLengthInMsec();
|
||||
|
||||
int readBuffer(sint16 *buffer, const int numSamples) override;
|
||||
|
||||
/** Is this a stereo stream? */
|
||||
bool isStereo() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Sample rate of the stream. */
|
||||
int getRate() const override {
|
||||
return 14700;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of data reached? If this returns true, it means that at this
|
||||
* time there is no data available in the stream. However there may be
|
||||
* more data in the future.
|
||||
* This is used by e.g. a rate converter to decide whether to keep on
|
||||
* converting data or stop.
|
||||
*/
|
||||
bool endOfData() const override {
|
||||
return buf_pos >= buf_len;
|
||||
}
|
||||
|
||||
bool rewind() override {
|
||||
buf_pos = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
bool should_free_raw_data;
|
||||
unsigned char *raw_audio_buf;
|
||||
uint32 buf_len;
|
||||
uint32 buf_pos;
|
||||
|
||||
private:
|
||||
inline sint16 convertSample(uint16 rawSample) const;
|
||||
};
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
150
engines/ultima/nuvie/sound/decoder/pc_speaker.cpp
Normal file
150
engines/ultima/nuvie/sound/decoder/pc_speaker.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
* PCSpeaker.cpp
|
||||
* Nuvie
|
||||
*
|
||||
* Created by Eric Fry on Sun Feb 13 2011.
|
||||
* Copyright (c) 2011. All rights reserved.
|
||||
*
|
||||
* 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/>.
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/nuvie/core/nuvie_defs.h"
|
||||
#include "ultima/nuvie/sound/decoder/pc_speaker.h"
|
||||
#include "audio/mixer.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
#define SPKR_VOLUME 5000
|
||||
//#define SPKR_SHIFT 8
|
||||
#define SPKR_SPEED (float)((SPKR_VOLUME*2)/0.070f)
|
||||
|
||||
#define PIT_TICK_RATE 1193182
|
||||
|
||||
void PCSpeaker::SetOn() {
|
||||
|
||||
wav_length = 0;
|
||||
/*
|
||||
//PCSPEAKER_SetType(3);
|
||||
dataFile.open("/Users/efry/pcspeaker.wav");
|
||||
dataFile.writeBuf((const unsigned char*)"RIFF", 4);
|
||||
dataFile.write4(36 + wav_length * 2); //length of RIFF chunk
|
||||
dataFile.writeBuf((const unsigned char*)"WAVE", 4);
|
||||
dataFile.writeBuf((const unsigned char*)"fmt ", 4);
|
||||
dataFile.write4(16); // length of format chunk
|
||||
dataFile.write2(1); // PCM encoding
|
||||
dataFile.write2(1); // mono
|
||||
dataFile.write4(rate); // sample frequency 16KHz
|
||||
dataFile.write4(rate * 2); // sample rate
|
||||
dataFile.write2(2); // BlockAlign
|
||||
dataFile.write2(16); // Bits per sample
|
||||
|
||||
dataFile.writeBuf((const unsigned char*)"data", 4);
|
||||
dataFile.write4(wav_length * 2); // length of data chunk
|
||||
*/
|
||||
time_left = 0.0;
|
||||
want_vol = -SPKR_VOLUME;
|
||||
}
|
||||
|
||||
void PCSpeaker::SetOff() {
|
||||
want_vol = 0;
|
||||
time_left = 0.0;
|
||||
/*
|
||||
//PCSPEAKER_SetType(0);
|
||||
dataFile.seek(4);
|
||||
dataFile.write4(36 + wav_length * 2); //length of RIFF chunk
|
||||
dataFile.seek(40);
|
||||
dataFile.write4(wav_length * 2); // length of data chunk
|
||||
|
||||
dataFile.close();
|
||||
*/
|
||||
}
|
||||
|
||||
void PCSpeaker::SetFrequency(uint16 freq, float offset) {
|
||||
//PCSPEAKER_SetCounter(PIT_TICK_RATE/freq, PIT_MODE_3_SQUAREWAVE);
|
||||
|
||||
if (frequency == freq)
|
||||
return;
|
||||
|
||||
frequency = freq;
|
||||
osc_length = rate / frequency;
|
||||
|
||||
osc_samples = 0;
|
||||
half_period = ((float)rate / (float)frequency) / 2;
|
||||
//want_vol = SPKR_VOLUME;
|
||||
|
||||
//DEBUG(0, LEVEL_DEBUGGING, "new_freq = %d half_period = %f time_left = %f", freq, half_period, time_left);
|
||||
|
||||
//time_left = offset; //half_period;
|
||||
|
||||
}
|
||||
|
||||
PCSpeaker::PCSpeaker(uint32 mixer_rate) : rate(mixer_rate), cur_vol(0.0f), want_vol(0.0f),
|
||||
frequency(0), half_period(0.0f), time_left(0.0f), osc_length(0),
|
||||
osc_samples(0), wav_length(0) {
|
||||
}
|
||||
|
||||
|
||||
void PCSpeaker::PCSPEAKER_CallBack(sint16 *stream, const uint32 len) {
|
||||
uint32 i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
//float new_time_left = time_left - 1;
|
||||
|
||||
if (cur_vol != want_vol) {
|
||||
if (time_left < 1.0f)
|
||||
cur_vol = cur_vol + ((want_vol * 8.3502) * time_left) / 2;
|
||||
else
|
||||
cur_vol = cur_vol + ((want_vol * 8.3502) / 2);
|
||||
|
||||
if (cur_vol > SPKR_VOLUME || cur_vol < -SPKR_VOLUME) { //limit the volume to our max speaker range.
|
||||
cur_vol = want_vol;
|
||||
}
|
||||
}
|
||||
|
||||
if (time_left <= 1.0f) { //we change wave direction in this time slice.
|
||||
//change wave edge.
|
||||
if (want_vol < 0)
|
||||
want_vol = SPKR_VOLUME;
|
||||
else
|
||||
want_vol = -SPKR_VOLUME;
|
||||
|
||||
float remainder = (1.0f - time_left);
|
||||
|
||||
if (remainder != 0.0f) { //calculate new current volume position
|
||||
cur_vol = cur_vol + ((want_vol * 8.3502) * remainder) / 2;
|
||||
|
||||
if (cur_vol > SPKR_VOLUME || cur_vol < -SPKR_VOLUME) { //limit the volume to our max speaker range.
|
||||
cur_vol = want_vol;
|
||||
}
|
||||
}
|
||||
|
||||
time_left = half_period - remainder;
|
||||
//DEBUG(0, LEVEL_DEBUGGING, "remainder = %f, time_left = %f\n", remainder, time_left);
|
||||
} else
|
||||
time_left = time_left - 1.0f;
|
||||
|
||||
stream[i] = (sint16)cur_vol;
|
||||
//dataFile.write2(stream[i]);
|
||||
//wav_length++;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
|
||||
62
engines/ultima/nuvie/sound/decoder/pc_speaker.h
Normal file
62
engines/ultima/nuvie/sound/decoder/pc_speaker.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/* 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 NUVIE_SOUND_MIXER_DECODER_PC_SPEAKER_H
|
||||
#define NUVIE_SOUND_MIXER_DECODER_PC_SPEAKER_H
|
||||
|
||||
#include "ultima/nuvie/files/nuvie_io_file.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
#define SPKR_OUTPUT_RATE 22050 //11025 //FIXME may need to fiddle with this.
|
||||
|
||||
class PCSpeaker {
|
||||
private:
|
||||
uint32 rate;
|
||||
uint16 frequency;
|
||||
float half_period;
|
||||
float cur_vol;
|
||||
float want_vol;
|
||||
float time_left;
|
||||
|
||||
uint32 osc_length;
|
||||
uint32 osc_samples;
|
||||
|
||||
private:
|
||||
|
||||
NuvieIOFileWrite dataFile;
|
||||
uint32 wav_length;
|
||||
|
||||
public:
|
||||
PCSpeaker(uint32 mixer_rate);
|
||||
~PCSpeaker() { }
|
||||
void SetOn();
|
||||
void SetOff();
|
||||
void SetFrequency(uint16 freq, float offset = 0.0f);
|
||||
|
||||
void PCSPEAKER_CallBack(sint16 *stream, const uint32 len);
|
||||
};
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
427
engines/ultima/nuvie/sound/decoder/pc_speaker_stream.cpp
Normal file
427
engines/ultima/nuvie/sound/decoder/pc_speaker_stream.cpp
Normal file
@@ -0,0 +1,427 @@
|
||||
/* Created by Eric Fry
|
||||
* Copyright (C) 2011 The Nuvie Team
|
||||
*
|
||||
* 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/>.
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/nuvie/core/nuvie_defs.h"
|
||||
#include "ultima/nuvie/sound/decoder/pc_speaker_stream.h"
|
||||
#include "ultima/nuvie/core/game.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
PCSpeakerFreqStream::PCSpeakerFreqStream(uint freq, uint16 d) {
|
||||
frequency = freq;
|
||||
|
||||
duration = d * (SPKR_OUTPUT_RATE / 1255);
|
||||
if (freq != 0) {
|
||||
pcspkr->SetOn();
|
||||
pcspkr->SetFrequency(frequency);
|
||||
}
|
||||
|
||||
total_samples_played = 0;
|
||||
}
|
||||
|
||||
|
||||
PCSpeakerFreqStream::~PCSpeakerFreqStream() {
|
||||
|
||||
}
|
||||
|
||||
uint32 PCSpeakerFreqStream::getLengthInMsec() {
|
||||
return (uint32)(duration / (getRate() / 1000.0f));
|
||||
}
|
||||
|
||||
int PCSpeakerFreqStream::readBuffer(sint16 *buffer, const int numSamples) {
|
||||
uint32 samples = (uint32)numSamples;
|
||||
|
||||
if (total_samples_played >= duration)
|
||||
return 0;
|
||||
|
||||
if (total_samples_played + samples > duration)
|
||||
samples = duration - total_samples_played;
|
||||
|
||||
if (frequency != 0)
|
||||
pcspkr->PCSPEAKER_CallBack(buffer, samples);
|
||||
else
|
||||
memset(buffer, 0, sizeof(sint16)*numSamples);
|
||||
|
||||
total_samples_played += samples;
|
||||
|
||||
if (total_samples_played >= duration) {
|
||||
finished = true;
|
||||
pcspkr->SetOff();
|
||||
}
|
||||
|
||||
return samples;
|
||||
}
|
||||
|
||||
//******** PCSpeakerSweepFreqStream
|
||||
|
||||
PCSpeakerSweepFreqStream::PCSpeakerSweepFreqStream(uint start, uint end, uint16 d, uint16 s) {
|
||||
start_freq = start;
|
||||
finish_freq = end;
|
||||
cur_freq = start_freq;
|
||||
|
||||
num_steps = d / s;
|
||||
freq_step = ((finish_freq - start_freq) * s) / d;
|
||||
stepping = s;
|
||||
duration = d * (SPKR_OUTPUT_RATE / 1255);
|
||||
samples_per_step = (float)s * (SPKR_OUTPUT_RATE * 0.000879533f); //(2 * (uint32)(SPKR_OUTPUT_RATE / start_freq)); //duration / num_steps;
|
||||
sample_pos = 0.0f;
|
||||
pcspkr->SetOn();
|
||||
pcspkr->SetFrequency(start_freq);
|
||||
|
||||
|
||||
total_samples_played = 0;
|
||||
cur_step = 0;
|
||||
DEBUG(0, LEVEL_DEBUGGING, "num_steps = %d freq_step = %d samples_per_step = %f\n", num_steps, freq_step, samples_per_step);
|
||||
}
|
||||
|
||||
|
||||
PCSpeakerSweepFreqStream::~PCSpeakerSweepFreqStream() {
|
||||
|
||||
}
|
||||
|
||||
uint32 PCSpeakerSweepFreqStream::getLengthInMsec() {
|
||||
return (uint32)((num_steps * samples_per_step) / (getRate() / 1000.0f));
|
||||
}
|
||||
|
||||
int PCSpeakerSweepFreqStream::readBuffer(sint16 *buffer, const int numSamples) {
|
||||
uint32 samples = (uint32)numSamples;
|
||||
uint32 i;
|
||||
//if(total_samples_played >= duration)
|
||||
// return 0;
|
||||
|
||||
//if(total_samples_played + samples > duration)
|
||||
// samples = duration - total_samples_played;
|
||||
|
||||
for (i = 0; i < samples && cur_step < num_steps;) {
|
||||
//DEBUG(0, LEVEL_DEBUGGING, "sample_pos = %f\n", sample_pos);
|
||||
float n = samples_per_step - sample_pos;
|
||||
if ((float)i + n > (float)samples)
|
||||
n = (float)(samples - i);
|
||||
|
||||
float remainder = n - floor(n);
|
||||
n = floor(n);
|
||||
pcspkr->PCSPEAKER_CallBack(&buffer[i], (uint32)n);
|
||||
sample_pos += n;
|
||||
|
||||
i += (uint32)n;
|
||||
//DEBUG(0, LEVEL_DEBUGGING, "sample_pos = %f remainder = %f\n", sample_pos, remainder);
|
||||
if (sample_pos + remainder >= samples_per_step) {
|
||||
cur_freq += freq_step;
|
||||
|
||||
pcspkr->SetFrequency(cur_freq, remainder);
|
||||
|
||||
if (remainder != 0.0f) {
|
||||
sample_pos = 1.0f - remainder;
|
||||
pcspkr->PCSPEAKER_CallBack(&buffer[i], 1);
|
||||
i++;
|
||||
} else {
|
||||
sample_pos = 0;
|
||||
}
|
||||
|
||||
cur_step++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
total_samples_played += i;
|
||||
|
||||
if (cur_step >= num_steps) { //total_samples_played >= duration)
|
||||
DEBUG(0, LEVEL_DEBUGGING, "total_samples_played = %d cur_freq = %d\n", total_samples_played, cur_freq);
|
||||
finished = true;
|
||||
pcspkr->SetOff();
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
//**************** PCSpeakerRandomStream
|
||||
|
||||
PCSpeakerRandomStream::PCSpeakerRandomStream(uint freq, uint16 d, uint16 s)
|
||||
: rand_value(0x7664), base_val(freq), duration(0), stepping(0),
|
||||
cur_step(0), sample_pos(0), num_steps(d / s),
|
||||
samples_per_step(s * (SPKR_OUTPUT_RATE / 20 / 800)),
|
||||
total_samples_played(0) {
|
||||
/*
|
||||
frequency = freq;
|
||||
|
||||
duration = d * (SPKR_OUTPUT_RATE / 1255);
|
||||
|
||||
pcspkr->SetFrequency(frequency);
|
||||
pcspkr->SetOn();
|
||||
|
||||
total_samples_played = 0;
|
||||
*/
|
||||
|
||||
pcspkr->SetOn();
|
||||
pcspkr->SetFrequency(getNextFreqValue());
|
||||
|
||||
DEBUG(0, LEVEL_DEBUGGING, "num_steps = %d samples_per_step = %d\n", num_steps, samples_per_step);
|
||||
|
||||
}
|
||||
|
||||
|
||||
PCSpeakerRandomStream::~PCSpeakerRandomStream() {
|
||||
|
||||
}
|
||||
|
||||
uint32 PCSpeakerRandomStream::getLengthInMsec() {
|
||||
return (uint32)((num_steps * samples_per_step) / (getRate() / 1000.0f));
|
||||
}
|
||||
|
||||
uint16 PCSpeakerRandomStream::getNextFreqValue() {
|
||||
rand_value += 0x9248;
|
||||
rand_value = rand_value & 0xffff; //clamp_max(rand_value, 65535);
|
||||
uint16 bits = rand_value & 0x7;
|
||||
rand_value = (rand_value >> 3) + (bits << 13); //rotate rand_value right (ror) by 3 bits
|
||||
rand_value = rand_value ^ 0x9248;
|
||||
rand_value += 0x11;
|
||||
rand_value = rand_value & 0xffff; //clamp_max(rand_value, 65535);
|
||||
|
||||
uint16 freq = base_val - 0x64 + 1;
|
||||
uint16 tmp = rand_value;
|
||||
freq = tmp - floor(tmp / freq) * freq;
|
||||
freq += 0x64;
|
||||
|
||||
return freq;
|
||||
}
|
||||
|
||||
int PCSpeakerRandomStream::readBuffer(sint16 *buffer, const int numSamples) {
|
||||
uint32 samples = (uint32)numSamples;
|
||||
uint32 s = 0;
|
||||
//if(total_samples_played >= duration)
|
||||
// return 0;
|
||||
|
||||
//if(total_samples_played + samples > duration)
|
||||
// samples = duration - total_samples_played;
|
||||
|
||||
for (uint32 i = 0; i < samples && cur_step <= num_steps;) {
|
||||
uint32 n = samples_per_step - sample_pos;
|
||||
if (i + n > samples)
|
||||
n = samples - i;
|
||||
|
||||
pcspkr->PCSPEAKER_CallBack(&buffer[i], n);
|
||||
sample_pos += n;
|
||||
i += n;
|
||||
// DEBUG(0, LEVEL_DEBUGGING, "n = %d\n", n);
|
||||
if (sample_pos >= samples_per_step) {
|
||||
//DEBUG(0, LEVEL_DEBUGGING, "samples_per_step = %d period = %d\n", samples_per_step, period);
|
||||
pcspkr->SetFrequency(getNextFreqValue());
|
||||
sample_pos = 0;
|
||||
cur_step++;
|
||||
}
|
||||
|
||||
s += n;
|
||||
|
||||
}
|
||||
|
||||
total_samples_played += s;
|
||||
|
||||
if (cur_step >= num_steps) { //total_samples_played >= duration)
|
||||
DEBUG(0, LEVEL_DEBUGGING, "total_samples_played = %d\n", total_samples_played);
|
||||
finished = true;
|
||||
pcspkr->SetOff();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
//**************** PCSpeakerStutterStream
|
||||
|
||||
PCSpeakerStutterStream::PCSpeakerStutterStream(sint16 a0, uint16 a2, uint16 a4, uint16 a6, uint16 a8) {
|
||||
arg_0 = a0;
|
||||
arg_2 = a2;
|
||||
arg_4 = a4;
|
||||
arg_6 = a6;
|
||||
arg_8 = a8;
|
||||
|
||||
cx = arg_4;
|
||||
dx = 0;
|
||||
|
||||
pcspkr->SetOn();
|
||||
pcspkr->SetFrequency(22096);
|
||||
|
||||
delay = (SPKR_OUTPUT_RATE / 22050) * arg_6; //FIXME this needs to be refined.
|
||||
delay_remaining = 0;
|
||||
|
||||
//samples_per_step = s * (SPKR_OUTPUT_RATE / 20 / 800); //1255);
|
||||
//total_samples_played = 0;
|
||||
//DEBUG(0, LEVEL_DEBUGGING, "num_steps = %d samples_per_step = %d\n", num_steps, samples_per_step);
|
||||
|
||||
}
|
||||
|
||||
|
||||
PCSpeakerStutterStream::~PCSpeakerStutterStream() {
|
||||
|
||||
}
|
||||
|
||||
uint32 PCSpeakerStutterStream::getLengthInMsec() {
|
||||
return (uint32)((arg_4 * delay) / (getRate() / 1000.0f));
|
||||
}
|
||||
|
||||
|
||||
int PCSpeakerStutterStream::readBuffer(sint16 *buffer, const int numSamples) {
|
||||
uint32 s = 0;
|
||||
|
||||
for (; cx > 0 && s < (uint32)numSamples; cx--) {
|
||||
uint32 n = (uint32)floor(delay_remaining);
|
||||
if (n > 0) {
|
||||
pcspkr->PCSPEAKER_CallBack(&buffer[s], n);
|
||||
delay_remaining -= n;
|
||||
s += n;
|
||||
}
|
||||
|
||||
dx = (dx + arg_8) & 0xffff;
|
||||
|
||||
if (dx > arg_2) {
|
||||
pcspkr->SetOn();
|
||||
} else {
|
||||
pcspkr->SetOff();
|
||||
}
|
||||
|
||||
arg_2 += arg_0;
|
||||
/*
|
||||
for(int i = arg_6; i > 0 ; i--)
|
||||
{
|
||||
for(int j = counter;j > 0;)
|
||||
{
|
||||
j--;
|
||||
}
|
||||
}
|
||||
*/
|
||||
n = (uint32)floor(delay);
|
||||
if (s + n > (uint32)numSamples)
|
||||
n = numSamples - s;
|
||||
|
||||
pcspkr->PCSPEAKER_CallBack(&buffer[s], n);
|
||||
delay_remaining = delay - n;
|
||||
s += n;
|
||||
}
|
||||
|
||||
if (cx <= 0) {
|
||||
//DEBUG(0, LEVEL_DEBUGGING, "total_samples_played = %d\n", total_samples_played);
|
||||
finished = true;
|
||||
pcspkr->SetOff();
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
Audio::AudioStream *makePCSpeakerSlugDissolveSfxStream(uint /*rate*/) {
|
||||
Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(SPKR_OUTPUT_RATE, false);
|
||||
for (uint16 i = 0; i < 20; i++) {
|
||||
stream->queueAudioStream(new PCSpeakerRandomStream((NUVIE_RAND() % 0x1068) + 0x258, 0x15e, 1), DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
Audio::AudioStream *makePCSpeakerGlassSfxStream(uint /*rate*/) {
|
||||
Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(SPKR_OUTPUT_RATE, false);
|
||||
for (uint16 i = 0x7d0; i < 0x4e20; i += 0x3e8) {
|
||||
stream->queueAudioStream(new PCSpeakerRandomStream(i, 0x78, 0x28), DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
|
||||
Audio::AudioStream *makePCSpeakerMagicCastingP1SfxStream(uint /*rate*/, uint8 magic_circle) {
|
||||
//Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(rate, false);
|
||||
|
||||
return new PCSpeakerRandomStream(0x2bc, 0x640 * magic_circle + 0x1f40, 0x320);
|
||||
|
||||
//return stream;
|
||||
}
|
||||
|
||||
Audio::AudioStream *makePCSpeakerMagicCastingP2SfxStream(uint /*rate*/, uint8 magic_circle) {
|
||||
Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(SPKR_OUTPUT_RATE, false);
|
||||
|
||||
const sint16 word_30188[] = {3, 2, 2, 2, 1, 1, 1, 1, 1};
|
||||
|
||||
const uint16 word_30164[] = {0xA8C, 0xBB8, 0x3E8, 0x64, 0x1388, 0xFA0, 0x9C4, 0x3E8, 1};
|
||||
const uint16 word_30176[] = {0x7FBC, 0x7918, 0x9088, 0xAFC8, 0x7918, 0x84D0, 0x8E94, 0x9858, 0xA410};
|
||||
|
||||
const uint16 word_30152[] = {0x226A, 0x1E96, 0x1B94, 0x1996, 0x173E, 0x15C2, 0x143C, 0x12D4, 0x1180};
|
||||
|
||||
stream->queueAudioStream(new PCSpeakerStutterStream(word_30188[magic_circle], word_30164[magic_circle], (magic_circle * 0xfa0) + 0x2710, 1, word_30152[magic_circle]));
|
||||
stream->queueAudioStream(new PCSpeakerStutterStream(-word_30188[magic_circle], word_30176[magic_circle], (magic_circle * 0xfa0) + 0x2710, 1, word_30152[magic_circle]));
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
Audio::AudioStream *makePCSpeakerAvatarDeathSfxStream(uint /*rate*/) {
|
||||
const uint16 avatar_death_tune[] = {0x12C, 0x119, 0x12C, 0xFA, 0x119, 0xDE, 0xFA, 0xFA};
|
||||
|
||||
Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(SPKR_OUTPUT_RATE, false);
|
||||
for (uint8 i = 0; i < 8; i++) {
|
||||
stream->queueAudioStream(new PCSpeakerStutterStream(3, 1, 0x4e20, 1, avatar_death_tune[i]));
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
Audio::AudioStream *makePCSpeakerKalLorSfxStream(uint /*rate*/) {
|
||||
Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(SPKR_OUTPUT_RATE, false);
|
||||
for (uint8 i = 0; i < 0x32; i++) {
|
||||
stream->queueAudioStream(new PCSpeakerStutterStream((0x32 - i) << 2, 0x2710 - (i << 6), 0x3e8, 1, (i << 4) + 0x320));
|
||||
}
|
||||
|
||||
stream->queueAudioStream(new PCSpeakerStutterStream(8, 0, 0x1f40, 1, 0x640));
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
Audio::AudioStream *makePCSpeakerHailStoneSfxStream(uint /*rate*/) {
|
||||
//FIXME This doesn't sound right. It should probably use a single
|
||||
// pcspkr object. The original also plays the hailstones
|
||||
// individually, not all at once like we do. :(
|
||||
Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(SPKR_OUTPUT_RATE, false);
|
||||
|
||||
for (uint16 i = 0; i < 0x28; i++) {
|
||||
stream->queueAudioStream(new PCSpeakerFreqStream((NUVIE_RAND() % 0x28) + 0x20, 8), DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
/* The original logic looks something like this. But this doesn't sound right.
|
||||
uint16 base_freq = (NUVIE_RAND()%0x64)+0x190;
|
||||
for(uint16 i=0;i<0x28;i++)
|
||||
{
|
||||
if(NUVIE_RAND()%7==0)
|
||||
stream->queueAudioStream(new PCSpeakerFreqStream(base_freq + (NUVIE_RAND()%0x28), 8), DisposeAfterUse::YES);
|
||||
else
|
||||
stream->queueAudioStream(new PCSpeakerFreqStream(0, 8), DisposeAfterUse::YES);
|
||||
}
|
||||
*/
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
Audio::AudioStream *makePCSpeakerEarthQuakeSfxStream(uint /*rate*/) {
|
||||
Audio::QueuingAudioStream *stream = Audio::makeQueuingAudioStream(SPKR_OUTPUT_RATE, false);
|
||||
|
||||
for (uint16 i = 0; i < 0x28; i++) {
|
||||
stream->queueAudioStream(new PCSpeakerFreqStream((NUVIE_RAND() % 0xb5) + 0x13, 8), DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
186
engines/ultima/nuvie/sound/decoder/pc_speaker_stream.h
Normal file
186
engines/ultima/nuvie/sound/decoder/pc_speaker_stream.h
Normal file
@@ -0,0 +1,186 @@
|
||||
/* 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 NUVIE_SOUND_MIXER_DECODER_PC_SPEAKER_STREAM_H
|
||||
#define NUVIE_SOUND_MIXER_DECODER_PC_SPEAKER_STREAM_H
|
||||
|
||||
#include "ultima/shared/std/string.h"
|
||||
#include "ultima/nuvie/sound/decoder/pc_speaker.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
class PCSpeakerStream : public Audio::RewindableAudioStream {
|
||||
public:
|
||||
PCSpeakerStream() {
|
||||
pcspkr = new PCSpeaker(SPKR_OUTPUT_RATE);
|
||||
finished = false;
|
||||
}
|
||||
|
||||
~PCSpeakerStream() override {
|
||||
delete pcspkr;
|
||||
}
|
||||
|
||||
/** Is this a stereo stream? */
|
||||
bool isStereo() const override {
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Sample rate of the stream. */
|
||||
int getRate() const override {
|
||||
return SPKR_OUTPUT_RATE;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of data reached? If this returns true, it means that at this
|
||||
* time there is no data available in the stream. However there may be
|
||||
* more data in the future.
|
||||
* This is used by e.g. a rate converter to decide whether to keep on
|
||||
* converting data or stop.
|
||||
*/
|
||||
bool endOfData() const override {
|
||||
return finished;
|
||||
}
|
||||
|
||||
bool rewind() override {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
PCSpeaker *pcspkr;
|
||||
bool finished;
|
||||
};
|
||||
|
||||
|
||||
class PCSpeakerFreqStream : public PCSpeakerStream {
|
||||
public:
|
||||
PCSpeakerFreqStream() {
|
||||
|
||||
}
|
||||
|
||||
PCSpeakerFreqStream(uint start, uint16 d);
|
||||
~PCSpeakerFreqStream() override;
|
||||
uint32 getLengthInMsec();
|
||||
int readBuffer(sint16 *buffer, const int numSamples) override;
|
||||
|
||||
protected:
|
||||
|
||||
uint32 frequency;
|
||||
uint32 duration;
|
||||
uint32 total_samples_played;
|
||||
|
||||
};
|
||||
|
||||
class PCSpeakerSweepFreqStream : public PCSpeakerStream {
|
||||
public:
|
||||
PCSpeakerSweepFreqStream() {
|
||||
|
||||
}
|
||||
|
||||
PCSpeakerSweepFreqStream(uint start, uint end, uint16 d, uint16 s);
|
||||
~PCSpeakerSweepFreqStream() override;
|
||||
uint32 getLengthInMsec();
|
||||
int readBuffer(sint16 *buffer, const int numSamples) override;
|
||||
|
||||
protected:
|
||||
|
||||
uint32 start_freq;
|
||||
uint32 finish_freq;
|
||||
uint32 cur_freq;
|
||||
uint16 duration;
|
||||
uint16 stepping;
|
||||
|
||||
uint32 freq_step;
|
||||
float samples_per_step;
|
||||
float sample_pos;
|
||||
uint32 total_samples_played;
|
||||
uint32 num_steps;
|
||||
uint32 cur_step;
|
||||
|
||||
};
|
||||
|
||||
class PCSpeakerRandomStream : public PCSpeakerStream {
|
||||
public:
|
||||
PCSpeakerRandomStream() {
|
||||
|
||||
}
|
||||
|
||||
PCSpeakerRandomStream(uint start, uint16 d, uint16 s);
|
||||
~PCSpeakerRandomStream() override;
|
||||
uint32 getLengthInMsec();
|
||||
uint16 getNextFreqValue();
|
||||
int readBuffer(sint16 *buffer, const int numSamples) override;
|
||||
|
||||
protected:
|
||||
|
||||
uint16 base_val;
|
||||
uint16 duration;
|
||||
uint16 stepping;
|
||||
|
||||
uint32 rand_value;
|
||||
uint32 sample_pos;
|
||||
uint32 total_samples_played;
|
||||
uint32 samples_per_step;
|
||||
uint32 num_steps;
|
||||
uint32 cur_step;
|
||||
|
||||
};
|
||||
|
||||
class PCSpeakerStutterStream : public PCSpeakerStream {
|
||||
public:
|
||||
PCSpeakerStutterStream() {
|
||||
|
||||
}
|
||||
|
||||
PCSpeakerStutterStream(sint16 a0, uint16 a2, uint16 a4, uint16 a6, uint16 a8);
|
||||
~PCSpeakerStutterStream() override;
|
||||
uint32 getLengthInMsec();
|
||||
int readBuffer(sint16 *buffer, const int numSamples) override;
|
||||
|
||||
protected:
|
||||
|
||||
sint16 arg_0;
|
||||
uint16 arg_2;
|
||||
uint16 arg_4;
|
||||
uint16 arg_6;
|
||||
uint16 arg_8;
|
||||
|
||||
uint16 dx;
|
||||
uint16 cx;
|
||||
float delay;
|
||||
float delay_remaining;
|
||||
|
||||
};
|
||||
|
||||
Audio::AudioStream *makePCSpeakerSlugDissolveSfxStream(uint rate);
|
||||
Audio::AudioStream *makePCSpeakerGlassSfxStream(uint rate);
|
||||
Audio::AudioStream *makePCSpeakerMagicCastingP1SfxStream(uint rate, uint8 magic_circle);
|
||||
Audio::AudioStream *makePCSpeakerMagicCastingP2SfxStream(uint rate, uint8 magic_circle);
|
||||
Audio::AudioStream *makePCSpeakerAvatarDeathSfxStream(uint rate);
|
||||
Audio::AudioStream *makePCSpeakerKalLorSfxStream(uint rate);
|
||||
Audio::AudioStream *makePCSpeakerHailStoneSfxStream(uint rate);
|
||||
Audio::AudioStream *makePCSpeakerEarthQuakeSfxStream(uint rate);
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,134 @@
|
||||
/* 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 "ultima/nuvie/sound/decoder/random_collection_audio_stream.h"
|
||||
#include "ultima/nuvie/core/game.h"
|
||||
#include "audio/audiostream.h"
|
||||
#include "common/mutex.h"
|
||||
#include "audio/mixer.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
namespace U6Audio {
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark --- random collection audio stream ---
|
||||
#pragma mark -
|
||||
|
||||
class RandomCollectionAudioStreamImpl : public RandomCollectionAudioStream {
|
||||
private:
|
||||
/**
|
||||
* The sampling rate of this audio stream.
|
||||
*/
|
||||
const int _rate;
|
||||
|
||||
/**
|
||||
* Whether this audio stream is mono (=false) or stereo (=true).
|
||||
*/
|
||||
const int _stereo;
|
||||
|
||||
/**
|
||||
* This flag is set by the finish() method only. See there for more details.
|
||||
*/
|
||||
bool _finished;
|
||||
|
||||
/**
|
||||
* An array of audio streams.
|
||||
*/
|
||||
Std::vector<Audio::RewindableAudioStream *> _streams;
|
||||
|
||||
DisposeAfterUse::Flag _disposeAfterUse;
|
||||
|
||||
Audio::RewindableAudioStream *_currentStream;
|
||||
public:
|
||||
RandomCollectionAudioStreamImpl(int rate, bool stereo, const Std::vector<Audio::RewindableAudioStream *> &streams, DisposeAfterUse::Flag disposeAfterUse)
|
||||
: _rate(rate), _stereo(stereo), _finished(false), _streams(streams), _disposeAfterUse(disposeAfterUse) {
|
||||
if (_streams.size() > 0)
|
||||
_currentStream = _streams[NUVIE_RAND() % _streams.size()];
|
||||
else
|
||||
_currentStream = nullptr;
|
||||
}
|
||||
|
||||
~RandomCollectionAudioStreamImpl() override;
|
||||
|
||||
// Implement the AudioStream API
|
||||
int readBuffer(int16 *buffer, const int numSamples) override;
|
||||
bool isStereo() const override {
|
||||
return _stereo;
|
||||
}
|
||||
int getRate() const override {
|
||||
return _rate;
|
||||
}
|
||||
bool endOfData() const override {
|
||||
return false;
|
||||
}
|
||||
bool endOfStream() const override {
|
||||
return _finished;
|
||||
}
|
||||
|
||||
void finish() override {
|
||||
_finished = true;
|
||||
}
|
||||
};
|
||||
|
||||
RandomCollectionAudioStreamImpl::~RandomCollectionAudioStreamImpl() {
|
||||
if (_disposeAfterUse == DisposeAfterUse::YES) {
|
||||
while (!_streams.empty()) {
|
||||
delete _streams.back();
|
||||
_streams.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int RandomCollectionAudioStreamImpl::readBuffer(int16 *buffer, const int numSamples) {
|
||||
int samplesDecoded = 0;
|
||||
|
||||
if (_currentStream) {
|
||||
while (samplesDecoded < numSamples) {
|
||||
samplesDecoded += _currentStream->readBuffer(buffer + samplesDecoded, numSamples - samplesDecoded);
|
||||
|
||||
if (_currentStream->endOfData()) {
|
||||
_currentStream->rewind();
|
||||
|
||||
//pseudo random we don't want to play the same stream twice in a row.
|
||||
int32 idx = NUVIE_RAND() % _streams.size();
|
||||
Audio::RewindableAudioStream *tmp = _streams[idx];
|
||||
if (_currentStream == tmp) {
|
||||
idx = (idx + (NUVIE_RAND() % 1 == 1 ? 1 : _streams.size() - 1)) % _streams.size();
|
||||
_currentStream = _streams[idx];
|
||||
} else
|
||||
_currentStream = tmp;
|
||||
|
||||
//DEBUG(0, LEVEL_INFORMATIONAL, "new sample_num = %d\n", idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
return samplesDecoded;
|
||||
}
|
||||
|
||||
RandomCollectionAudioStream *makeRandomCollectionAudioStream(int rate, bool stereo,
|
||||
Std::vector<Audio::RewindableAudioStream *> streams, DisposeAfterUse::Flag disposeAfterUse) {
|
||||
return new RandomCollectionAudioStreamImpl(rate, stereo, streams, disposeAfterUse);
|
||||
}
|
||||
|
||||
} // End of namespace U6Audio
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
@@ -0,0 +1,51 @@
|
||||
/* 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 NUVIE_SOUND_MIXER_RANDOM_COLLECTION_AUDIO_STREAM_H
|
||||
#define NUVIE_SOUND_MIXER_RANDOM_COLLECTION_AUDIO_STREAM_H
|
||||
|
||||
#include "ultima/shared/std/containers.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
namespace U6Audio {
|
||||
|
||||
class RandomCollectionAudioStream : public Audio::AudioStream {
|
||||
public:
|
||||
/**
|
||||
* Mark this stream as finished. That is, signal that no further data
|
||||
* will be queued to it. Only after this has been done can this
|
||||
* stream ever 'end'.
|
||||
*/
|
||||
virtual void finish() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Factory function for a QueuingAudioStream.
|
||||
*/
|
||||
RandomCollectionAudioStream *makeRandomCollectionAudioStream(int rate, bool stereo, Std::vector<Audio::RewindableAudioStream *>streams, DisposeAfterUse::Flag disposeAfterUse);
|
||||
|
||||
} // End of namespace U6Audio
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
128
engines/ultima/nuvie/sound/decoder/u6_adplug_decoder_stream.cpp
Normal file
128
engines/ultima/nuvie/sound/decoder/u6_adplug_decoder_stream.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
/* Created by Eric Fry
|
||||
* Copyright (C) 2011 The Nuvie Team
|
||||
*
|
||||
* 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/>.
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ultima/nuvie/core/nuvie_defs.h"
|
||||
#include "ultima/nuvie/misc/u6_misc.h"
|
||||
#include "ultima/nuvie/files/nuvie_io.h"
|
||||
#include "ultima/nuvie/files/u6_lib_n.h"
|
||||
#include "ultima/nuvie/files/u6_lzw.h"
|
||||
#include "ultima/nuvie/sound/decoder/u6_adplug_decoder_stream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
U6AdPlugDecoderStream::U6AdPlugDecoderStream(CEmuopl *o, const Common::Path &filename, uint16 song_num) {
|
||||
is_midi_track = false;
|
||||
opl = o;
|
||||
samples_left = 0;
|
||||
if (has_file_extension(filename.baseName().c_str(), ".lzc")) {
|
||||
player = new CmidPlayer(opl);
|
||||
((CmidPlayer *)player)->load(filename, song_num);
|
||||
is_midi_track = true;
|
||||
} else {
|
||||
player = new Cu6mPlayer(opl);
|
||||
player->load(filename);
|
||||
}
|
||||
player_refresh_count = (int)(opl->getRate() / player->getrefresh());
|
||||
|
||||
interrupt_rate = (int)(opl->getRate() / 60);
|
||||
interrupt_samples_left = interrupt_rate;
|
||||
}
|
||||
|
||||
U6AdPlugDecoderStream::~U6AdPlugDecoderStream() {
|
||||
}
|
||||
|
||||
int U6AdPlugDecoderStream::readBuffer(sint16 *buffer, const int numSamples) {
|
||||
sint32 i, j;
|
||||
short *data = (short *)buffer;
|
||||
|
||||
int len = numSamples / 2;
|
||||
|
||||
//DEBUG(0, LEVEL_INFORMATIONAL, "Get here. numSamples = %d player refreshrate = %f refresh_count = %d\n", numSamples, player->getrefresh(), (int)(opl->getRate() / player->getrefresh()));
|
||||
|
||||
if (samples_left > 0) {
|
||||
if (samples_left > len) {
|
||||
update_opl(data, len);
|
||||
samples_left -= len;
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
update_opl(data, samples_left);
|
||||
data += samples_left * 2;
|
||||
len -= samples_left;
|
||||
samples_left = 0;
|
||||
}
|
||||
|
||||
for (i = len; i > 0;) {
|
||||
|
||||
if (!player->update()) {
|
||||
player->rewind();
|
||||
//SoundManager::g_MusicFinished = true;
|
||||
DEBUG(0, LEVEL_DEBUGGING, "Music Finished!\n");
|
||||
}
|
||||
|
||||
j = (int)(opl->getRate() / player->getrefresh());
|
||||
if (j > i) {
|
||||
samples_left = j - i;
|
||||
j = i;
|
||||
}
|
||||
update_opl(data, j);
|
||||
|
||||
data += j * 2;
|
||||
i -= j;
|
||||
}
|
||||
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
void U6AdPlugDecoderStream::update_opl(short *data, int len) {
|
||||
if (is_midi_track) {
|
||||
if (interrupt_samples_left > 0) {
|
||||
if (interrupt_samples_left > len) {
|
||||
opl->update(data, len);
|
||||
interrupt_samples_left -= len;
|
||||
return;
|
||||
}
|
||||
|
||||
opl->update(data, interrupt_samples_left);
|
||||
data += interrupt_samples_left * 2;
|
||||
len -= interrupt_samples_left;
|
||||
interrupt_samples_left = 0;
|
||||
}
|
||||
|
||||
for (int i = len; i > 0;) {
|
||||
((CmidPlayer *)player)->interrupt_vector();
|
||||
|
||||
int j = interrupt_rate;
|
||||
if (j > i) {
|
||||
interrupt_samples_left = j - i;
|
||||
j = i;
|
||||
}
|
||||
opl->update(data, j);
|
||||
|
||||
data += j * 2;
|
||||
i -= j;
|
||||
}
|
||||
} else {
|
||||
opl->update(data, len);
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
@@ -0,0 +1,95 @@
|
||||
/* Created by Eric Fry
|
||||
* Copyright (C) 2011 The Nuvie Team
|
||||
*
|
||||
* 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/>.
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef NUVIE_SOUND_ADPLUG_ADPLUG_DECODER_STREAM_H
|
||||
#define NUVIE_SOUND_ADPLUG_ADPLUG_DECODER_STREAM_H
|
||||
|
||||
#include "ultima/shared/std/string.h"
|
||||
#include "ultima/nuvie/sound/adplug/emu_opl.h"
|
||||
#include "ultima/nuvie/sound/adplug/opl.h"
|
||||
#include "ultima/nuvie/sound/adplug/u6m.h"
|
||||
#include "ultima/nuvie/sound/adplug/mid.h"
|
||||
#include "audio/audiostream.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
class U6Lib_n;
|
||||
class U6Lzw;
|
||||
class NuvieIOBuffer;
|
||||
using Std::string;
|
||||
|
||||
class U6AdPlugDecoderStream : public Audio::RewindableAudioStream {
|
||||
public:
|
||||
U6AdPlugDecoderStream() {
|
||||
opl = nullptr;
|
||||
player = nullptr;
|
||||
player_refresh_count = 0;
|
||||
}
|
||||
|
||||
U6AdPlugDecoderStream(CEmuopl *o, const Common::Path &filename, uint16 song_num);
|
||||
~U6AdPlugDecoderStream() override;
|
||||
|
||||
int readBuffer(sint16 *buffer, const int numSamples) override;
|
||||
|
||||
/** Is this a stereo stream? */
|
||||
bool isStereo() const override {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Sample rate of the stream. */
|
||||
int getRate() const override {
|
||||
return opl->getRate();
|
||||
}
|
||||
|
||||
bool rewind() override {
|
||||
if (player) {
|
||||
player->rewind(); //FIXME this would need to be locked if called outside mixer thread.
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* End of data reached? If this returns true, it means that at this
|
||||
* time there is no data available in the stream. However there may be
|
||||
* more data in the future.
|
||||
* This is used by e.g. a rate converter to decide whether to keep on
|
||||
* converting data or stop.
|
||||
*/
|
||||
bool endOfData() const override {
|
||||
return false;
|
||||
}
|
||||
private:
|
||||
void update_opl(short *data, int num_samples);
|
||||
protected:
|
||||
|
||||
uint16 samples_left;
|
||||
CEmuopl *opl;
|
||||
CPlayer *player;
|
||||
int player_refresh_count;
|
||||
int interrupt_rate;
|
||||
int interrupt_samples_left;
|
||||
bool is_midi_track;
|
||||
};
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user