Make Channel an interface

This commit is contained in:
Ted John 2017-01-02 03:21:45 +00:00
parent 0d4531d10d
commit 46b4dbb4cb
2 changed files with 404 additions and 199 deletions

View File

@ -346,95 +346,225 @@ void Source_SampleStream::Unload()
buffersize = 0; buffersize = 0;
} }
Channel::Channel() class AudioChannel : public IAudioChannel
{ {
SetRate(1); private:
SetVolume(SDL_MIX_MAXVOLUME); Source * _source = nullptr;
SetPan(0.5f); SpeexResamplerState * _resampler = nullptr;
}
Channel::~Channel() int _group = MIXER_GROUP_SOUND;
{ double _rate = 0;
if (resampler) { unsigned long _offset = 0;
speex_resampler_destroy(resampler); int _loop = 0;
resampler = 0;
}
if (deletesourceondone) {
delete source;
}
}
void Channel::Play(Source& source, int loop = MIXER_LOOP_NONE) int _volume = 1;
{ float _volume_l = 0.f;
Channel::source = &source; float _volume_r = 0.f;
Channel::loop = loop; float _oldvolume_l = 0.f;
offset = 0; float _oldvolume_r = 0.f;
done = false; int _oldvolume = 0;
} float _pan = 0;
void Channel::SetRate(double rate) bool _stopping = false;
{ bool _done = true;
Channel::rate = rate; bool _deleteondone = false;
if (Channel::rate < 0.001) { bool _deletesourceondone = false;
Channel::rate = 0.001;
}
}
void Channel::SetVolume(int volume) public:
{ AudioChannel()
Channel::volume = volume; {
if (volume > SDL_MIX_MAXVOLUME) { SetRate(1);
Channel::volume = SDL_MIX_MAXVOLUME; SetVolume(SDL_MIX_MAXVOLUME);
} SetPan(0.5f);
if (volume < 0) { }
Channel::volume = 0;
}
}
void Channel::SetPan(float pan) ~AudioChannel() override
{ {
Channel::pan = pan; if (_resampler != nullptr)
if (pan > 1) { {
Channel::pan = 1; speex_resampler_destroy(_resampler);
} _resampler = nullptr;
if (pan < 0) { }
Channel::pan = 0; if (_deletesourceondone)
} {
double decibels = (std::abs(Channel::pan - 0.5) * 2.0) * 100.0; delete _source;
double attenuation = pow(10, decibels / 20.0); }
if (Channel::pan <= 0.5) { }
volume_l = 1.0;
volume_r = float(1.0 / attenuation);
} else {
volume_r = 1.0;
volume_l = float(1.0 / attenuation);
}
}
bool Channel::IsPlaying() Source * GetSource() const override
{ {
return !done; return _source;
} }
unsigned long Channel::GetOffset() SpeexResamplerState * GetResampler() const override
{ {
return offset; return _resampler;
} }
bool Channel::SetOffset(unsigned long offset) void SetResampler(SpeexResamplerState * value) override
{ {
if (source && offset < source->Length()) { _resampler = value;
int samplesize = source->Format().channels * source->Format().BytesPerSample(); }
Channel::offset = (offset / samplesize) * samplesize;
return true;
}
return false;
}
void Channel::SetGroup(int group) int GetGroup() const override
{ {
Channel::group = group; return _group;
} }
void SetGroup(int group)
{
_group = group;
}
double GetRate() const override
{
return _rate;
}
void SetRate(double rate)
{
_rate = Math::Max(0.001, rate);
}
unsigned long GetOffset() const override
{
return _offset;
}
bool SetOffset(unsigned long offset)
{
if (_source && offset < _source->Length())
{
AudioFormat format = _source->Format();
int samplesize = format.channels * format.BytesPerSample();
_offset = (offset / samplesize) * samplesize;
return true;
}
return false;
}
virtual int GetLoop() const override
{
return _loop;
}
virtual void SetLoop(int value) override
{
_loop = value;
}
int GetVolume() const override
{
return _volume;
}
float GetVolumeL() const override
{
return _volume_l;
}
float GetVolumeR() const override
{
return _volume_r;
}
float GetOldVolumeL() const override
{
return _oldvolume_l;
}
float GetOldVolumeR() const override
{
return _oldvolume_r;
}
int GetOldVolume() const override
{
return _oldvolume;
}
void SetVolume(int volume) override
{
_volume = Math::Clamp(0, volume, SDL_MIX_MAXVOLUME);
}
float GetPan() const override
{
return _pan;
}
void SetPan(float pan)
{
_pan = Math::Clamp(0.0f, pan, 1.0f);
double decibels = (std::abs(_pan - 0.5) * 2.0) * 100.0;
double attenuation = pow(10, decibels / 20.0);
if (_pan <= 0.5)
{
_volume_l = 1.0;
_volume_r = (float)(1.0 / attenuation);
}
else
{
_volume_r = 1.0;
_volume_l = (float)(1.0 / attenuation);
}
}
bool IsStopping() const override
{
return _stopping;
}
void SetStopping(bool value) override
{
_stopping = value;
}
bool IsDone() const override
{
return _done;
}
void SetDone(bool value) override
{
_done = value;
}
bool DeleteOnDone() const
{
return _deleteondone;
}
void SetDeleteOnDone(bool value) override
{
_deleteondone = value;
}
void SetDeleteSourceOnDone(bool value) override
{
_deletesourceondone = value;
}
bool IsPlaying() const override
{
return !_done;
}
void Play(Source& source, int loop)
{
_source = &source;
_loop = loop;
_offset = 0;
_done = false;
}
void UpdateOldVolume() override
{
_oldvolume = _volume;
_oldvolume_l = _volume_l;
_oldvolume_r = _volume_r;
}
};
class AudioMixer : public IAudioMixer class AudioMixer : public IAudioMixer
{ {
@ -442,7 +572,7 @@ private:
SDL_AudioDeviceID deviceid = 0; SDL_AudioDeviceID deviceid = 0;
AudioFormat format = { 0 }; AudioFormat format = { 0 };
uint8 * effectbuffer = nullptr; uint8 * effectbuffer = nullptr;
std::list<Channel *> channels; std::list<IAudioChannel *> channels;
Source_Null source_null; Source_Null source_null;
float volume = 1.0f; float volume = 1.0f;
float adjust_sound_vol = 0.0f; float adjust_sound_vol = 0.0f;
@ -531,24 +661,25 @@ public:
SDL_UnlockAudioDevice(deviceid); SDL_UnlockAudioDevice(deviceid);
} }
Channel * Play(Source& source, int loop, bool deleteondone, bool deletesourceondone) override IAudioChannel * Play(Source& source, int loop, bool deleteondone, bool deletesourceondone) override
{ {
Lock(); Lock();
Channel* newchannel = new (std::nothrow) Channel; IAudioChannel * newchannel = new (std::nothrow) AudioChannel;
if (newchannel) { if (newchannel != nullptr)
{
newchannel->Play(source, loop); newchannel->Play(source, loop);
newchannel->deleteondone = deleteondone; newchannel->SetDeleteOnDone(deleteondone);
newchannel->deletesourceondone = deletesourceondone; newchannel->SetDeleteSourceOnDone(deletesourceondone);
channels.push_back(newchannel); channels.push_back(newchannel);
} }
Unlock(); Unlock();
return newchannel; return newchannel;
} }
void Stop(Channel& channel) override void Stop(IAudioChannel * channel) override
{ {
Lock(); Lock();
channel.stopping = true; channel->SetStopping(true);
Unlock(); Unlock();
} }
@ -592,109 +723,137 @@ private:
static void SDLCALL Callback(void * arg, uint8 * stream, int length) static void SDLCALL Callback(void * arg, uint8 * stream, int length)
{ {
auto mixer = static_cast<AudioMixer *>(arg); auto mixer = static_cast<AudioMixer *>(arg);
memset(stream, 0, length); memset(stream, 0, length);
std::list<Channel*>::iterator i = mixer->channels.begin(); std::list<IAudioChannel *>::iterator it = mixer->channels.begin();
while (i != mixer->channels.end()) { while (it != mixer->channels.end())
Channel * channel = *i; {
mixer->MixChannel(*channel, stream, length); IAudioChannel * channel = *it;
if ((channel->done && channel->deleteondone) || channel->stopping) mixer->MixChannel(channel, stream, length);
if ((channel->IsDone() && channel->DeleteOnDone()) || channel->IsStopping())
{ {
delete channel; delete channel;
i = mixer->channels.erase(i); it = mixer->channels.erase(it);
} }
else else
{ {
i++; it++;
} }
} }
} }
void MixChannel(Channel& channel, uint8* data, int length) void MixChannel(IAudioChannel * channel, uint8* data, int length)
{ {
// Did the volume level get changed? Recalculate level in this case. // Did the volume level get changed? Recalculate level in this case.
if (setting_sound_vol != gConfigSound.sound_volume) { if (setting_sound_vol != gConfigSound.sound_volume)
{
setting_sound_vol = gConfigSound.sound_volume; setting_sound_vol = gConfigSound.sound_volume;
adjust_sound_vol = powf(setting_sound_vol / 100.f, 10.f / 6.f); adjust_sound_vol = powf(setting_sound_vol / 100.f, 10.f / 6.f);
} }
if (setting_music_vol != gConfigSound.ride_music_volume) { if (setting_music_vol != gConfigSound.ride_music_volume)
{
setting_music_vol = gConfigSound.ride_music_volume; setting_music_vol = gConfigSound.ride_music_volume;
adjust_music_vol = powf(setting_music_vol / 100.f, 10.f / 6.f); adjust_music_vol = powf(setting_music_vol / 100.f, 10.f / 6.f);
} }
// Do not mix channel if channel is a sound and sound is disabled // Do not mix channel if channel is a sound and sound is disabled
if (channel.group == MIXER_GROUP_SOUND && !gConfigSound.sound_enabled) { if (channel->GetGroup() == MIXER_GROUP_SOUND && !gConfigSound.sound_enabled) {
return; return;
} }
if (channel.source && channel.source->Length() > 0 && !channel.done) { Source * source = channel->GetSource();
AudioFormat streamformat = channel.source->Format(); if (source != nullptr && source->Length() > 0 && !channel->IsDone())
{
AudioFormat streamformat = source->Format();
int loaded = 0; int loaded = 0;
SDL_AudioCVT cvt; SDL_AudioCVT cvt;
cvt.len_ratio = 1; cvt.len_ratio = 1;
do { do
{
int samplesize = format.channels * format.BytesPerSample(); int samplesize = format.channels * format.BytesPerSample();
int samples = length / samplesize; int samples = length / samplesize;
int samplesloaded = loaded / samplesize; int samplesloaded = loaded / samplesize;
double rate = 1; double rate = 1;
if (format.format == AUDIO_S16SYS) { if (format.format == AUDIO_S16SYS)
rate = channel.rate; {
rate = channel->GetRate();
} }
int samplestoread = (int)((samples - samplesloaded) * rate); int samplestoread = (int)((samples - samplesloaded) * rate);
int lengthloaded = 0; int lengthloaded = 0;
if (channel.offset < channel.source->Length()) { if (channel->GetOffset() < source->Length())
{
bool mustconvert = false; bool mustconvert = false;
if (MustConvert(*channel.source)) { if (MustConvert(*source))
if (SDL_BuildAudioCVT(&cvt, streamformat.format, streamformat.channels, streamformat.freq, format.format, format.channels, format.freq) == -1) { {
if (SDL_BuildAudioCVT(&cvt, streamformat.format, streamformat.channels, streamformat.freq, format.format, format.channels, format.freq) == -1)
{
break; break;
} }
mustconvert = true; mustconvert = true;
} }
const uint8* datastream = 0; const uint8 * datastream = nullptr;
int toread = (int)(samplestoread / cvt.len_ratio) * samplesize; int toread = (int)(samplestoread / cvt.len_ratio) * samplesize;
int readfromstream = (channel.source->GetSome(channel.offset, &datastream, toread)); int readfromstream = source->GetSome(channel->GetOffset(), &datastream, toread);
if (readfromstream == 0) { if (readfromstream == 0)
{
break; break;
} }
uint8* dataconverted = 0; uint8* dataconverted = 0;
const uint8* tomix = 0; const uint8* tomix = 0;
if (mustconvert) { if (mustconvert)
{
// tofix: there seems to be an issue with converting audio using SDL_ConvertAudio in the callback vs preconverted, can cause pops and static depending on sample rate and channels // tofix: there seems to be an issue with converting audio using SDL_ConvertAudio in the callback vs preconverted, can cause pops and static depending on sample rate and channels
if (Convert(cvt, datastream, readfromstream, &dataconverted)) { if (Convert(cvt, datastream, readfromstream, &dataconverted))
{
tomix = dataconverted; tomix = dataconverted;
lengthloaded = cvt.len_cvt; lengthloaded = cvt.len_cvt;
} else { }
else
{
break; break;
} }
} else { }
else
{
tomix = datastream; tomix = datastream;
lengthloaded = readfromstream; lengthloaded = readfromstream;
} }
bool effectbufferloaded = false; bool effectbufferloaded = false;
if (rate != 1 && format.format == AUDIO_S16SYS) { if (rate != 1 && format.format == AUDIO_S16SYS)
{
int in_len = (int)((double)lengthloaded / samplesize); int in_len = (int)((double)lengthloaded / samplesize);
int out_len = samples; int out_len = samples;
if (!channel.resampler) {
channel.resampler = speex_resampler_init(format.channels, format.freq, format.freq, 0, 0); SpeexResamplerState * resampler = channel->GetResampler();
if (resampler == nullptr)
{
resampler = speex_resampler_init(format.channels, format.freq, format.freq, 0, 0);
channel->SetResampler(resampler);
} }
if (readfromstream == toread) { if (readfromstream == toread)
{
// use buffer lengths for conversion ratio so that it fits exactly // use buffer lengths for conversion ratio so that it fits exactly
speex_resampler_set_rate(channel.resampler, in_len, samples - samplesloaded); speex_resampler_set_rate(resampler, in_len, samples - samplesloaded);
} else {
// reached end of stream so we cant use buffer length as resampling ratio
speex_resampler_set_rate(channel.resampler, format.freq, (int)(format.freq * (1 / rate)));
} }
speex_resampler_process_interleaved_int(channel.resampler, (const spx_int16_t*)tomix, (spx_uint32_t*)&in_len, (spx_int16_t*)effectbuffer, (spx_uint32_t*)&out_len); else
{
// reached end of stream so we cant use buffer length as resampling ratio
speex_resampler_set_rate(resampler, format.freq, (int)(format.freq * (1 / rate)));
}
speex_resampler_process_interleaved_int(resampler, (const spx_int16_t*)tomix, (spx_uint32_t*)&in_len, (spx_int16_t*)effectbuffer, (spx_uint32_t*)&out_len);
effectbufferloaded = true; effectbufferloaded = true;
tomix = effectbuffer; tomix = effectbuffer;
lengthloaded = (out_len * samplesize); lengthloaded = (out_len * samplesize);
} }
if (channel.pan != 0.5f && format.channels == 2) { if (channel->GetPan() != 0.5f && format.channels == 2)
if (!effectbufferloaded) { {
if (!effectbufferloaded)
{
memcpy(effectbuffer, tomix, lengthloaded); memcpy(effectbuffer, tomix, lengthloaded);
effectbufferloaded = true; effectbufferloaded = true;
tomix = effectbuffer; tomix = effectbuffer;
@ -710,13 +869,14 @@ private:
} }
int mixlength = lengthloaded; int mixlength = lengthloaded;
if (loaded + mixlength > length) { if (loaded + mixlength > length)
{
mixlength = length - loaded; mixlength = length - loaded;
} }
float volumeadjust = volume; float volumeadjust = volume;
volumeadjust *= (gConfigSound.master_volume / 100.0f); volumeadjust *= (gConfigSound.master_volume / 100.0f);
switch (channel.group) { switch (channel->GetGroup()) {
case MIXER_GROUP_SOUND: case MIXER_GROUP_SOUND:
volumeadjust *= adjust_sound_vol; volumeadjust *= adjust_sound_vol;
@ -729,15 +889,18 @@ private:
volumeadjust *= adjust_music_vol; volumeadjust *= adjust_music_vol;
break; break;
} }
int startvolume = (int)(channel.oldvolume * volumeadjust); int startvolume = (int)(channel->GetOldVolume() * volumeadjust);
int endvolume = (int)(channel.volume * volumeadjust); int endvolume = (int)(channel->GetVolume() * volumeadjust);
if (channel.stopping) { if (channel->IsStopping())
{
endvolume = 0; endvolume = 0;
} }
int mixvolume = (int)(channel.volume * volumeadjust); int mixvolume = (int)(channel->GetVolume() * volumeadjust);
if (startvolume != endvolume) { if (startvolume != endvolume)
{
// fade between volume levels to smooth out sound and minimize clicks from sudden volume changes // fade between volume levels to smooth out sound and minimize clicks from sudden volume changes
if (!effectbufferloaded) { if (!effectbufferloaded)
{
memcpy(effectbuffer, tomix, lengthloaded); memcpy(effectbuffer, tomix, lengthloaded);
effectbufferloaded = true; effectbufferloaded = true;
tomix = effectbuffer; tomix = effectbuffer;
@ -756,72 +919,85 @@ private:
SDL_MixAudioFormat(&data[loaded], tomix, format.format, mixlength, mixvolume); SDL_MixAudioFormat(&data[loaded], tomix, format.format, mixlength, mixvolume);
if (dataconverted) { if (dataconverted)
{
delete[] dataconverted; delete[] dataconverted;
} }
channel.offset += readfromstream; channel->SetOffset(channel->GetOffset() + readfromstream);
} }
loaded += lengthloaded; loaded += lengthloaded;
if (channel.loop != 0 && channel.offset >= channel.source->Length()) { int loop = channel->GetLoop();
if (channel.loop != -1) { if (loop != 0 && channel->GetOffset() >= source->Length())
channel.loop--; {
if (loop != -1)
{
channel->SetLoop(loop - 1);
} }
channel.offset = 0; channel->SetOffset(0);
} }
} while (loaded < length && channel.loop != 0 && !channel.stopping); }
while (loaded < length && channel->GetLoop() != 0 && !channel->IsStopping());
channel.oldvolume = channel.volume; channel->UpdateOldVolume();
channel.oldvolume_l = channel.volume_l; if (channel->GetLoop() == 0 && channel->GetOffset() >= source->Length())
channel.oldvolume_r = channel.volume_r; {
if (channel.loop == 0 && channel.offset >= channel.source->Length()) { channel->SetDone(true);
channel.done = true;
} }
} }
} }
void EffectPanS16(Channel& channel, sint16* data, int length) static void EffectPanS16(const IAudioChannel * channel, sint16 * data, int length)
{ {
const float dt = 1.0f / (length * 2); const float dt = 1.0f / (length * 2);
float left_volume = channel.oldvolume_l; float volumeL = channel->GetOldVolumeL();
float right_volume = channel.oldvolume_r; float volumeR = channel->GetOldVolumeR();
const float d_left = dt * (channel.volume_l - channel.oldvolume_l); const float d_left = dt * (channel->GetVolumeL() - channel->GetOldVolumeL());
const float d_right = dt * (channel.volume_r - channel.oldvolume_r); const float d_right = dt * (channel->GetVolumeR() - channel->GetOldVolumeR());
for (int i = 0; i < length * 2; i += 2) { for (int i = 0; i < length * 2; i += 2)
data[i] = (sint16)(data[i] * left_volume); {
data[i + 1] = (sint16)(data[i + 1] * right_volume); data[i] = (sint16)(data[i] * volumeL);
left_volume += d_left; data[i + 1] = (sint16)(data[i + 1] * volumeR);
right_volume += d_right; volumeL += d_left;
volumeR += d_right;
} }
} }
void EffectPanU8(Channel& channel, uint8* data, int length) static void EffectPanU8(const IAudioChannel * channel, uint8 * data, int length)
{ {
for (int i = 0; i < length * 2; i += 2) { float volumeL = channel->GetVolumeL();
float volumeR = channel->GetVolumeR();
float oldVolumeL = channel->GetOldVolumeL();
float oldVolumeR = channel->GetOldVolumeR();
for (int i = 0; i < length * 2; i += 2)
{
float t = (float)i / (length * 2); float t = (float)i / (length * 2);
data[i] = (uint8)(data[i] * ((1.0 - t) * channel.oldvolume_l + t * channel.volume_l)); data[i] = (uint8)(data[i] * ((1.0 - t) * oldVolumeL + t * volumeL));
data[i + 1] = (uint8)(data[i + 1] * ((1.0 - t) * channel.oldvolume_r + t * channel.volume_r)); data[i + 1] = (uint8)(data[i + 1] * ((1.0 - t) * oldVolumeR + t * volumeR));
} }
} }
void EffectFadeS16(sint16* data, int length, int startvolume, int endvolume) static void EffectFadeS16(sint16 * data, int length, int startvolume, int endvolume)
{ {
float startvolume_f = (float)startvolume / SDL_MIX_MAXVOLUME; float startvolume_f = (float)startvolume / SDL_MIX_MAXVOLUME;
float endvolume_f = (float)endvolume / SDL_MIX_MAXVOLUME; float endvolume_f = (float)endvolume / SDL_MIX_MAXVOLUME;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++)
{
float t = (float)i / length; float t = (float)i / length;
data[i] = (sint16)(data[i] * ((1 - t) * startvolume_f + t * endvolume_f)); data[i] = (sint16)(data[i] * ((1 - t) * startvolume_f + t * endvolume_f));
} }
} }
void EffectFadeU8(uint8* data, int length, int startvolume, int endvolume) static void EffectFadeU8(uint8* data, int length, int startvolume, int endvolume)
{ {
float startvolume_f = (float)startvolume / SDL_MIX_MAXVOLUME; float startvolume_f = (float)startvolume / SDL_MIX_MAXVOLUME;
float endvolume_f = (float)endvolume / SDL_MIX_MAXVOLUME; float endvolume_f = (float)endvolume / SDL_MIX_MAXVOLUME;
for (int i = 0; i < length; i++) { for (int i = 0; i < length; i++)
{
float t = (float)i / length; float t = (float)i / length;
data[i] = (uint8)(data[i] * ((1 - t) * startvolume_f + t * endvolume_f)); data[i] = (uint8)(data[i] * ((1 - t) * startvolume_f + t * endvolume_f));
} }
@ -830,7 +1006,10 @@ private:
bool MustConvert(Source& source) bool MustConvert(Source& source)
{ {
const AudioFormat sourceformat = source.Format(); const AudioFormat sourceformat = source.Format();
if (sourceformat.format != format.format || sourceformat.channels != format.channels || sourceformat.freq != format.freq) { if (sourceformat.format != format.format ||
sourceformat.channels != format.channels ||
sourceformat.freq != format.freq)
{
return true; return true;
} }
return false; return false;
@ -864,7 +1043,7 @@ void Mixer_Init(const char * device)
void * Mixer_Play_Effect(size_t id, int loop, int volume, float pan, double rate, int deleteondone) void * Mixer_Play_Effect(size_t id, int loop, int volume, float pan, double rate, int deleteondone)
{ {
Channel * channel = nullptr; IAudioChannel * channel = nullptr;
if (!gOpenRCT2Headless && gConfigSound.sound_enabled) if (!gOpenRCT2Headless && gConfigSound.sound_enabled)
{ {
if (id >= SOUND_MAXID) if (id >= SOUND_MAXID)
@ -893,7 +1072,7 @@ void Mixer_Stop_Channel(void * channel)
{ {
if (!gOpenRCT2Headless) if (!gOpenRCT2Headless)
{ {
gMixer->Stop(*static_cast<Channel*>(channel)); gMixer->Stop(static_cast<IAudioChannel*>(channel));
} }
} }
@ -902,17 +1081,17 @@ void Mixer_Channel_Volume(void * channel, int volume)
if (!gOpenRCT2Headless) if (!gOpenRCT2Headless)
{ {
gMixer->Lock(); gMixer->Lock();
static_cast<Channel*>(channel)->SetVolume(volume); static_cast<IAudioChannel*>(channel)->SetVolume(volume);
gMixer->Unlock(); gMixer->Unlock();
} }
} }
void Mixer_Channel_Pan(void* channel, float pan) void Mixer_Channel_Pan(void * channel, float pan)
{ {
if (!gOpenRCT2Headless) if (!gOpenRCT2Headless)
{ {
gMixer->Lock(); gMixer->Lock();
static_cast<Channel*>(channel)->SetPan(pan); static_cast<IAudioChannel*>(channel)->SetPan(pan);
gMixer->Unlock(); gMixer->Unlock();
} }
} }
@ -922,7 +1101,7 @@ void Mixer_Channel_Rate(void* channel, double rate)
if (!gOpenRCT2Headless) if (!gOpenRCT2Headless)
{ {
gMixer->Lock(); gMixer->Lock();
static_cast<Channel*>(channel)->SetRate(rate); static_cast<IAudioChannel*>(channel)->SetRate(rate);
gMixer->Unlock(); gMixer->Unlock();
} }
} }
@ -932,7 +1111,7 @@ int Mixer_Channel_IsPlaying(void * channel)
bool isPlaying = false; bool isPlaying = false;
if (!gOpenRCT2Headless) if (!gOpenRCT2Headless)
{ {
isPlaying = static_cast<Channel*>(channel)->IsPlaying(); isPlaying = static_cast<IAudioChannel*>(channel)->IsPlaying();
} }
return isPlaying; return isPlaying;
} }
@ -942,7 +1121,7 @@ unsigned long Mixer_Channel_GetOffset(void * channel)
unsigned long offset = 0; unsigned long offset = 0;
if (!gOpenRCT2Headless) if (!gOpenRCT2Headless)
{ {
offset = static_cast<Channel*>(channel)->GetOffset(); offset = static_cast<IAudioChannel*>(channel)->GetOffset();
} }
return offset; return offset;
} }
@ -952,7 +1131,7 @@ int Mixer_Channel_SetOffset(void * channel, unsigned long offset)
int result = 0; int result = 0;
if (!gOpenRCT2Headless) if (!gOpenRCT2Headless)
{ {
result = static_cast<Channel*>(channel)->SetOffset(offset); result = static_cast<IAudioChannel*>(channel)->SetOffset(offset);
} }
return result; return result;
} }
@ -961,13 +1140,13 @@ void Mixer_Channel_SetGroup(void * channel, int group)
{ {
if (!gOpenRCT2Headless) if (!gOpenRCT2Headless)
{ {
static_cast<Channel*>(channel)->SetGroup(group); static_cast<IAudioChannel *>(channel)->SetGroup(group);
} }
} }
void * Mixer_Play_Music(int pathId, int loop, int streaming) void * Mixer_Play_Music(int pathId, int loop, int streaming)
{ {
Channel * channel = nullptr; IAudioChannel * channel = nullptr;
if (!gOpenRCT2Headless) if (!gOpenRCT2Headless)
{ {
IAudioMixer * mixer = gMixer; IAudioMixer * mixer = gMixer;

View File

@ -120,30 +120,56 @@ class Channel
public: public:
Channel(); Channel();
~Channel(); ~Channel();
void Play(Source& source, int loop);
void SetRate(double rate);
void SetVolume(int volume);
void SetPan(float pan);
bool IsPlaying();
unsigned long GetOffset();
bool SetOffset(unsigned long offset);
void SetGroup(int group);
int loop = 0; };
unsigned long offset = 0;
double rate = 0; interface IAudioChannel
int volume = 1; {
float volume_l = 0.f, volume_r = 0.f; virtual ~IAudioChannel() = default;
float oldvolume_l = 0.f, oldvolume_r = 0.f;
float pan = 0; virtual Source * GetSource() const abstract;
bool done = true;
bool deleteondone = false; virtual SpeexResamplerState * GetResampler() const abstract;
bool deletesourceondone = false; virtual void SetResampler(SpeexResamplerState * value) abstract;
bool stopping = false;
int oldvolume = 0; virtual int GetGroup() const abstract;
int group = MIXER_GROUP_SOUND; virtual void SetGroup(int group) abstract;
SpeexResamplerState* resampler = nullptr;
Source* source = nullptr; virtual double GetRate() const abstract;
virtual void SetRate(double rate) abstract;
virtual unsigned long GetOffset() const abstract;
virtual bool SetOffset(unsigned long offset) abstract;
virtual int GetLoop() const abstract;
virtual void SetLoop(int value) abstract;
virtual int GetVolume() const abstract;
virtual float GetVolumeL() const abstract;
virtual float GetVolumeR() const abstract;
virtual float GetOldVolumeL() const abstract;
virtual float GetOldVolumeR() const abstract;
virtual int GetOldVolume() const abstract;
virtual void SetVolume(int volume) abstract;
virtual float GetPan() const abstract;
virtual void SetPan(float pan) abstract;
virtual bool IsStopping() const abstract;
virtual void SetStopping(bool value) abstract;
virtual bool IsDone() const abstract;
virtual void SetDone(bool value) abstract;
virtual bool DeleteOnDone() const abstract;
virtual void SetDeleteOnDone(bool value) abstract;
virtual void SetDeleteSourceOnDone(bool value) abstract;
virtual bool IsPlaying() const abstract;
virtual void Play(Source& source, int loop = MIXER_LOOP_NONE) abstract;
virtual void UpdateOldVolume() abstract;
}; };
interface IAudioMixer interface IAudioMixer
@ -154,8 +180,8 @@ interface IAudioMixer
virtual void Close() abstract; virtual void Close() abstract;
virtual void Lock() abstract; virtual void Lock() abstract;
virtual void Unlock() abstract; virtual void Unlock() abstract;
virtual Channel * Play(Source& source, int loop, bool deleteondone, bool deletesourceondone) abstract; virtual IAudioChannel * Play(Source& source, int loop, bool deleteondone, bool deletesourceondone) abstract;
virtual void Stop(Channel& channel) abstract; virtual void Stop(IAudioChannel * channel) abstract;
virtual bool LoadMusic(size_t pathid) abstract; virtual bool LoadMusic(size_t pathid) abstract;
virtual void SetVolume(float volume) abstract; virtual void SetVolume(float volume) abstract;