Skip to content

Commit 2fa4e22

Browse files
authored
Merge pull request #3432 from Desdaemon/upstream-master
Audio: Add support for panning
2 parents 82adf68 + 220f897 commit 2fa4e22

15 files changed

Lines changed: 244 additions & 54 deletions

src/audio.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ AudioInterface& Audio() {
3333
return default_;
3434
}
3535

36-
void EmptyAudio::BGM_Play(Filesystem_Stream::InputStream, int, int, int) {
36+
void EmptyAudio::BGM_Play(Filesystem_Stream::InputStream, int, int, int, int) {
3737
bgm_starttick = Player::GetFrames();
3838
playing = true;
3939
}

src/audio.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,9 @@ struct AudioInterface {
6161
* @param volume volume.
6262
* @param pitch pitch.
6363
* @param fadein fadein.
64+
* @param balance balance (0 - 100)
6465
*/
65-
virtual void BGM_Play(Filesystem_Stream::InputStream stream, int volume, int pitch, int fadein) = 0;
66+
virtual void BGM_Play(Filesystem_Stream::InputStream stream, int volume, int pitch, int fadein, int balance) = 0;
6667

6768
/**
6869
* Stops the currently playing background music.
@@ -118,6 +119,11 @@ struct AudioInterface {
118119
*/
119120
virtual void BGM_Pitch(int pitch) = 0;
120121

122+
/**
123+
* Adjusts the balance of the currently playing background music.
124+
*/
125+
virtual void BGM_Balance(int balance) = 0;
126+
121127
/**
122128
* @return Type of music being played.
123129
*/
@@ -129,8 +135,9 @@ struct AudioInterface {
129135
* @param se se to play.
130136
* @param volume volume.
131137
* @param pitch pitch.
138+
* @param balance balance (0 - 100)
132139
*/
133-
virtual void SE_Play(std::unique_ptr<AudioSeCache> se, int volume, int pitch) = 0;
140+
virtual void SE_Play(std::unique_ptr<AudioSeCache> se, int volume, int pitch, int balance) = 0;
134141

135142
/**
136143
* Stops the currently playing sound effect.
@@ -162,7 +169,7 @@ struct AudioInterface {
162169
struct EmptyAudio : public AudioInterface {
163170
public:
164171
explicit EmptyAudio(const Game_ConfigAudio& cfg);
165-
void BGM_Play(Filesystem_Stream::InputStream, int, int, int) override;
172+
void BGM_Play(Filesystem_Stream::InputStream, int, int, int, int) override;
166173
void BGM_Pause() override {}
167174
void BGM_Resume() override {}
168175
void BGM_Stop() override;
@@ -172,8 +179,9 @@ struct EmptyAudio : public AudioInterface {
172179
void BGM_Fade(int) override {}
173180
void BGM_Volume(int) override {}
174181
void BGM_Pitch(int) override {};
182+
void BGM_Balance(int) override {}
175183
std::string BGM_GetType() const override { return {}; };
176-
void SE_Play(std::unique_ptr<AudioSeCache>, int, int) override {}
184+
void SE_Play(std::unique_ptr<AudioSeCache>, int, int, int) override {}
177185
void SE_Stop() override {}
178186
void Update() override {}
179187
void vGetConfig(Game_ConfigAudio& cfg) const override;

src/audio_decoder.cpp

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717

1818
// Headers
1919
#include <cassert>
20+
#include <cmath>
2021
#include <cstdint>
2122
#include <cstring>
2223
#include "audio_decoder.h"
24+
#include "audio_decoder_base.h"
2325
#include "audio_midi.h"
2426
#include "audio_resampler.h"
2527
#include "output.h"
@@ -175,16 +177,16 @@ void AudioDecoder::Update(std::chrono::microseconds delta) {
175177

176178
volume += static_cast<float>(std::chrono::duration_cast<std::chrono::microseconds>(delta).count()) * delta_volume_step;
177179
volume = Utils::Clamp(static_cast<float>(volume), 0.0f, 100.0f);
178-
log_volume = AdjustVolume(volume);
180+
ApplyLogVolume();
179181
}
180182

181-
int AudioDecoder::GetVolume() const {
182-
return static_cast<int>(log_volume);
183+
StereoVolume AudioDecoder::GetVolume() const {
184+
return log_volume;
183185
}
184186

185187
void AudioDecoder::SetVolume(int new_volume) {
186188
volume = Utils::Clamp(static_cast<float>(new_volume), 0.0f, 100.0f);
187-
log_volume = AdjustVolume(volume);
189+
ApplyLogVolume();
188190
}
189191

190192
void AudioDecoder::SetFade(int end, std::chrono::milliseconds duration) {
@@ -200,6 +202,11 @@ void AudioDecoder::SetFade(int end, std::chrono::milliseconds duration) {
200202
delta_volume_step = (static_cast<float>(fade_volume_end) - volume) / fade_time.count();
201203
}
202204

205+
void AudioDecoder::SetBalance(int balance) {
206+
AudioDecoderBase::SetBalance(balance);
207+
ApplyLogVolume();
208+
}
209+
203210
int AudioDecoder::GetSamplesizeForFormat(AudioDecoderBase::Format format) {
204211
switch (format) {
205212
case AudioDecoderBase::Format::S8:
@@ -217,3 +224,17 @@ int AudioDecoder::GetSamplesizeForFormat(AudioDecoderBase::Format format) {
217224
assert(false && "Bad format");
218225
return -1;
219226
}
227+
228+
void AudioDecoder::ApplyLogVolume() {
229+
float base_gain = AdjustVolume(volume);
230+
int balance = GetBalance();
231+
float left_gain = 1.f, right_gain = 1.f;
232+
constexpr float pan_exp = 0.5012f;
233+
if (balance <= 50) {
234+
right_gain = std::pow(pan_exp, (50 - balance) / 10.f);
235+
} else {
236+
left_gain = std::pow(pan_exp, (balance - 50) / 10.f);
237+
}
238+
log_volume.left_volume = base_gain * left_gain;
239+
log_volume.right_volume = base_gain * right_gain;
240+
}

src/audio_decoder.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ class AudioDecoder : public AudioDecoderBase {
7171
*
7272
* @return current volume (from 0 - 100)
7373
*/
74-
int GetVolume() const final override;
74+
StereoVolume GetVolume() const final override;
7575

7676
/**
7777
* Sets the volume of the audio decoder.
@@ -100,14 +100,21 @@ class AudioDecoder : public AudioDecoderBase {
100100
* @param delta Time in us since the last call of this function.
101101
*/
102102
void Update(std::chrono::microseconds delta) final override;
103+
104+
/**
105+
* Sets the pan/balance of the audio decoder.
106+
*/
107+
void SetBalance(int new_balance) override;
103108
private:
104109
bool paused = false;
105110
float volume = 0.0f;
106-
float log_volume = 0.0f; // as used by RPG_RT
111+
StereoVolume log_volume = {0.f, 0.f}; // as used by RPG_RT
107112

108113
int fade_volume_end = 0;
109114
std::chrono::microseconds fade_time = std::chrono::microseconds(0);
110115
float delta_volume_step = 0.0f;
116+
117+
void ApplyLogVolume();
111118
};
112119

113120
#endif

src/audio_decoder_base.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
float AudioDecoderBase::AdjustVolume(float volume) {
2727
// Adjust to RPG_RT (Direct Sound) volume scale
2828
if (volume > 0) {
29-
return 100.0f * std::pow(10.0f, (-100 + volume) / 60.0f);
29+
return 100.0f * std::pow(10.0f, -(35.0f / 20.0f) * (1.0f - volume / 100.0f));
3030
}
3131
return 0.0f;
3232
}
@@ -73,6 +73,14 @@ int AudioDecoderBase::GetLoopCount() const {
7373
return loop_count;
7474
}
7575

76+
int AudioDecoderBase::GetBalance() const {
77+
return balance;
78+
}
79+
80+
void AudioDecoderBase::SetBalance(int new_balance) {
81+
balance = Utils::Clamp(new_balance, 0, 100);
82+
}
83+
7684
bool AudioDecoderBase::WasInited() const {
7785
return true;
7886
}

src/audio_decoder_base.h

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@
2727
#include <chrono>
2828
#include "filesystem_stream.h"
2929

30+
/**
31+
* Stereo volume for left and right channels.
32+
* Both values are in the range 0 - 100.
33+
*/
34+
struct StereoVolume {
35+
float left_volume;
36+
float right_volume;
37+
};
38+
3039
/**
3140
* The AudioDecoder class provides an abstraction over the decoding of
3241
* common audio formats.
@@ -107,6 +116,18 @@ class AudioDecoderBase {
107116
*/
108117
virtual int GetLoopCount() const;
109118

119+
/**
120+
* Gets the current balance of the audio decoder.
121+
* The value is in the range 0 - 100, where 0 is full left, 100 is full right
122+
*/
123+
virtual int GetBalance() const;
124+
125+
/**
126+
* Sets the balance of the audio decoder.
127+
* The value is clamped to the range 0 - 100.
128+
*/
129+
virtual void SetBalance(int new_balance);
130+
110131
// Functions to be implemented by the audio decoder
111132
/**
112133
* Assigns a stream to the audio decoder.
@@ -131,9 +152,9 @@ class AudioDecoderBase {
131152
* Gets the current volume of the audio decoder.
132153
* Fades are considered.
133154
*
134-
* @return current volume (from 0 - 100)
155+
* @return left-right pair of current volume (from 0 - 100)
135156
*/
136-
virtual int GetVolume() const = 0;
157+
virtual StereoVolume GetVolume() const = 0;
137158

138159
/**
139160
* Sets the current volume of the audio decoder.
@@ -282,6 +303,7 @@ class AudioDecoderBase {
282303

283304
bool looping = false;
284305
int loop_count = 0;
306+
int balance = 50;
285307

286308
int Decode(uint8_t* buffer, int length, int recursion_depth);
287309
};

src/audio_decoder_midi.cpp

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@
1717

1818
#include <array>
1919
#include <algorithm>
20+
#include <cmath>
2021
#include "audio.h"
2122
#include "audio_decoder_midi.h"
2223
#include "midisequencer.h"
2324
#include "output.h"
25+
#include "utils.h"
2426

2527
using namespace std::chrono_literals;
2628

@@ -38,6 +40,7 @@ constexpr int samples_per_play = 64 / sample_divider;
3840

3941
static const uint8_t midi_set_reg_param_upper = 0x6;
4042
static const uint8_t midi_control_volume = 0x7;
43+
static const uint8_t midi_control_pan = 0xA;
4144
static const uint8_t midi_event_control_change = 0xB;
4245
static const uint8_t midi_set_reg_param_lower = 0x26;
4346
static const uint8_t midi_control_all_sound_off = 0x78;
@@ -66,6 +69,10 @@ static uint32_t midimsg_volume(uint8_t channel, uint8_t volume) {
6669
return midimsg_make(midi_event_control_change, channel, midi_control_volume, volume);
6770
}
6871

72+
static uint32_t midimsg_pan(uint8_t channel, uint8_t pan) {
73+
return midimsg_make(midi_event_control_change, channel, midi_control_pan, pan);
74+
}
75+
6976
static uint32_t midimsg_reset_all_controller(uint8_t channel) {
7077
return midimsg_make(midi_event_control_change, channel, midi_control_reset_all_controller, 0);
7178
}
@@ -112,6 +119,7 @@ AudioDecoderMidi::AudioDecoderMidi(std::unique_ptr<MidiDecoder> mididec)
112119
: mididec(std::move(mididec)) {
113120
seq = std::make_unique<midisequencer::sequencer>();
114121
channel_volumes.fill(127);
122+
midi_requested_channel_pans.fill(64);
115123
music_type = "midi";
116124
}
117125

@@ -175,14 +183,14 @@ void AudioDecoderMidi::Resume() {
175183
}
176184
}
177185

178-
int AudioDecoderMidi::GetVolume() const {
186+
StereoVolume AudioDecoderMidi::GetVolume() const {
179187
// When handled by Midi messages fake a 100 otherwise the volume is adjusted twice
180188

181189
if (!mididec->SupportsMidiMessages()) {
182-
return static_cast<int>(log_volume);
190+
return log_volume;
183191
}
184192

185-
return 100;
193+
return {100, 100};
186194
}
187195

188196
void AudioDecoderMidi::SetVolume(int new_volume) {
@@ -195,9 +203,7 @@ void AudioDecoderMidi::SetVolume(int new_volume) {
195203
mididec->SendMidiMessage(msg);
196204
}
197205

198-
if (!mididec->SupportsMidiMessages()) {
199-
log_volume = AdjustVolume(volume * 100.0f);
200-
}
206+
ApplyLogVolume();
201207
}
202208

203209
void AudioDecoderMidi::SetFade(int end, std::chrono::milliseconds duration) {
@@ -214,6 +220,16 @@ void AudioDecoderMidi::SetFade(int end, std::chrono::milliseconds duration) {
214220
delta_volume_step = (fade_volume_end - volume) / fade_steps;
215221
}
216222

223+
void AudioDecoderMidi::SetBalance(int new_balance) {
224+
AudioDecoderBase::SetBalance(new_balance);
225+
ApplyLogVolume();
226+
227+
for (int channel = 0; channel < 16; channel++) {
228+
uint32_t msg = midimsg_pan(channel, ChannelPan(midi_requested_channel_pans[channel]));
229+
mididec->SendMidiMessage(msg);
230+
}
231+
}
232+
217233
bool AudioDecoderMidi::Seek(std::streamoff offset, std::ios_base::seekdir origin) {
218234
assert(!tempo.empty());
219235

@@ -251,9 +267,7 @@ void AudioDecoderMidi::Update(std::chrono::microseconds delta) {
251267
}
252268
if (fade_steps > 0 && mtime - last_fade_mtime > 0.1s) {
253269
volume = Utils::Clamp<float>(volume + delta_volume_step, 0.0f, 1.0f);
254-
if (!mididec->SupportsMidiMessages()) {
255-
log_volume = AdjustVolume(volume * 100.0f);
256-
}
270+
ApplyLogVolume();
257271
for (int i = 0; i < 16; i++) {
258272
uint32_t msg = midimsg_volume(i, static_cast<uint8_t>(channel_volumes[i] * volume * global_volume));
259273
mididec->SendMidiMessage(msg);
@@ -392,6 +406,9 @@ void AudioDecoderMidi::midi_message(int, uint_least32_t message) {
392406
channel_volumes[channel] = value2;
393407
// Send the modified volume to midiout
394408
message = midimsg_volume(channel, static_cast<uint8_t>(value2 * volume * global_volume));
409+
} else if (event_type == midi_event_control_change && value1 == midi_control_pan) {
410+
midi_requested_channel_pans[channel] = value2;
411+
message = midimsg_pan(channel, ChannelPan(value2));
395412
}
396413
if (midimsg_validate(message)) {
397414
mididec->SendMidiMessage(message);
@@ -480,3 +497,23 @@ int AudioDecoderMidi::MidiTempoData::GetSamples(std::chrono::microseconds mtime_
480497
int ticks_since_last = static_cast<int>(ticks_per_us * delta.count());
481498
return samples + static_cast<int>(ticks_since_last * samples_per_tick);
482499
}
500+
501+
void AudioDecoderMidi::ApplyLogVolume() {
502+
if (!mididec->SupportsMidiMessages()) {
503+
float base_gain = AdjustVolume(volume);
504+
int balance = GetBalance();
505+
float left_gain = 1.f, right_gain = 1.f;
506+
constexpr float pan_exp = 0.5012f;
507+
if (balance <= 50) {
508+
right_gain = std::pow(pan_exp, (50 - balance) / 10.f);
509+
} else {
510+
left_gain = std::pow(pan_exp, (balance - 50) / 10.f);
511+
}
512+
log_volume.left_volume = base_gain * left_gain;
513+
log_volume.right_volume = base_gain * right_gain;
514+
}
515+
}
516+
517+
int AudioDecoderMidi::ChannelPan(int desired_pan) const {
518+
return Utils::Clamp(desired_pan + ((GetBalance() - 50) * 2), 0, 127);
519+
}

0 commit comments

Comments
 (0)