mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-12 17:17:09 -04:00
WIP on adding speed/rate argument when playing sounds instead
This commit is contained in:
parent
6e433e5585
commit
97fcc429bf
103
src/Audio.c
103
src/Audio.c
@ -54,8 +54,8 @@ static void AudioWarn(cc_result res, const char* action) {
|
|||||||
Logger_Warn(res, action, Audio_DescribeError);
|
Logger_Warn(res, action, Audio_DescribeError);
|
||||||
}
|
}
|
||||||
static void AudioBase_Clear(struct AudioContext* ctx);
|
static void AudioBase_Clear(struct AudioContext* ctx);
|
||||||
static void* AudioBase_AdjustSound(struct AudioContext* ctx, struct Sound* snd, int volume);
|
static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, struct AudioData* data);
|
||||||
static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct Sound* snd, void* data);
|
static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct AudioData* data);
|
||||||
|
|
||||||
|
|
||||||
#if defined CC_BUILD_OPENAL
|
#if defined CC_BUILD_OPENAL
|
||||||
@ -289,14 +289,14 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) {
|
|||||||
*inUse = ctx->count - ctx->free; return 0;
|
*inUse = ctx->count - ctx->free; return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) {
|
cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) {
|
||||||
/* Channels/Sample rate is per buffer, not a per source property */
|
/* Channels/Sample rate is per buffer, not a per source property */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) {
|
cc_result Audio_PlayData(struct AudioContext* ctx, struct Sound* snd, int volume) {
|
||||||
void* data = AudioBase_AdjustSound(ctx, snd, volume);
|
cc_book ok = AudioBase_AdjustSound(ctx, snd, volume);
|
||||||
if (data) return AudioBase_PlaySound(ctx, snd, data);
|
if (ok) return AudioBase_PlaySound(ctx, snd, data);
|
||||||
return ERR_OUT_OF_MEMORY;
|
return ERR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,15 +477,21 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) {
|
|||||||
|
|
||||||
*inUse = count; return res;
|
*inUse = count; return res;
|
||||||
}
|
}
|
||||||
|
/* achieve higher speed by playing samples at higher sample rate */
|
||||||
|
#define Audio_AdjustSampleRate(data) ((data->sampleRate * data->rate) / 100)
|
||||||
|
|
||||||
cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) {
|
cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) {
|
||||||
|
int channels = data->channels;
|
||||||
|
int sampleRate = Audio_AdjustSampleRate(data);
|
||||||
return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate);
|
return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) {
|
cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data) {
|
||||||
void* data = AudioBase_AdjustSound(ctx, snd, volume);
|
cc_bool ok = AudioBase_AdjustSound(ctx, data);
|
||||||
if (data) return AudioBase_PlaySound(ctx, snd, data);
|
if (!ok) return ERR_OUT_OF_MEMORY;
|
||||||
return ERR_OUT_OF_MEMORY;
|
|
||||||
|
data->sampleRate = Audio_AdjustSampleRate(data);
|
||||||
|
return AudioBase_PlaySound(ctx, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_bool Audio_DescribeError(cc_result res, cc_string* dst) {
|
cc_bool Audio_DescribeError(cc_result res, cc_string* dst) {
|
||||||
@ -684,9 +690,9 @@ cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) {
|
|||||||
return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate);
|
return !ctx->channels || (ctx->channels == channels && ctx->sampleRate == sampleRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) {
|
cc_result Audio_PlayData(struct AudioContext* ctx, struct Sound* snd, int volume) {
|
||||||
void* data = AudioBase_AdjustSound(ctx, snd, volume);
|
cc_bool ok = AudioBase_AdjustSound(ctx, snd, volume);
|
||||||
if (data) return AudioBase_PlaySound(ctx, snd, data);
|
if (ok) return AudioBase_PlaySound(ctx, snd, data);
|
||||||
return ERR_OUT_OF_MEMORY;
|
return ERR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -756,12 +762,12 @@ cc_result Audio_Poll(struct AudioContext* ctx, int* inUse) {
|
|||||||
*inUse = 0; return 0;
|
*inUse = 0; return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate) {
|
cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data) {
|
||||||
/* Channels/Sample rate is per buffer, not a per source property */
|
/* Channels/Sample rate is per buffer, not a per source property */
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume) {
|
cc_result Audio_PlayData(struct AudioContext* ctx, struct Sound* snd, int volume) {
|
||||||
if (!ctx->contextID)
|
if (!ctx->contextID)
|
||||||
ctx->contextID = interop_AudioCreate();
|
ctx->contextID = interop_AudioCreate();
|
||||||
return interop_AudioPlay(ctx->contextID, snd, volume);
|
return interop_AudioPlay(ctx->contextID, snd, volume);
|
||||||
@ -792,34 +798,35 @@ static void AudioBase_Clear(struct AudioContext* ctx) {
|
|||||||
ctx->_tmpSize = 0;
|
ctx->_tmpSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void* AudioBase_AdjustSound(struct AudioContext* ctx, struct Sound* snd, int volume) {
|
static cc_bool AudioBase_AdjustSound(struct AudioContext* ctx, struct AudioData* data) {
|
||||||
void* data;
|
void* audio;
|
||||||
if (volume >= 100) return snd->data;
|
if (data->volume >= 100) return true;
|
||||||
|
|
||||||
/* copy to temp buffer to apply volume */
|
/* copy to temp buffer to apply volume */
|
||||||
if (ctx->_tmpSize < snd->size) {
|
if (ctx->_tmpSize < data->size) {
|
||||||
/* TODO: check if we can realloc NULL without a problem */
|
/* TODO: check if we can realloc NULL without a problem */
|
||||||
if (ctx->_tmpData) {
|
if (ctx->_tmpData) {
|
||||||
data = Mem_TryRealloc(ctx->_tmpData, snd->size, 1);
|
audio = Mem_TryRealloc(ctx->_tmpData, data->size, 1);
|
||||||
} else {
|
} else {
|
||||||
data = Mem_TryAlloc(snd->size, 1);
|
audio = Mem_TryAlloc(data->size, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!data) return NULL;
|
if (!data) return false;
|
||||||
ctx->_tmpData = data;
|
ctx->_tmpData = audio;
|
||||||
ctx->_tmpSize = snd->size;
|
ctx->_tmpSize = data->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
data = ctx->_tmpData;
|
audio = ctx->_tmpData;
|
||||||
Mem_Copy(data, snd->data, snd->size);
|
Mem_Copy(audio, data->data, data->size);
|
||||||
ApplyVolume((cc_int16*)data, snd->size / 2, volume);
|
ApplyVolume((cc_int16*)audio, data->size / 2, data->volume);
|
||||||
return data;
|
data->data = audio;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct Sound* snd, void* data) {
|
static cc_result AudioBase_PlaySound(struct AudioContext* ctx, struct AudioData* data) {
|
||||||
cc_result res;
|
cc_result res;
|
||||||
if ((res = Audio_SetFormat(ctx, snd->channels, snd->sampleRate))) return res;
|
if ((res = Audio_SetFormat(ctx, data->channels, data->sampleRate))) return res;
|
||||||
if ((res = Audio_QueueData(ctx, data, snd->size))) return res;
|
if ((res = Audio_QueueData(ctx, data->data, data->size))) return res;
|
||||||
if ((res = Audio_Play(ctx))) return res;
|
if ((res = Audio_Play(ctx))) return res;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -980,27 +987,31 @@ CC_NOINLINE static void Sounds_Fail(cc_result res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void Sounds_Play(cc_uint8 type, struct Soundboard* board) {
|
static void Sounds_Play(cc_uint8 type, struct Soundboard* board) {
|
||||||
const struct Sound* snd_;
|
struct AudioData data;
|
||||||
struct Sound snd;
|
const struct Sound* snd;
|
||||||
struct AudioContext* ctx;
|
struct AudioContext* ctx;
|
||||||
int inUse, i, volume;
|
int inUse, i;
|
||||||
cc_result res;
|
cc_result res;
|
||||||
|
|
||||||
if (type == SOUND_NONE || !Audio_SoundsVolume) return;
|
if (type == SOUND_NONE || !Audio_SoundsVolume) return;
|
||||||
snd_ = Soundboard_PickRandom(board, type);
|
snd = Soundboard_PickRandom(board, type);
|
||||||
if (!snd_) return;
|
if (!snd) return;
|
||||||
|
|
||||||
snd = *snd_;
|
data.data = snd->data;
|
||||||
volume = Audio_SoundsVolume;
|
data.size = snd->size;
|
||||||
|
data.channels = snd->channels;
|
||||||
|
data.sampleRate = snd->sampleRate;
|
||||||
|
data.rate = 100;
|
||||||
|
data.volume = Audio_SoundsVolume;
|
||||||
|
|
||||||
/* https://minecraft.fandom.com/wiki/Block_of_Gold#Sounds */
|
/* https://minecraft.fandom.com/wiki/Block_of_Gold#Sounds */
|
||||||
/* https://minecraft.fandom.com/wiki/Grass#Sounds */
|
/* https://minecraft.fandom.com/wiki/Grass#Sounds */
|
||||||
if (board == &digBoard) {
|
if (board == &digBoard) {
|
||||||
if (type == SOUND_METAL) snd.sampleRate = (snd.sampleRate * 6) / 5;
|
if (type == SOUND_METAL) data.rate = 120;
|
||||||
else snd.sampleRate = (snd.sampleRate * 4) / 5;
|
else data.rate = 80;
|
||||||
} else {
|
} else {
|
||||||
volume /= 2;
|
data.volume /= 2;
|
||||||
if (type == SOUND_METAL) snd.sampleRate = (snd.sampleRate * 7) / 5;
|
if (type == SOUND_METAL) data.rate = 140;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Try to play on a context that doesn't need to be recreated */
|
/* Try to play on a context that doesn't need to be recreated */
|
||||||
@ -1010,9 +1021,9 @@ static void Sounds_Play(cc_uint8 type, struct Soundboard* board) {
|
|||||||
|
|
||||||
if (res) { Sounds_Fail(res); return; }
|
if (res) { Sounds_Fail(res); return; }
|
||||||
if (inUse > 0) continue;
|
if (inUse > 0) continue;
|
||||||
if (!Audio_FastPlay(ctx, snd.channels, snd.sampleRate)) continue;
|
if (!Audio_FastPlay(ctx, &data)) continue;
|
||||||
|
|
||||||
res = Audio_PlaySound(ctx, &snd, volume);
|
res = Audio_PlayData(ctx, &data);
|
||||||
if (res) Sounds_Fail(res);
|
if (res) Sounds_Fail(res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1025,7 +1036,7 @@ static void Sounds_Play(cc_uint8 type, struct Soundboard* board) {
|
|||||||
if (res) { Sounds_Fail(res); return; }
|
if (res) { Sounds_Fail(res); return; }
|
||||||
if (inUse > 0) continue;
|
if (inUse > 0) continue;
|
||||||
|
|
||||||
res = Audio_PlaySound(ctx, &snd, volume);
|
res = Audio_PlayData(ctx, &data);
|
||||||
if (res) Sounds_Fail(res);
|
if (res) Sounds_Fail(res);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
16
src/Audio.h
16
src/Audio.h
@ -12,6 +12,13 @@ struct Sound {
|
|||||||
int channels, sampleRate;
|
int channels, sampleRate;
|
||||||
void* data; cc_uint32 size;
|
void* data; cc_uint32 size;
|
||||||
};
|
};
|
||||||
|
struct AudioData {
|
||||||
|
void* data; cc_uint32 size; /* the raw 16 bit integer samples */
|
||||||
|
int channels;
|
||||||
|
int sampleRate; /* frequency / sample rate */
|
||||||
|
int volume; /* volume data played at (100 = normal volume) */
|
||||||
|
int rate; /* speed/pitch played at (100 = normal speed) */
|
||||||
|
};
|
||||||
|
|
||||||
/* Volume sounds are played at, from 0-100. */
|
/* Volume sounds are played at, from 0-100. */
|
||||||
/* NOTE: Use Audio_SetSounds, don't change this directly. */
|
/* NOTE: Use Audio_SetSounds, don't change this directly. */
|
||||||
@ -44,11 +51,10 @@ cc_result Audio_Play(struct AudioContext* ctx);
|
|||||||
/* (e.g. if inUse is 0, no audio buffers are being played or queued) */
|
/* (e.g. if inUse is 0, no audio buffers are being played or queued) */
|
||||||
cc_result Audio_Poll(struct AudioContext* ctx, int* inUse);
|
cc_result Audio_Poll(struct AudioContext* ctx, int* inUse);
|
||||||
|
|
||||||
/* Plays the given audio data at the given volume */
|
/* Plays the given audio data */
|
||||||
cc_result Audio_PlaySound(struct AudioContext* ctx, struct Sound* snd, int volume);
|
cc_result Audio_PlayData(struct AudioContext* ctx, struct AudioData* data);
|
||||||
/* Whether the given audio context can play audio data in the given format, */
|
/* Whether the given audio data can be played without recreating the underlying audio device */
|
||||||
/* without recreating the underlying audio device */
|
cc_bool Audio_FastPlay(struct AudioContext* ctx, struct AudioData* data);
|
||||||
cc_bool Audio_FastPlay(struct AudioContext* ctx, int channels, int sampleRate);
|
|
||||||
/* Outputs more detailed information about errors with audio. */
|
/* Outputs more detailed information about errors with audio. */
|
||||||
cc_bool Audio_DescribeError(cc_result res, cc_string* dst);
|
cc_bool Audio_DescribeError(cc_result res, cc_string* dst);
|
||||||
#endif
|
#endif
|
||||||
|
@ -206,7 +206,7 @@ static const cc_uint8 checkbox_indices[] = {
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
};
|
};
|
||||||
static PackedCol checkbox_palette[] = {
|
static const PackedCol checkbox_palette[] = {
|
||||||
PackedCol_Make( 0, 0, 0, 0), PackedCol_Make(144, 144, 144, 255),
|
PackedCol_Make( 0, 0, 0, 0), PackedCol_Make(144, 144, 144, 255),
|
||||||
PackedCol_Make( 61, 61, 61, 255), PackedCol_Make( 94, 94, 94, 255),
|
PackedCol_Make( 61, 61, 61, 255), PackedCol_Make( 94, 94, 94, 255),
|
||||||
PackedCol_Make(197, 196, 197, 255), PackedCol_Make( 57, 57, 57, 255),
|
PackedCol_Make(197, 196, 197, 255), PackedCol_Make( 57, 57, 57, 255),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user