mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-10-01 07:28:30 +00:00
audio: Add gain support to audio streams and logical audio devices.
Fixes #10028.
This commit is contained in:
@@ -718,6 +718,62 @@ extern SDL_DECLSPEC int SDLCALL SDL_ResumeAudioDevice(SDL_AudioDeviceID dev);
|
|||||||
*/
|
*/
|
||||||
extern SDL_DECLSPEC SDL_bool SDLCALL SDL_AudioDevicePaused(SDL_AudioDeviceID dev);
|
extern SDL_DECLSPEC SDL_bool SDLCALL SDL_AudioDevicePaused(SDL_AudioDeviceID dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the gain of an audio device.
|
||||||
|
*
|
||||||
|
* The gain of a device is its volume; a larger gain means a louder output,
|
||||||
|
* with a gain of zero being silence.
|
||||||
|
*
|
||||||
|
* Audio devices default to a gain of 1.0f (no change in output).
|
||||||
|
*
|
||||||
|
* Physical devices may not have their gain changed, only logical devices,
|
||||||
|
* and this function will always return -1.0f when used on physical devices.
|
||||||
|
*
|
||||||
|
* \param devid the audio device to query.
|
||||||
|
* \returns the gain of the device, or -1.0f on error.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetAudioDeviceGain
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC float SDLCALL SDL_GetAudioDeviceGain(SDL_AudioDeviceID devid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the gain of an audio device.
|
||||||
|
*
|
||||||
|
* The gain of a device is its volume; a larger gain means a louder output,
|
||||||
|
* with a gain of zero being silence.
|
||||||
|
*
|
||||||
|
* Audio devices default to a gain of 1.0f (no change in output).
|
||||||
|
*
|
||||||
|
* Physical devices may not have their gain changed, only logical devices,
|
||||||
|
* and this function will always return -1 when used on physical devices. While
|
||||||
|
* it might seem attractive to adjust several logical devices at once in this
|
||||||
|
* way, it would allow an app or library to interfere with another portion of
|
||||||
|
* the program's otherwise-isolated devices.
|
||||||
|
*
|
||||||
|
* This is applied, along with any per-audiostream gain, during playback to
|
||||||
|
* the hardware, and can be continuously changed to create various effects.
|
||||||
|
* On recording devices, this will adjust the gain before passing the data
|
||||||
|
* into an audiostream; that recording audiostream can then adjust its gain
|
||||||
|
* further when outputting the data elsewhere, if it likes, but that second
|
||||||
|
* gain is not applied until the data leaves the audiostream again.
|
||||||
|
*
|
||||||
|
* \param devid the audio device on which to change gain.
|
||||||
|
* \param gain the gain. 1.0f is no change, 0.0f is silence.
|
||||||
|
* \returns 0 on success, or -1 on error.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, as it holds
|
||||||
|
* a stream-specific mutex while running.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAudioDeviceGain
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_SetAudioDeviceGain(SDL_AudioDeviceID devid, float gain);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close a previously-opened audio device.
|
* Close a previously-opened audio device.
|
||||||
*
|
*
|
||||||
@@ -981,6 +1037,51 @@ extern SDL_DECLSPEC float SDLCALL SDL_GetAudioStreamFrequencyRatio(SDL_AudioStre
|
|||||||
*/
|
*/
|
||||||
extern SDL_DECLSPEC int SDLCALL SDL_SetAudioStreamFrequencyRatio(SDL_AudioStream *stream, float ratio);
|
extern SDL_DECLSPEC int SDLCALL SDL_SetAudioStreamFrequencyRatio(SDL_AudioStream *stream, float ratio);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the gain of an audio stream.
|
||||||
|
*
|
||||||
|
* The gain of a stream is its volume; a larger gain means a louder output,
|
||||||
|
* with a gain of zero being silence.
|
||||||
|
*
|
||||||
|
* Audio streams default to a gain of 1.0f (no change in output).
|
||||||
|
*
|
||||||
|
* \param stream the SDL_AudioStream to query.
|
||||||
|
* \returns the gain of the stream, or -1.0f on error.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, as it holds
|
||||||
|
* a stream-specific mutex while running.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_SetAudioStreamGain
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC float SDLCALL SDL_GetAudioStreamGain(SDL_AudioStream *stream);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Change the gain of an audio stream.
|
||||||
|
*
|
||||||
|
* The gain of a stream is its volume; a larger gain means a louder output,
|
||||||
|
* with a gain of zero being silence.
|
||||||
|
*
|
||||||
|
* Audio streams default to a gain of 1.0f (no change in output).
|
||||||
|
*
|
||||||
|
* This is applied during SDL_GetAudioStreamData, and can be continuously
|
||||||
|
* changed to create various effects.
|
||||||
|
*
|
||||||
|
* \param stream the stream on which the gain is being changed.
|
||||||
|
* \param gain the gain. 1.0f is no change, 0.0f is silence.
|
||||||
|
* \returns 0 on success, or -1 on error.
|
||||||
|
*
|
||||||
|
* \threadsafety It is safe to call this function from any thread, as it holds
|
||||||
|
* a stream-specific mutex while running.
|
||||||
|
*
|
||||||
|
* \since This function is available since SDL 3.0.0.
|
||||||
|
*
|
||||||
|
* \sa SDL_GetAudioStreamGain
|
||||||
|
*/
|
||||||
|
extern SDL_DECLSPEC int SDLCALL SDL_SetAudioStreamGain(SDL_AudioStream *stream, float gain);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add data to the stream.
|
* Add data to the stream.
|
||||||
*
|
*
|
||||||
@@ -1465,6 +1566,10 @@ extern SDL_DECLSPEC SDL_AudioStream *SDLCALL SDL_OpenAudioDeviceStream(SDL_Audio
|
|||||||
* changed. However, this only covers frequency and channel count; data is
|
* changed. However, this only covers frequency and channel count; data is
|
||||||
* always provided here in SDL_AUDIO_F32 format.
|
* always provided here in SDL_AUDIO_F32 format.
|
||||||
*
|
*
|
||||||
|
* The postmix callback runs _after_ logical device gain and audiostream gain
|
||||||
|
* have been applied, which is to say you can make the output data louder
|
||||||
|
* at this point than the gain settings would suggest.
|
||||||
|
*
|
||||||
* \param userdata a pointer provided by the app through
|
* \param userdata a pointer provided by the app through
|
||||||
* SDL_SetAudioPostmixCallback, for its own use.
|
* SDL_SetAudioPostmixCallback, for its own use.
|
||||||
* \param spec the current format of audio that is to be submitted to the
|
* \param spec the current format of audio that is to be submitted to the
|
||||||
|
@@ -1103,7 +1103,7 @@ SDL_bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
|
|||||||
// We should have updated this elsewhere if the format changed!
|
// We should have updated this elsewhere if the format changed!
|
||||||
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &device->spec));
|
SDL_assert(SDL_AudioSpecsEqual(&stream->dst_spec, &device->spec));
|
||||||
|
|
||||||
const int br = SDL_AtomicGet(&logdev->paused) ? 0 : SDL_GetAudioStreamData(stream, device_buffer, buffer_size);
|
const int br = SDL_AtomicGet(&logdev->paused) ? 0 : SDL_GetAudioStreamDataAdjustGain(stream, device_buffer, buffer_size, logdev->gain);
|
||||||
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
|
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
|
||||||
failed = SDL_TRUE;
|
failed = SDL_TRUE;
|
||||||
SDL_memset(device_buffer, device->silence_value, buffer_size); // just supply silence to the device before we die.
|
SDL_memset(device_buffer, device->silence_value, buffer_size); // just supply silence to the device before we die.
|
||||||
@@ -1143,7 +1143,7 @@ SDL_bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
|
|||||||
for iterating here because the binding linked list can only change while the device lock is held.
|
for iterating here because the binding linked list can only change while the device lock is held.
|
||||||
(we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
|
(we _do_ lock the stream during binding/unbinding to make sure that two threads can't try to bind
|
||||||
the same stream to different devices at the same time, though.) */
|
the same stream to different devices at the same time, though.) */
|
||||||
const int br = SDL_GetAudioStreamData(stream, device->work_buffer, work_buffer_size);
|
const int br = SDL_GetAudioStreamDataAdjustGain(stream, device->work_buffer, work_buffer_size, logdev->gain);
|
||||||
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
|
if (br < 0) { // Probably OOM. Kill the audio device; the whole thing is likely dying soon anyhow.
|
||||||
failed = SDL_TRUE;
|
failed = SDL_TRUE;
|
||||||
break;
|
break;
|
||||||
@@ -1161,8 +1161,8 @@ SDL_bool SDL_PlaybackAudioThreadIterate(SDL_AudioDevice *device)
|
|||||||
|
|
||||||
if (((Uint8 *) final_mix_buffer) != device_buffer) {
|
if (((Uint8 *) final_mix_buffer) != device_buffer) {
|
||||||
// !!! FIXME: we can't promise the device buf is aligned/padded for SIMD.
|
// !!! FIXME: we can't promise the device buf is aligned/padded for SIMD.
|
||||||
//ConvertAudio(needed_samples / device->spec.channels, final_mix_buffer, SDL_AUDIO_F32, device->spec.channels, NULL, device_buffer, device->spec.format, device->spec.channels, NULL, NULL);
|
//ConvertAudio(needed_samples / device->spec.channels, final_mix_buffer, SDL_AUDIO_F32, device->spec.channels, NULL, device_buffer, device->spec.format, device->spec.channels, NULL, NULL, 1.0f);
|
||||||
ConvertAudio(needed_samples / device->spec.channels, final_mix_buffer, SDL_AUDIO_F32, device->spec.channels, NULL, device->work_buffer, device->spec.format, device->spec.channels, NULL, NULL);
|
ConvertAudio(needed_samples / device->spec.channels, final_mix_buffer, SDL_AUDIO_F32, device->spec.channels, NULL, device->work_buffer, device->spec.format, device->spec.channels, NULL, NULL, 1.0f);
|
||||||
SDL_memcpy(device_buffer, device->work_buffer, buffer_size);
|
SDL_memcpy(device_buffer, device->work_buffer, buffer_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1250,7 +1250,7 @@ SDL_bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device)
|
|||||||
void *output_buffer = device->work_buffer;
|
void *output_buffer = device->work_buffer;
|
||||||
|
|
||||||
// I don't know why someone would want a postmix on a recording device, but we offer it for API consistency.
|
// I don't know why someone would want a postmix on a recording device, but we offer it for API consistency.
|
||||||
if (logdev->postmix) {
|
if (logdev->postmix || (logdev->gain != 1.0f)) {
|
||||||
// move to float format.
|
// move to float format.
|
||||||
SDL_AudioSpec outspec;
|
SDL_AudioSpec outspec;
|
||||||
SDL_copyp(&outspec, &device->spec);
|
SDL_copyp(&outspec, &device->spec);
|
||||||
@@ -1258,13 +1258,15 @@ SDL_bool SDL_RecordingAudioThreadIterate(SDL_AudioDevice *device)
|
|||||||
output_buffer = device->postmix_buffer;
|
output_buffer = device->postmix_buffer;
|
||||||
const int frames = br / SDL_AUDIO_FRAMESIZE(device->spec);
|
const int frames = br / SDL_AUDIO_FRAMESIZE(device->spec);
|
||||||
br = frames * SDL_AUDIO_FRAMESIZE(outspec);
|
br = frames * SDL_AUDIO_FRAMESIZE(outspec);
|
||||||
ConvertAudio(frames, device->work_buffer, device->spec.format, outspec.channels, NULL, device->postmix_buffer, SDL_AUDIO_F32, outspec.channels, NULL, NULL);
|
ConvertAudio(frames, device->work_buffer, device->spec.format, outspec.channels, NULL, device->postmix_buffer, SDL_AUDIO_F32, outspec.channels, NULL, NULL, logdev->gain);
|
||||||
logdev->postmix(logdev->postmix_userdata, &outspec, device->postmix_buffer, br);
|
if (logdev->postmix) {
|
||||||
|
logdev->postmix(logdev->postmix_userdata, &outspec, device->postmix_buffer, br);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
|
for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
|
||||||
// We should have updated this elsewhere if the format changed!
|
// We should have updated this elsewhere if the format changed!
|
||||||
SDL_assert(stream->src_spec.format == (logdev->postmix ? SDL_AUDIO_F32 : device->spec.format));
|
SDL_assert(stream->src_spec.format == ((logdev->postmix || (logdev->gain != 1.0f)) ? SDL_AUDIO_F32 : device->spec.format));
|
||||||
SDL_assert(stream->src_spec.channels == device->spec.channels);
|
SDL_assert(stream->src_spec.channels == device->spec.channels);
|
||||||
SDL_assert(stream->src_spec.freq == device->spec.freq);
|
SDL_assert(stream->src_spec.freq == device->spec.freq);
|
||||||
|
|
||||||
@@ -1695,6 +1697,7 @@ SDL_AudioDeviceID SDL_OpenAudioDevice(SDL_AudioDeviceID devid, const SDL_AudioSp
|
|||||||
SDL_AtomicSet(&logdev->paused, 0);
|
SDL_AtomicSet(&logdev->paused, 0);
|
||||||
retval = logdev->instance_id = AssignAudioDeviceInstanceId(device->recording, /*islogical=*/SDL_TRUE);
|
retval = logdev->instance_id = AssignAudioDeviceInstanceId(device->recording, /*islogical=*/SDL_TRUE);
|
||||||
logdev->physical_device = device;
|
logdev->physical_device = device;
|
||||||
|
logdev->gain = 1.0f;
|
||||||
logdev->opened_as_default = wants_default;
|
logdev->opened_as_default = wants_default;
|
||||||
logdev->next = device->logical_devices;
|
logdev->next = device->logical_devices;
|
||||||
if (device->logical_devices) {
|
if (device->logical_devices) {
|
||||||
@@ -1752,6 +1755,44 @@ SDL_bool SDL_AudioDevicePaused(SDL_AudioDeviceID devid)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float SDL_GetAudioDeviceGain(SDL_AudioDeviceID devid)
|
||||||
|
{
|
||||||
|
SDL_AudioDevice *device = NULL;
|
||||||
|
SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid, &device);
|
||||||
|
const float retval = logdev ? logdev->gain : -1.0f;
|
||||||
|
ReleaseAudioDevice(device);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_SetAudioDeviceGain(SDL_AudioDeviceID devid, float gain)
|
||||||
|
{
|
||||||
|
if (gain < 0.0f) {
|
||||||
|
return SDL_InvalidParamError("gain");
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_AudioDevice *device = NULL;
|
||||||
|
SDL_LogicalAudioDevice *logdev = ObtainLogicalAudioDevice(devid, &device);
|
||||||
|
int retval = -1;
|
||||||
|
if (logdev) {
|
||||||
|
logdev->gain = gain;
|
||||||
|
if (device->recording) {
|
||||||
|
const SDL_bool need_float32 = (logdev->postmix || logdev->gain != 1.0f);
|
||||||
|
for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
|
||||||
|
// set the proper end of the stream to the device's format.
|
||||||
|
// SDL_SetAudioStreamFormat does a ton of validation just to memcpy an audiospec.
|
||||||
|
SDL_LockMutex(stream->lock);
|
||||||
|
stream->src_spec.format = need_float32 ? SDL_AUDIO_F32 : device->spec.format;
|
||||||
|
SDL_UnlockMutex(stream->lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAudioStreamFormatsPhysical(device);
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
ReleaseAudioDevice(device);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
int SDL_SetAudioPostmixCallback(SDL_AudioDeviceID devid, SDL_AudioPostmixCallback callback, void *userdata)
|
int SDL_SetAudioPostmixCallback(SDL_AudioDeviceID devid, SDL_AudioPostmixCallback callback, void *userdata)
|
||||||
{
|
{
|
||||||
SDL_AudioDevice *device = NULL;
|
SDL_AudioDevice *device = NULL;
|
||||||
@@ -1770,11 +1811,12 @@ int SDL_SetAudioPostmixCallback(SDL_AudioDeviceID devid, SDL_AudioPostmixCallbac
|
|||||||
logdev->postmix_userdata = userdata;
|
logdev->postmix_userdata = userdata;
|
||||||
|
|
||||||
if (device->recording) {
|
if (device->recording) {
|
||||||
|
const SDL_bool need_float32 = (callback || logdev->gain != 1.0f);
|
||||||
for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
|
for (SDL_AudioStream *stream = logdev->bound_streams; stream; stream = stream->next_binding) {
|
||||||
// set the proper end of the stream to the device's format.
|
// set the proper end of the stream to the device's format.
|
||||||
// SDL_SetAudioStreamFormat does a ton of validation just to memcpy an audiospec.
|
// SDL_SetAudioStreamFormat does a ton of validation just to memcpy an audiospec.
|
||||||
SDL_LockMutex(stream->lock);
|
SDL_LockMutex(stream->lock);
|
||||||
stream->src_spec.format = callback ? SDL_AUDIO_F32 : device->spec.format;
|
stream->src_spec.format = need_float32 ? SDL_AUDIO_F32 : device->spec.format;
|
||||||
SDL_UnlockMutex(stream->lock);
|
SDL_UnlockMutex(stream->lock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -194,10 +194,14 @@ static void SwizzleAudio(const int num_frames, void *dst, const void *src, int c
|
|||||||
//
|
//
|
||||||
// The scratch buffer must be able to store `num_frames * CalculateMaxSampleFrameSize(src_format, src_channels, dst_format, dst_channels)` bytes.
|
// The scratch buffer must be able to store `num_frames * CalculateMaxSampleFrameSize(src_format, src_channels, dst_format, dst_channels)` bytes.
|
||||||
// If the scratch buffer is NULL, this restriction applies to the output buffer instead.
|
// If the scratch buffer is NULL, this restriction applies to the output buffer instead.
|
||||||
|
//
|
||||||
|
// Since this is a convenient point that audio goes through even if it doesn't need format conversion,
|
||||||
|
// we also handle gain adjustment here, so we don't have to make another pass over the data later.
|
||||||
|
// Strictly speaking, this is also a "conversion". :)
|
||||||
void ConvertAudio(int num_frames,
|
void ConvertAudio(int num_frames,
|
||||||
const void *src, SDL_AudioFormat src_format, int src_channels, const Uint8 *src_map,
|
const void *src, SDL_AudioFormat src_format, int src_channels, const Uint8 *src_map,
|
||||||
void *dst, SDL_AudioFormat dst_format, int dst_channels, const Uint8 *dst_map,
|
void *dst, SDL_AudioFormat dst_format, int dst_channels, const Uint8 *dst_map,
|
||||||
void* scratch)
|
void* scratch, float gain)
|
||||||
{
|
{
|
||||||
SDL_assert(src != NULL);
|
SDL_assert(src != NULL);
|
||||||
SDL_assert(dst != NULL);
|
SDL_assert(dst != NULL);
|
||||||
@@ -243,7 +247,7 @@ void ConvertAudio(int num_frames,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// see if we can skip float conversion entirely.
|
// see if we can skip float conversion entirely.
|
||||||
if (src_channels == dst_channels) {
|
if ((src_channels == dst_channels) && (gain == 1.0f)) {
|
||||||
if (src_format == dst_format) {
|
if (src_format == dst_format) {
|
||||||
// nothing to do, we're already in the right format, just copy it over if necessary.
|
// nothing to do, we're already in the right format, just copy it over if necessary.
|
||||||
if (dst_map) {
|
if (dst_map) {
|
||||||
@@ -280,6 +284,23 @@ void ConvertAudio(int num_frames,
|
|||||||
src = buf;
|
src = buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Gain adjustment
|
||||||
|
if (gain != 1.0f) {
|
||||||
|
float *buf = (float *)(dstconvert ? scratch : dst);
|
||||||
|
const int total_samples = num_frames * src_channels;
|
||||||
|
if (src == buf) {
|
||||||
|
for (int i = 0; i < total_samples; i++) {
|
||||||
|
buf[i] *= gain;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
float *fsrc = (float *)src;
|
||||||
|
for (int i = 0; i < total_samples; i++) {
|
||||||
|
buf[i] = fsrc[i] * gain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src = buf;
|
||||||
|
}
|
||||||
|
|
||||||
// Channel conversion
|
// Channel conversion
|
||||||
|
|
||||||
if (channelconvert) {
|
if (channelconvert) {
|
||||||
@@ -379,6 +400,7 @@ SDL_AudioStream *SDL_CreateAudioStream(const SDL_AudioSpec *src_spec, const SDL_
|
|||||||
}
|
}
|
||||||
|
|
||||||
retval->freq_ratio = 1.0f;
|
retval->freq_ratio = 1.0f;
|
||||||
|
retval->gain = 1.0f;
|
||||||
retval->queue = SDL_CreateAudioQueue(8192);
|
retval->queue = SDL_CreateAudioQueue(8192);
|
||||||
|
|
||||||
if (!retval->queue) {
|
if (!retval->queue) {
|
||||||
@@ -593,6 +615,35 @@ int SDL_SetAudioStreamFrequencyRatio(SDL_AudioStream *stream, float freq_ratio)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float SDL_GetAudioStreamGain(SDL_AudioStream *stream)
|
||||||
|
{
|
||||||
|
if (!stream) {
|
||||||
|
SDL_InvalidParamError("stream");
|
||||||
|
return -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LockMutex(stream->lock);
|
||||||
|
const float gain = stream->gain;
|
||||||
|
SDL_UnlockMutex(stream->lock);
|
||||||
|
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SDL_SetAudioStreamGain(SDL_AudioStream *stream, float gain)
|
||||||
|
{
|
||||||
|
if (!stream) {
|
||||||
|
return SDL_InvalidParamError("stream");
|
||||||
|
} else if (gain < 0.0f) {
|
||||||
|
return SDL_InvalidParamError("gain");
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_LockMutex(stream->lock);
|
||||||
|
stream->gain = gain;
|
||||||
|
SDL_UnlockMutex(stream->lock);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int CheckAudioStreamIsFullySetup(SDL_AudioStream *stream)
|
static int CheckAudioStreamIsFullySetup(SDL_AudioStream *stream)
|
||||||
{
|
{
|
||||||
if (stream->src_spec.format == 0) {
|
if (stream->src_spec.format == 0) {
|
||||||
@@ -820,7 +871,7 @@ static Sint64 GetAudioStreamHead(SDL_AudioStream* stream, SDL_AudioSpec* out_spe
|
|||||||
|
|
||||||
// You must hold stream->lock and validate your parameters before calling this!
|
// You must hold stream->lock and validate your parameters before calling this!
|
||||||
// Enough input data MUST be available!
|
// Enough input data MUST be available!
|
||||||
static int GetAudioStreamDataInternal(SDL_AudioStream *stream, void *buf, int output_frames)
|
static int GetAudioStreamDataInternal(SDL_AudioStream *stream, void *buf, int output_frames, float gain)
|
||||||
{
|
{
|
||||||
const SDL_AudioSpec* src_spec = &stream->input_spec;
|
const SDL_AudioSpec* src_spec = &stream->input_spec;
|
||||||
const SDL_AudioSpec* dst_spec = &stream->dst_spec;
|
const SDL_AudioSpec* dst_spec = &stream->dst_spec;
|
||||||
@@ -854,7 +905,7 @@ static int GetAudioStreamDataInternal(SDL_AudioStream *stream, void *buf, int ou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SDL_ReadFromAudioQueue(stream->queue, buf, dst_format, dst_channels, dst_map, 0, output_frames, 0, work_buffer) != buf) {
|
if (SDL_ReadFromAudioQueue(stream->queue, buf, dst_format, dst_channels, dst_map, 0, output_frames, 0, work_buffer, gain) != buf) {
|
||||||
return SDL_SetError("Not enough data in queue");
|
return SDL_SetError("Not enough data in queue");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -919,10 +970,15 @@ static int GetAudioStreamDataInternal(SDL_AudioStream *stream, void *buf, int ou
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// adjust gain either before resampling or after, depending on which point has less
|
||||||
|
// samples to process.
|
||||||
|
const float preresample_gain = (input_frames > output_frames) ? 1.0f : gain;
|
||||||
|
const float postresample_gain = (input_frames > output_frames) ? gain : 1.0f;
|
||||||
|
|
||||||
// (dst channel map is NULL because we'll do the final swizzle on ConvertAudio after resample.)
|
// (dst channel map is NULL because we'll do the final swizzle on ConvertAudio after resample.)
|
||||||
const Uint8* input_buffer = SDL_ReadFromAudioQueue(stream->queue,
|
const Uint8* input_buffer = SDL_ReadFromAudioQueue(stream->queue,
|
||||||
NULL, resample_format, resample_channels, NULL,
|
NULL, resample_format, resample_channels, NULL,
|
||||||
padding_frames, input_frames, padding_frames, work_buffer);
|
padding_frames, input_frames, padding_frames, work_buffer, preresample_gain);
|
||||||
|
|
||||||
if (!input_buffer) {
|
if (!input_buffer) {
|
||||||
return SDL_SetError("Not enough data in queue (resample)");
|
return SDL_SetError("Not enough data in queue (resample)");
|
||||||
@@ -939,13 +995,13 @@ static int GetAudioStreamDataInternal(SDL_AudioStream *stream, void *buf, int ou
|
|||||||
resample_rate, &stream->resample_offset);
|
resample_rate, &stream->resample_offset);
|
||||||
|
|
||||||
// Convert to the final format, if necessary (src channel map is NULL because SDL_ReadFromAudioQueue already handled this).
|
// Convert to the final format, if necessary (src channel map is NULL because SDL_ReadFromAudioQueue already handled this).
|
||||||
ConvertAudio(output_frames, resample_buffer, resample_format, resample_channels, NULL, buf, dst_format, dst_channels, dst_map, work_buffer);
|
ConvertAudio(output_frames, resample_buffer, resample_format, resample_channels, NULL, buf, dst_format, dst_channels, dst_map, work_buffer, postresample_gain);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get converted/resampled data from the stream
|
// get converted/resampled data from the stream
|
||||||
int SDL_GetAudioStreamData(SDL_AudioStream *stream, void *voidbuf, int len)
|
int SDL_GetAudioStreamDataAdjustGain(SDL_AudioStream *stream, void *voidbuf, int len, float extra_gain)
|
||||||
{
|
{
|
||||||
Uint8 *buf = (Uint8 *) voidbuf;
|
Uint8 *buf = (Uint8 *) voidbuf;
|
||||||
|
|
||||||
@@ -970,6 +1026,7 @@ int SDL_GetAudioStreamData(SDL_AudioStream *stream, void *voidbuf, int len)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const float gain = stream->gain * extra_gain;
|
||||||
const int dst_frame_size = SDL_AUDIO_FRAMESIZE(stream->dst_spec);
|
const int dst_frame_size = SDL_AUDIO_FRAMESIZE(stream->dst_spec);
|
||||||
|
|
||||||
len -= len % dst_frame_size; // chop off any fractional sample frame.
|
len -= len % dst_frame_size; // chop off any fractional sample frame.
|
||||||
@@ -1029,7 +1086,7 @@ int SDL_GetAudioStreamData(SDL_AudioStream *stream, void *voidbuf, int len)
|
|||||||
output_frames = SDL_min(output_frames, chunk_size);
|
output_frames = SDL_min(output_frames, chunk_size);
|
||||||
output_frames = (int) SDL_min(output_frames, available_frames);
|
output_frames = (int) SDL_min(output_frames, available_frames);
|
||||||
|
|
||||||
if (GetAudioStreamDataInternal(stream, &buf[total], output_frames) != 0) {
|
if (GetAudioStreamDataInternal(stream, &buf[total], output_frames, gain) != 0) {
|
||||||
total = total ? total : -1;
|
total = total ? total : -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -1046,6 +1103,11 @@ int SDL_GetAudioStreamData(SDL_AudioStream *stream, void *voidbuf, int len)
|
|||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SDL_GetAudioStreamData(SDL_AudioStream *stream, void *voidbuf, int len)
|
||||||
|
{
|
||||||
|
return SDL_GetAudioStreamDataAdjustGain(stream, voidbuf, len, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
// number of converted/resampled bytes available for output
|
// number of converted/resampled bytes available for output
|
||||||
int SDL_GetAudioStreamAvailable(SDL_AudioStream *stream)
|
int SDL_GetAudioStreamAvailable(SDL_AudioStream *stream)
|
||||||
{
|
{
|
||||||
|
@@ -514,7 +514,7 @@ static const Uint8 *PeekIntoAudioQueueFuture(SDL_AudioQueue *queue, Uint8 *data,
|
|||||||
const Uint8 *SDL_ReadFromAudioQueue(SDL_AudioQueue *queue,
|
const Uint8 *SDL_ReadFromAudioQueue(SDL_AudioQueue *queue,
|
||||||
Uint8 *dst, SDL_AudioFormat dst_format, int dst_channels, const Uint8 *dst_map,
|
Uint8 *dst, SDL_AudioFormat dst_format, int dst_channels, const Uint8 *dst_map,
|
||||||
int past_frames, int present_frames, int future_frames,
|
int past_frames, int present_frames, int future_frames,
|
||||||
Uint8 *scratch)
|
Uint8 *scratch, float gain)
|
||||||
{
|
{
|
||||||
SDL_AudioTrack *track = queue->head;
|
SDL_AudioTrack *track = queue->head;
|
||||||
|
|
||||||
@@ -552,7 +552,7 @@ const Uint8 *SDL_ReadFromAudioQueue(SDL_AudioQueue *queue,
|
|||||||
// Do we still need to copy/convert the data?
|
// Do we still need to copy/convert the data?
|
||||||
if (dst) {
|
if (dst) {
|
||||||
ConvertAudio(past_frames + present_frames + future_frames, ptr,
|
ConvertAudio(past_frames + present_frames + future_frames, ptr,
|
||||||
src_format, src_channels, src_map, dst, dst_format, dst_channels, dst_map, scratch);
|
src_format, src_channels, src_map, dst, dst_format, dst_channels, dst_map, scratch, gain);
|
||||||
ptr = dst;
|
ptr = dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,19 +570,19 @@ const Uint8 *SDL_ReadFromAudioQueue(SDL_AudioQueue *queue,
|
|||||||
Uint8 *ptr = dst;
|
Uint8 *ptr = dst;
|
||||||
|
|
||||||
if (src_past_bytes) {
|
if (src_past_bytes) {
|
||||||
ConvertAudio(past_frames, PeekIntoAudioQueuePast(queue, scratch, src_past_bytes), src_format, src_channels, src_map, dst, dst_format, dst_channels, dst_map, scratch);
|
ConvertAudio(past_frames, PeekIntoAudioQueuePast(queue, scratch, src_past_bytes), src_format, src_channels, src_map, dst, dst_format, dst_channels, dst_map, scratch, gain);
|
||||||
dst += dst_past_bytes;
|
dst += dst_past_bytes;
|
||||||
scratch += dst_past_bytes;
|
scratch += dst_past_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_present_bytes) {
|
if (src_present_bytes) {
|
||||||
ConvertAudio(present_frames, ReadFromAudioQueue(queue, scratch, src_present_bytes), src_format, src_channels, src_map, dst, dst_format, dst_channels, dst_map, scratch);
|
ConvertAudio(present_frames, ReadFromAudioQueue(queue, scratch, src_present_bytes), src_format, src_channels, src_map, dst, dst_format, dst_channels, dst_map, scratch, gain);
|
||||||
dst += dst_present_bytes;
|
dst += dst_present_bytes;
|
||||||
scratch += dst_present_bytes;
|
scratch += dst_present_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src_future_bytes) {
|
if (src_future_bytes) {
|
||||||
ConvertAudio(future_frames, PeekIntoAudioQueueFuture(queue, scratch, src_future_bytes), src_format, src_channels, src_map, dst, dst_format, dst_channels, dst_map, scratch);
|
ConvertAudio(future_frames, PeekIntoAudioQueueFuture(queue, scratch, src_future_bytes), src_format, src_channels, src_map, dst, dst_format, dst_channels, dst_map, scratch, gain);
|
||||||
dst += dst_future_bytes;
|
dst += dst_future_bytes;
|
||||||
scratch += dst_future_bytes;
|
scratch += dst_future_bytes;
|
||||||
}
|
}
|
||||||
|
@@ -69,7 +69,7 @@ size_t SDL_NextAudioQueueIter(SDL_AudioQueue *queue, void **inout_iter, SDL_Audi
|
|||||||
const Uint8 *SDL_ReadFromAudioQueue(SDL_AudioQueue *queue,
|
const Uint8 *SDL_ReadFromAudioQueue(SDL_AudioQueue *queue,
|
||||||
Uint8 *dst, SDL_AudioFormat dst_format, int dst_channels, const Uint8 *dst_map,
|
Uint8 *dst, SDL_AudioFormat dst_format, int dst_channels, const Uint8 *dst_map,
|
||||||
int past_frames, int present_frames, int future_frames,
|
int past_frames, int present_frames, int future_frames,
|
||||||
Uint8 *scratch);
|
Uint8 *scratch, float gain);
|
||||||
|
|
||||||
// Get the total number of bytes currently queued
|
// Get the total number of bytes currently queued
|
||||||
size_t SDL_GetAudioQueueQueued(SDL_AudioQueue *queue);
|
size_t SDL_GetAudioQueueQueued(SDL_AudioQueue *queue);
|
||||||
|
@@ -118,17 +118,19 @@ extern SDL_bool SDL_ChannelMapIsBogus(const Uint8 *map, int channels);
|
|||||||
extern void ConvertAudio(int num_frames,
|
extern void ConvertAudio(int num_frames,
|
||||||
const void *src, SDL_AudioFormat src_format, int src_channels, const Uint8 *src_map,
|
const void *src, SDL_AudioFormat src_format, int src_channels, const Uint8 *src_map,
|
||||||
void *dst, SDL_AudioFormat dst_format, int dst_channels, const Uint8 *dst_map,
|
void *dst, SDL_AudioFormat dst_format, int dst_channels, const Uint8 *dst_map,
|
||||||
void* scratch);
|
void* scratch, float gain);
|
||||||
|
|
||||||
// Compare two SDL_AudioSpecs, return SDL_TRUE if they match exactly.
|
// Compare two SDL_AudioSpecs, return SDL_TRUE if they match exactly.
|
||||||
// Using SDL_memcmp directly isn't safe, since potential padding (and unused parts of the channel map) might not be initialized.
|
// Using SDL_memcmp directly isn't safe, since potential padding (and unused parts of the channel map) might not be initialized.
|
||||||
extern SDL_bool SDL_AudioSpecsEqual(const SDL_AudioSpec *a, const SDL_AudioSpec *b);
|
extern SDL_bool SDL_AudioSpecsEqual(const SDL_AudioSpec *a, const SDL_AudioSpec *b);
|
||||||
|
|
||||||
|
|
||||||
// Special case to let something in SDL_audiocvt.c access something in SDL_audio.c. Don't use this.
|
// Special case to let something in SDL_audiocvt.c access something in SDL_audio.c. Don't use this.
|
||||||
extern void OnAudioStreamCreated(SDL_AudioStream *stream);
|
extern void OnAudioStreamCreated(SDL_AudioStream *stream);
|
||||||
extern void OnAudioStreamDestroy(SDL_AudioStream *stream);
|
extern void OnAudioStreamDestroy(SDL_AudioStream *stream);
|
||||||
|
|
||||||
|
// This just lets audio playback apply logical device gain at the same time as audiostream gain, so it's one multiplication instead of thousands.
|
||||||
|
extern int SDL_GetAudioStreamDataAdjustGain(SDL_AudioStream *stream, void *voidbuf, int len, float extra_gain);
|
||||||
|
|
||||||
typedef struct SDL_AudioDriverImpl
|
typedef struct SDL_AudioDriverImpl
|
||||||
{
|
{
|
||||||
void (*DetectDevices)(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording);
|
void (*DetectDevices)(SDL_AudioDevice **default_playback, SDL_AudioDevice **default_recording);
|
||||||
@@ -196,6 +198,7 @@ struct SDL_AudioStream
|
|||||||
SDL_AudioSpec src_spec;
|
SDL_AudioSpec src_spec;
|
||||||
SDL_AudioSpec dst_spec;
|
SDL_AudioSpec dst_spec;
|
||||||
float freq_ratio;
|
float freq_ratio;
|
||||||
|
float gain;
|
||||||
|
|
||||||
struct SDL_AudioQueue* queue;
|
struct SDL_AudioQueue* queue;
|
||||||
|
|
||||||
@@ -230,6 +233,9 @@ struct SDL_LogicalAudioDevice
|
|||||||
// If whole logical device is paused (process no streams bound to this device).
|
// If whole logical device is paused (process no streams bound to this device).
|
||||||
SDL_AtomicInt paused;
|
SDL_AtomicInt paused;
|
||||||
|
|
||||||
|
// Volume of the device output.
|
||||||
|
float gain;
|
||||||
|
|
||||||
// double-linked list of all audio streams currently bound to this opened device.
|
// double-linked list of all audio streams currently bound to this opened device.
|
||||||
SDL_AudioStream *bound_streams;
|
SDL_AudioStream *bound_streams;
|
||||||
|
|
||||||
|
@@ -167,6 +167,7 @@ SDL3_0.0.0 {
|
|||||||
SDL_GetAssertionHandler;
|
SDL_GetAssertionHandler;
|
||||||
SDL_GetAssertionReport;
|
SDL_GetAssertionReport;
|
||||||
SDL_GetAudioDeviceFormat;
|
SDL_GetAudioDeviceFormat;
|
||||||
|
SDL_GetAudioDeviceGain;
|
||||||
SDL_GetAudioDeviceName;
|
SDL_GetAudioDeviceName;
|
||||||
SDL_GetAudioDriver;
|
SDL_GetAudioDriver;
|
||||||
SDL_GetAudioPlaybackDevices;
|
SDL_GetAudioPlaybackDevices;
|
||||||
@@ -176,6 +177,7 @@ SDL3_0.0.0 {
|
|||||||
SDL_GetAudioStreamDevice;
|
SDL_GetAudioStreamDevice;
|
||||||
SDL_GetAudioStreamFormat;
|
SDL_GetAudioStreamFormat;
|
||||||
SDL_GetAudioStreamFrequencyRatio;
|
SDL_GetAudioStreamFrequencyRatio;
|
||||||
|
SDL_GetAudioStreamGain;
|
||||||
SDL_GetAudioStreamProperties;
|
SDL_GetAudioStreamProperties;
|
||||||
SDL_GetAudioStreamQueued;
|
SDL_GetAudioStreamQueued;
|
||||||
SDL_GetBasePath;
|
SDL_GetBasePath;
|
||||||
@@ -682,9 +684,11 @@ SDL3_0.0.0 {
|
|||||||
SDL_SendJoystickEffect;
|
SDL_SendJoystickEffect;
|
||||||
SDL_SendJoystickVirtualSensorData;
|
SDL_SendJoystickVirtualSensorData;
|
||||||
SDL_SetAssertionHandler;
|
SDL_SetAssertionHandler;
|
||||||
|
SDL_SetAudioDeviceGain;
|
||||||
SDL_SetAudioPostmixCallback;
|
SDL_SetAudioPostmixCallback;
|
||||||
SDL_SetAudioStreamFormat;
|
SDL_SetAudioStreamFormat;
|
||||||
SDL_SetAudioStreamFrequencyRatio;
|
SDL_SetAudioStreamFrequencyRatio;
|
||||||
|
SDL_SetAudioStreamGain;
|
||||||
SDL_SetAudioStreamGetCallback;
|
SDL_SetAudioStreamGetCallback;
|
||||||
SDL_SetAudioStreamPutCallback;
|
SDL_SetAudioStreamPutCallback;
|
||||||
SDL_SetBooleanProperty;
|
SDL_SetBooleanProperty;
|
||||||
|
@@ -191,6 +191,7 @@
|
|||||||
#define SDL_GetAndroidSDKVersion SDL_GetAndroidSDKVersion_REAL
|
#define SDL_GetAndroidSDKVersion SDL_GetAndroidSDKVersion_REAL
|
||||||
#define SDL_GetAssertionHandler SDL_GetAssertionHandler_REAL
|
#define SDL_GetAssertionHandler SDL_GetAssertionHandler_REAL
|
||||||
#define SDL_GetAssertionReport SDL_GetAssertionReport_REAL
|
#define SDL_GetAssertionReport SDL_GetAssertionReport_REAL
|
||||||
|
#define SDL_GetAudioDeviceGain SDL_GetAudioDeviceGain_REAL
|
||||||
#define SDL_GetAudioDeviceFormat SDL_GetAudioDeviceFormat_REAL
|
#define SDL_GetAudioDeviceFormat SDL_GetAudioDeviceFormat_REAL
|
||||||
#define SDL_GetAudioDeviceName SDL_GetAudioDeviceName_REAL
|
#define SDL_GetAudioDeviceName SDL_GetAudioDeviceName_REAL
|
||||||
#define SDL_GetAudioDriver SDL_GetAudioDriver_REAL
|
#define SDL_GetAudioDriver SDL_GetAudioDriver_REAL
|
||||||
@@ -201,6 +202,7 @@
|
|||||||
#define SDL_GetAudioStreamDevice SDL_GetAudioStreamDevice_REAL
|
#define SDL_GetAudioStreamDevice SDL_GetAudioStreamDevice_REAL
|
||||||
#define SDL_GetAudioStreamFormat SDL_GetAudioStreamFormat_REAL
|
#define SDL_GetAudioStreamFormat SDL_GetAudioStreamFormat_REAL
|
||||||
#define SDL_GetAudioStreamFrequencyRatio SDL_GetAudioStreamFrequencyRatio_REAL
|
#define SDL_GetAudioStreamFrequencyRatio SDL_GetAudioStreamFrequencyRatio_REAL
|
||||||
|
#define SDL_GetAudioStreamGain SDL_GetAudioStreamGain_REAL
|
||||||
#define SDL_GetAudioStreamProperties SDL_GetAudioStreamProperties_REAL
|
#define SDL_GetAudioStreamProperties SDL_GetAudioStreamProperties_REAL
|
||||||
#define SDL_GetAudioStreamQueued SDL_GetAudioStreamQueued_REAL
|
#define SDL_GetAudioStreamQueued SDL_GetAudioStreamQueued_REAL
|
||||||
#define SDL_GetBasePath SDL_GetBasePath_REAL
|
#define SDL_GetBasePath SDL_GetBasePath_REAL
|
||||||
@@ -707,9 +709,11 @@
|
|||||||
#define SDL_SendJoystickEffect SDL_SendJoystickEffect_REAL
|
#define SDL_SendJoystickEffect SDL_SendJoystickEffect_REAL
|
||||||
#define SDL_SendJoystickVirtualSensorData SDL_SendJoystickVirtualSensorData_REAL
|
#define SDL_SendJoystickVirtualSensorData SDL_SendJoystickVirtualSensorData_REAL
|
||||||
#define SDL_SetAssertionHandler SDL_SetAssertionHandler_REAL
|
#define SDL_SetAssertionHandler SDL_SetAssertionHandler_REAL
|
||||||
|
#define SDL_SetAudioDeviceGain SDL_SetAudioDeviceGain_REAL
|
||||||
#define SDL_SetAudioPostmixCallback SDL_SetAudioPostmixCallback_REAL
|
#define SDL_SetAudioPostmixCallback SDL_SetAudioPostmixCallback_REAL
|
||||||
#define SDL_SetAudioStreamFormat SDL_SetAudioStreamFormat_REAL
|
#define SDL_SetAudioStreamFormat SDL_SetAudioStreamFormat_REAL
|
||||||
#define SDL_SetAudioStreamFrequencyRatio SDL_SetAudioStreamFrequencyRatio_REAL
|
#define SDL_SetAudioStreamFrequencyRatio SDL_SetAudioStreamFrequencyRatio_REAL
|
||||||
|
#define SDL_SetAudioStreamGain SDL_SetAudioStreamGain_REAL
|
||||||
#define SDL_SetAudioStreamGetCallback SDL_SetAudioStreamGetCallback_REAL
|
#define SDL_SetAudioStreamGetCallback SDL_SetAudioStreamGetCallback_REAL
|
||||||
#define SDL_SetAudioStreamPutCallback SDL_SetAudioStreamPutCallback_REAL
|
#define SDL_SetAudioStreamPutCallback SDL_SetAudioStreamPutCallback_REAL
|
||||||
#define SDL_SetBooleanProperty SDL_SetBooleanProperty_REAL
|
#define SDL_SetBooleanProperty SDL_SetBooleanProperty_REAL
|
||||||
|
@@ -212,6 +212,7 @@ SDL_DYNAPI_PROC(int,SDL_GetAndroidSDKVersion,(void),(),return)
|
|||||||
SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetAssertionHandler,(void **a),(a),return)
|
SDL_DYNAPI_PROC(SDL_AssertionHandler,SDL_GetAssertionHandler,(void **a),(a),return)
|
||||||
SDL_DYNAPI_PROC(const SDL_AssertData*,SDL_GetAssertionReport,(void),(),return)
|
SDL_DYNAPI_PROC(const SDL_AssertData*,SDL_GetAssertionReport,(void),(),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceFormat,(SDL_AudioDeviceID a, SDL_AudioSpec *b, int *c),(a,b,c),return)
|
SDL_DYNAPI_PROC(int,SDL_GetAudioDeviceFormat,(SDL_AudioDeviceID a, SDL_AudioSpec *b, int *c),(a,b,c),return)
|
||||||
|
SDL_DYNAPI_PROC(float,SDL_GetAudioDeviceGain,(SDL_AudioDeviceID a),(a),return)
|
||||||
SDL_DYNAPI_PROC(const char*,SDL_GetAudioDeviceName,(SDL_AudioDeviceID a),(a),return)
|
SDL_DYNAPI_PROC(const char*,SDL_GetAudioDeviceName,(SDL_AudioDeviceID a),(a),return)
|
||||||
SDL_DYNAPI_PROC(const char*,SDL_GetAudioDriver,(int a),(a),return)
|
SDL_DYNAPI_PROC(const char*,SDL_GetAudioDriver,(int a),(a),return)
|
||||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioPlaybackDevices,(int *a),(a),return)
|
SDL_DYNAPI_PROC(SDL_AudioDeviceID*,SDL_GetAudioPlaybackDevices,(int *a),(a),return)
|
||||||
@@ -221,6 +222,7 @@ SDL_DYNAPI_PROC(int,SDL_GetAudioStreamData,(SDL_AudioStream *a, void *b, int c),
|
|||||||
SDL_DYNAPI_PROC(SDL_AudioDeviceID,SDL_GetAudioStreamDevice,(SDL_AudioStream *a),(a),return)
|
SDL_DYNAPI_PROC(SDL_AudioDeviceID,SDL_GetAudioStreamDevice,(SDL_AudioStream *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioSpec *b, SDL_AudioSpec *c),(a,b,c),return)
|
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamFormat,(SDL_AudioStream *a, SDL_AudioSpec *b, SDL_AudioSpec *c),(a,b,c),return)
|
||||||
SDL_DYNAPI_PROC(float,SDL_GetAudioStreamFrequencyRatio,(SDL_AudioStream *a),(a),return)
|
SDL_DYNAPI_PROC(float,SDL_GetAudioStreamFrequencyRatio,(SDL_AudioStream *a),(a),return)
|
||||||
|
SDL_DYNAPI_PROC(float,SDL_GetAudioStreamGain,(SDL_AudioStream *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetAudioStreamProperties,(SDL_AudioStream *a),(a),return)
|
SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetAudioStreamProperties,(SDL_AudioStream *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamQueued,(SDL_AudioStream *a),(a),return)
|
SDL_DYNAPI_PROC(int,SDL_GetAudioStreamQueued,(SDL_AudioStream *a),(a),return)
|
||||||
SDL_DYNAPI_PROC(char*,SDL_GetBasePath,(void),(),return)
|
SDL_DYNAPI_PROC(char*,SDL_GetBasePath,(void),(),return)
|
||||||
@@ -718,9 +720,11 @@ SDL_DYNAPI_PROC(int,SDL_SendGamepadEffect,(SDL_Gamepad *a, const void *b, int c)
|
|||||||
SDL_DYNAPI_PROC(int,SDL_SendJoystickEffect,(SDL_Joystick *a, const void *b, int c),(a,b,c),return)
|
SDL_DYNAPI_PROC(int,SDL_SendJoystickEffect,(SDL_Joystick *a, const void *b, int c),(a,b,c),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SendJoystickVirtualSensorData,(SDL_Joystick *a, SDL_SensorType b, Uint64 c, const float *d, int e),(a,b,c,d,e),return)
|
SDL_DYNAPI_PROC(int,SDL_SendJoystickVirtualSensorData,(SDL_Joystick *a, SDL_SensorType b, Uint64 c, const float *d, int e),(a,b,c,d,e),return)
|
||||||
SDL_DYNAPI_PROC(void,SDL_SetAssertionHandler,(SDL_AssertionHandler a, void *b),(a,b),)
|
SDL_DYNAPI_PROC(void,SDL_SetAssertionHandler,(SDL_AssertionHandler a, void *b),(a,b),)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_SetAudioDeviceGain,(SDL_AudioDeviceID a, float b),(a,b),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SetAudioPostmixCallback,(SDL_AudioDeviceID a, SDL_AudioPostmixCallback b, void *c),(a,b,c),return)
|
SDL_DYNAPI_PROC(int,SDL_SetAudioPostmixCallback,(SDL_AudioDeviceID a, SDL_AudioPostmixCallback b, void *c),(a,b,c),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFormat,(SDL_AudioStream *a, const SDL_AudioSpec *b, const SDL_AudioSpec *c),(a,b,c),return)
|
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFormat,(SDL_AudioStream *a, const SDL_AudioSpec *b, const SDL_AudioSpec *c),(a,b,c),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFrequencyRatio,(SDL_AudioStream *a, float b),(a,b),return)
|
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamFrequencyRatio,(SDL_AudioStream *a, float b),(a,b),return)
|
||||||
|
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamGain,(SDL_AudioStream *a, float b),(a,b),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamGetCallback,(SDL_AudioStream *a, SDL_AudioStreamCallback b, void *c),(a,b,c),return)
|
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamGetCallback,(SDL_AudioStream *a, SDL_AudioStreamCallback b, void *c),(a,b,c),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamPutCallback,(SDL_AudioStream *a, SDL_AudioStreamCallback b, void *c),(a,b,c),return)
|
SDL_DYNAPI_PROC(int,SDL_SetAudioStreamPutCallback,(SDL_AudioStream *a, SDL_AudioStreamCallback b, void *c),(a,b,c),return)
|
||||||
SDL_DYNAPI_PROC(int,SDL_SetBooleanProperty,(SDL_PropertiesID a, const char *b, SDL_bool c),(a,b,c),return)
|
SDL_DYNAPI_PROC(int,SDL_SetBooleanProperty,(SDL_PropertiesID a, const char *b, SDL_bool c),(a,b,c),return)
|
||||||
|
@@ -94,6 +94,7 @@ struct Thing
|
|||||||
float z;
|
float z;
|
||||||
Uint8 r, g, b, a;
|
Uint8 r, g, b, a;
|
||||||
float progress;
|
float progress;
|
||||||
|
float meter;
|
||||||
float scale;
|
float scale;
|
||||||
Uint64 createticks;
|
Uint64 createticks;
|
||||||
Texture *texture;
|
Texture *texture;
|
||||||
@@ -103,6 +104,7 @@ struct Thing
|
|||||||
void (*ondrag)(Thing *thing, int button, float x, float y);
|
void (*ondrag)(Thing *thing, int button, float x, float y);
|
||||||
void (*ondrop)(Thing *thing, int button, float x, float y);
|
void (*ondrop)(Thing *thing, int button, float x, float y);
|
||||||
void (*ondraw)(Thing *thing, SDL_Renderer *renderer);
|
void (*ondraw)(Thing *thing, SDL_Renderer *renderer);
|
||||||
|
void (*onmousewheel)(Thing *thing, float y);
|
||||||
|
|
||||||
Thing *prev;
|
Thing *prev;
|
||||||
Thing *next;
|
Thing *next;
|
||||||
@@ -355,6 +357,16 @@ static void DrawOneThing(SDL_Renderer *renderer, Thing *thing)
|
|||||||
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 128);
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 128);
|
||||||
SDL_RenderFillRect(renderer, &r);
|
SDL_RenderFillRect(renderer, &r);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (thing->meter > 0.0f) {
|
||||||
|
SDL_FRect r;
|
||||||
|
r.w = 10.0f;
|
||||||
|
r.h = thing->rect.h * ((thing->meter > 1.0f) ? 1.0f : thing->meter);
|
||||||
|
r.x = thing->rect.x + thing->rect.w + 2.0f;
|
||||||
|
r.y = (thing->rect.y + thing->rect.h) - r.h;
|
||||||
|
SDL_SetRenderDrawColor(renderer, 255, 255, 255, 128);
|
||||||
|
SDL_RenderFillRect(renderer, &r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawThings(SDL_Renderer *renderer)
|
static void DrawThings(SDL_Renderer *renderer)
|
||||||
@@ -581,6 +593,13 @@ static void StreamThing_ondrop(Thing *thing, int button, float x, float y)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void StreamThing_onmousewheel(Thing *thing, float y)
|
||||||
|
{
|
||||||
|
thing->meter += y * 0.01f;
|
||||||
|
thing->meter = SDL_clamp(thing->meter, 0.0f, 1.0f);
|
||||||
|
SDL_SetAudioStreamGain(thing->data.stream.stream, thing->meter);
|
||||||
|
}
|
||||||
|
|
||||||
static void StreamThing_ondraw(Thing *thing, SDL_Renderer *renderer)
|
static void StreamThing_ondraw(Thing *thing, SDL_Renderer *renderer)
|
||||||
{
|
{
|
||||||
if (thing->line_connected_to) { /* are we playing? Update progress bar, and bounce the levels a little. */
|
if (thing->line_connected_to) { /* are we playing? Update progress bar, and bounce the levels a little. */
|
||||||
@@ -618,7 +637,9 @@ static Thing *CreateStreamThing(const SDL_AudioSpec *spec, const Uint8 *buf, con
|
|||||||
thing->ondrag = StreamThing_ondrag;
|
thing->ondrag = StreamThing_ondrag;
|
||||||
thing->ondrop = StreamThing_ondrop;
|
thing->ondrop = StreamThing_ondrop;
|
||||||
thing->ondraw = StreamThing_ondraw;
|
thing->ondraw = StreamThing_ondraw;
|
||||||
|
thing->onmousewheel = StreamThing_onmousewheel;
|
||||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||||
|
thing->meter = 1.0f; /* gain. */
|
||||||
}
|
}
|
||||||
return thing;
|
return thing;
|
||||||
}
|
}
|
||||||
@@ -898,6 +919,13 @@ static void LogicalDeviceThing_ondraw(Thing *thing, SDL_Renderer *renderer)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void LogicalDeviceThing_onmousewheel(Thing *thing, float y)
|
||||||
|
{
|
||||||
|
thing->meter += y * 0.01f;
|
||||||
|
thing->meter = SDL_clamp(thing->meter, 0.0f, 1.0f);
|
||||||
|
SDL_SetAudioDeviceGain(thing->data.logdev.devid, thing->meter);
|
||||||
|
}
|
||||||
|
|
||||||
static Thing *CreateLogicalDeviceThing(Thing *parent, const SDL_AudioDeviceID which, const float x, const float y)
|
static Thing *CreateLogicalDeviceThing(Thing *parent, const SDL_AudioDeviceID which, const float x, const float y)
|
||||||
{
|
{
|
||||||
static const ThingType can_be_dropped_onto[] = { THING_TRASHCAN, THING_NULL };
|
static const ThingType can_be_dropped_onto[] = { THING_TRASHCAN, THING_NULL };
|
||||||
@@ -917,10 +945,12 @@ static Thing *CreateLogicalDeviceThing(Thing *parent, const SDL_AudioDeviceID wh
|
|||||||
SDL_SetTextureBlendMode(thing->data.logdev.visualizer, SDL_BLENDMODE_BLEND);
|
SDL_SetTextureBlendMode(thing->data.logdev.visualizer, SDL_BLENDMODE_BLEND);
|
||||||
}
|
}
|
||||||
thing->line_connected_to = physthing;
|
thing->line_connected_to = physthing;
|
||||||
|
thing->meter = 1.0f;
|
||||||
thing->ontick = LogicalDeviceThing_ontick;
|
thing->ontick = LogicalDeviceThing_ontick;
|
||||||
thing->ondrag = DeviceThing_ondrag;
|
thing->ondrag = DeviceThing_ondrag;
|
||||||
thing->ondrop = LogicalDeviceThing_ondrop;
|
thing->ondrop = LogicalDeviceThing_ondrop;
|
||||||
thing->ondraw = LogicalDeviceThing_ondraw;
|
thing->ondraw = LogicalDeviceThing_ondraw;
|
||||||
|
thing->onmousewheel = LogicalDeviceThing_onmousewheel;
|
||||||
thing->can_be_dropped_onto = can_be_dropped_onto;
|
thing->can_be_dropped_onto = can_be_dropped_onto;
|
||||||
|
|
||||||
SetLogicalDeviceTitlebar(thing);
|
SetLogicalDeviceTitlebar(thing);
|
||||||
@@ -1181,7 +1211,10 @@ int SDL_AppEvent(void *appstate, const SDL_Event *event)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_MOUSE_WHEEL:
|
case SDL_EVENT_MOUSE_WHEEL:
|
||||||
UpdateMouseOver(event->wheel.mouse_x, event->wheel.mouse_y);
|
thing = UpdateMouseOver(event->wheel.mouse_x, event->wheel.mouse_y);
|
||||||
|
if (thing && thing->onmousewheel) {
|
||||||
|
thing->onmousewheel(thing, event->wheel.y * ((event->wheel.direction == SDL_MOUSEWHEEL_FLIPPED) ? -1.0f : 1.0f));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_EVENT_KEY_DOWN:
|
case SDL_EVENT_KEY_DOWN:
|
||||||
|
Reference in New Issue
Block a user