Path: blob/main/RSDKv4/Audio.cpp
817 views
#include "RetroEngine.hpp"1#include <cmath>23int globalSFXCount = 0;4int stageSFXCount = 0;56int masterVolume = MAX_VOLUME;7int trackID = -1;8int sfxVolume = MAX_VOLUME;9int bgmVolume = MAX_VOLUME;10bool audioEnabled = false;1112bool musicEnabled = 0;13int musicStatus = MUSIC_STOPPED;14int musicStartPos = 0;15int musicPosition = 0;16int musicRatio = 0;17TrackInfo musicTracks[TRACK_COUNT];18SFXInfo sfxList[SFX_COUNT];19char sfxNames[SFX_COUNT][0x40];2021int currentStreamIndex = 0;22StreamFile streamFile[STREAMFILE_COUNT];23StreamInfo streamInfo[STREAMFILE_COUNT];24StreamFile *streamFilePtr = NULL;25StreamInfo *streamInfoPtr = NULL;2627ChannelInfo sfxChannels[CHANNEL_COUNT];2829int currentMusicTrack = -1;3031#if RETRO_USING_SDL1 || RETRO_USING_SDL23233#if RETRO_USING_SDL234SDL_AudioDeviceID audioDevice;35#endif36SDL_AudioSpec audioDeviceFormat;3738#define AUDIO_FREQUENCY (44100)39#define AUDIO_FORMAT (AUDIO_S16SYS) /**< Signed 16-bit samples */40#define AUDIO_SAMPLES (0x800)41#define AUDIO_CHANNELS (2)4243#define ADJUST_VOLUME(s, v) (s = (s * v) / MAX_VOLUME)44#endif4546int InitAudioPlayback()47{48StopAllSfx(); //"init"4950#if !RETRO_USE_ORIGINAL_CODE51#if RETRO_USING_SDL1 || RETRO_USING_SDL252SDL_AudioSpec want;53want.freq = AUDIO_FREQUENCY;54want.format = AUDIO_FORMAT;55want.samples = AUDIO_SAMPLES;56want.channels = AUDIO_CHANNELS;57want.callback = ProcessAudioPlayback;5859#if RETRO_USING_SDL260if ((audioDevice = SDL_OpenAudioDevice(nullptr, 0, &want, &audioDeviceFormat, SDL_AUDIO_ALLOW_FREQUENCY_CHANGE)) > 0) {61audioEnabled = true;62SDL_PauseAudioDevice(audioDevice, 0);63}64else {65PrintLog("Unable to open audio device: %s", SDL_GetError());66audioEnabled = false;67return true; // no audio but game wont crash now68}69#elif RETRO_USING_SDL170if (SDL_OpenAudio(&want, &audioDeviceFormat) == 0) {71audioEnabled = true;72SDL_PauseAudio(0);73}74else {75PrintLog("Unable to open audio device: %s", SDL_GetError());76audioEnabled = false;77return true; // no audio but game wont crash now78}79#endif // !RETRO_USING_SDL180#endif81#endif8283LoadGlobalSfx();8485return true;86}8788void LoadGlobalSfx()89{90FileInfo info;91FileInfo infoStore;92char strBuffer[0x100];93byte fileBuffer = 0;94int fileBuffer2 = 0;9596globalSFXCount = 0;9798if (LoadFile("Data/Game/GameConfig.bin", &info)) {99infoStore = info;100101FileRead(&fileBuffer, 1);102FileRead(strBuffer, fileBuffer);103104FileRead(&fileBuffer, 1);105FileRead(strBuffer, fileBuffer);106107byte buf[3];108for (int c = 0; c < 0x60; ++c) FileRead(buf, 3);109110// Read Obect Names111byte objectCount = 0;112FileRead(&objectCount, 1);113for (byte o = 0; o < objectCount; ++o) {114FileRead(&fileBuffer, 1);115FileRead(&strBuffer, fileBuffer);116}117118// Read Script Paths119for (byte s = 0; s < objectCount; ++s) {120FileRead(&fileBuffer, 1);121FileRead(&strBuffer, fileBuffer);122}123124byte varCount = 0;125FileRead(&varCount, 1);126for (byte v = 0; v < varCount; ++v) {127// Read Variable Name128FileRead(&fileBuffer, 1);129FileRead(&strBuffer, fileBuffer);130131// Read Variable Value132FileRead(&fileBuffer2, 4);133}134135// Read SFX136FileRead(&fileBuffer, 1);137globalSFXCount = fileBuffer;138for (byte s = 0; s < globalSFXCount; ++s) { // SFX Names139FileRead(&fileBuffer, 1);140FileRead(&strBuffer, fileBuffer);141strBuffer[fileBuffer] = 0;142143SetSfxName(strBuffer, s);144}145for (byte s = 0; s < globalSFXCount; ++s) { // SFX Paths146FileRead(&fileBuffer, 1);147FileRead(&strBuffer, fileBuffer);148strBuffer[fileBuffer] = 0;149150GetFileInfo(&infoStore);151CloseFile();152LoadSfx(strBuffer, s);153SetFileInfo(&infoStore);154}155156CloseFile();157158#if RETRO_USE_MOD_LOADER159Engine.LoadXMLSoundFX();160#endif161}162163for (int i = 0; i < CHANNEL_COUNT; ++i) sfxChannels[i].sfxID = -1;164}165166size_t readVorbis(void *mem, size_t size, size_t nmemb, void *ptr)167{168StreamFile *file = (StreamFile *)ptr;169170int n = size * nmemb;171if (size * nmemb > file->fileSize - file->filePos)172n = file->fileSize - file->filePos;173174if (n) {175memcpy(mem, &file->buffer[file->filePos], n);176file->filePos += n;177}178return n;179}180int seekVorbis(void *ptr, ogg_int64_t offset, int whence)181{182StreamFile *file = (StreamFile *)ptr;183184switch (whence) {185case SEEK_SET: whence = 0; break;186case SEEK_CUR: whence = file->filePos; break;187case SEEK_END: whence = file->fileSize; break;188default: break;189}190file->filePos = whence + offset;191return 0;192}193long tellVorbis(void *ptr)194{195StreamFile *file = (StreamFile *)ptr;196return file->filePos;197}198int closeVorbis(void *ptr) { return 1; }199200#if !RETRO_USE_ORIGINAL_CODE201void ProcessMusicStream(Sint32 *stream, size_t bytes_wanted)202{203if (!streamFilePtr || !streamInfoPtr)204return;205if (!streamFilePtr->fileSize)206return;207switch (musicStatus) {208case MUSIC_READY:209case MUSIC_PLAYING: {210#if RETRO_USING_SDL2211while (musicStatus == MUSIC_PLAYING && streamInfoPtr->stream && SDL_AudioStreamAvailable(streamInfoPtr->stream) < bytes_wanted) {212// We need more samples: get some213long bytes_read = ov_read(&streamInfoPtr->vorbisFile, (char *)streamInfoPtr->buffer, sizeof(streamInfoPtr->buffer), 0, 2, 1,214&streamInfoPtr->vorbBitstream);215216if (bytes_read == 0) {217// We've reached the end of the file218if (streamInfoPtr->trackLoop) {219ov_pcm_seek(&streamInfoPtr->vorbisFile, streamInfoPtr->loopPoint);220continue;221}222else {223musicStatus = MUSIC_STOPPED;224break;225}226}227228if (musicStatus != MUSIC_PLAYING229|| (streamInfoPtr->stream && SDL_AudioStreamPut(streamInfoPtr->stream, streamInfoPtr->buffer, (int)bytes_read) == -1))230return;231}232233// Now that we know there are enough samples, read them and mix them234int bytes_done = SDL_AudioStreamGet(streamInfoPtr->stream, streamInfoPtr->buffer, (int)bytes_wanted);235if (bytes_done == -1) {236return;237}238if (bytes_done != 0)239ProcessAudioMixing(stream, streamInfoPtr->buffer, bytes_done / sizeof(Sint16), (bgmVolume * masterVolume) / MAX_VOLUME, 0);240#endif241242#if RETRO_USING_SDL1243size_t bytes_gotten = 0;244byte *buffer = (byte *)malloc(bytes_wanted);245memset(buffer, 0, bytes_wanted);246while (bytes_gotten < bytes_wanted) {247// We need more samples: get some248long bytes_read =249ov_read(&oggFilePtr->vorbisFile, (char *)oggFilePtr->buffer,250sizeof(oggFilePtr->buffer) > (bytes_wanted - bytes_gotten) ? (bytes_wanted - bytes_gotten) : sizeof(oggFilePtr->buffer),2510, 2, 1, &oggFilePtr->vorbBitstream);252253if (bytes_read == 0) {254// We've reached the end of the file255if (oggFilePtr->trackLoop) {256ov_pcm_seek(&oggFilePtr->vorbisFile, oggFilePtr->loopPoint);257continue;258}259else {260musicStatus = MUSIC_STOPPED;261break;262}263}264265if (bytes_read > 0) {266memcpy(buffer + bytes_gotten, oggFilePtr->buffer, bytes_read);267bytes_gotten += bytes_read;268}269else {270PrintLog("Music read error: vorbis error: %d", bytes_read);271}272}273274if (bytes_gotten > 0) {275SDL_AudioCVT convert;276MEM_ZERO(convert);277int cvtResult = SDL_BuildAudioCVT(&convert, oggFilePtr->spec.format, oggFilePtr->spec.channels, oggFilePtr->spec.freq,278audioDeviceFormat.format, audioDeviceFormat.channels, audioDeviceFormat.freq);279if (cvtResult == 0) {280if (convert.len_mult > 0) {281convert.buf = (byte *)malloc(bytes_gotten * convert.len_mult);282convert.len = bytes_gotten;283memcpy(convert.buf, buffer, bytes_gotten);284SDL_ConvertAudio(&convert);285}286}287288// Now that we know there are enough samples, read them and mix them289// int bytes_done = SDL_AudioStreamGet(oggFilePtr->stream, oggFilePtr->buffer, bytes_wanted);290// if (bytes_done == -1) {291// return;292//}293294if (cvtResult == 0)295ProcessAudioMixing(stream, (const Sint16 *)convert.buf, bytes_gotten / sizeof(Sint16), (bgmVolume * masterVolume) / MAX_VOLUME,2960);297298if (convert.len > 0 && convert.buf)299free(convert.buf);300}301if (bytes_wanted > 0)302free(buffer);303#endif304305musicPosition = ov_pcm_tell(&streamInfoPtr->vorbisFile);306break;307}308case MUSIC_STOPPED:309case MUSIC_PAUSED:310case MUSIC_LOADING:311// dont play312break;313}314}315316void ProcessAudioPlayback(void *userdata, Uint8 *stream, int len)317{318(void)userdata; // Unused319320if (!audioEnabled)321return;322323Sint16 *output_buffer = (Sint16 *)stream;324325size_t samples_remaining = (size_t)len / sizeof(Sint16);326while (samples_remaining != 0) {327Sint32 mix_buffer[MIX_BUFFER_SAMPLES];328memset(mix_buffer, 0, sizeof(mix_buffer));329330const size_t samples_to_do = (samples_remaining < MIX_BUFFER_SAMPLES) ? samples_remaining : MIX_BUFFER_SAMPLES;331332// Mix music333ProcessMusicStream(mix_buffer, samples_to_do * sizeof(Sint16));334335// Mix SFX336for (byte i = 0; i < CHANNEL_COUNT; ++i) {337ChannelInfo *sfx = &sfxChannels[i];338if (sfx == NULL)339continue;340341if (sfx->sfxID < 0)342continue;343344if (sfx->samplePtr) {345Sint16 buffer[MIX_BUFFER_SAMPLES];346347size_t samples_done = 0;348while (samples_done != samples_to_do) {349size_t sampleLen = (sfx->sampleLength < samples_to_do - samples_done) ? sfx->sampleLength : samples_to_do - samples_done;350memcpy(&buffer[samples_done], sfx->samplePtr, sampleLen * sizeof(Sint16));351352samples_done += sampleLen;353sfx->samplePtr += sampleLen;354sfx->sampleLength -= sampleLen;355356if (sfx->sampleLength == 0) {357if (sfx->loopSFX) {358sfx->samplePtr = sfxList[sfx->sfxID].buffer;359sfx->sampleLength = sfxList[sfx->sfxID].length;360}361else {362MEM_ZEROP(sfx);363sfx->sfxID = -1;364break;365}366}367}368369#if RETRO_USING_SDL1 || RETRO_USING_SDL2370ProcessAudioMixing(mix_buffer, buffer, (int)samples_done, sfxVolume, sfx->pan);371#endif372}373}374375// Clamp mixed samples back to 16-bit and write them to the output buffer376for (size_t i = 0; i < sizeof(mix_buffer) / sizeof(*mix_buffer); ++i) {377const Sint16 max_audioval = ((1 << (16 - 1)) - 1);378const Sint16 min_audioval = -(1 << (16 - 1));379380const Sint32 sample = mix_buffer[i];381382if (sample > max_audioval)383*output_buffer++ = max_audioval;384else if (sample < min_audioval)385*output_buffer++ = min_audioval;386else387*output_buffer++ = sample;388}389390samples_remaining -= samples_to_do;391}392}393394#if RETRO_USING_SDL1 || RETRO_USING_SDL2395void ProcessAudioMixing(Sint32 *dst, const Sint16 *src, int len, int volume, sbyte pan)396{397if (volume == 0)398return;399400if (volume > MAX_VOLUME)401volume = MAX_VOLUME;402403float panL = 0.0;404float panR = 0.0;405int i = 0;406407if (pan < 0) {408panR = 1.0f - abs(pan / 100.0f);409panL = 1.0f;410}411else if (pan > 0) {412panL = 1.0f - abs(pan / 100.0f);413panR = 1.0f;414}415416while (len--) {417Sint32 sample = *src++;418ADJUST_VOLUME(sample, volume);419420if (pan != 0) {421if ((i % 2) != 0) {422sample *= panR;423}424else {425sample *= panL;426}427}428429*dst++ += sample;430431i++;432}433}434#endif435#endif436437void LoadMusic(void *userdata)438{439int oldStreamID = currentStreamIndex;440currentStreamIndex++;441currentStreamIndex %= STREAMFILE_COUNT;442443LockAudioDevice();444445if (streamFile[currentStreamIndex].fileSize > 0)446StopMusic(false);447448FileInfo info;449if (LoadFile(musicTracks[currentMusicTrack].fileName, &info)) {450StreamInfo *strmInfo = &streamInfo[currentStreamIndex];451452StreamFile *musFile = &streamFile[currentStreamIndex];453musFile->filePos = 0;454musFile->fileSize = info.vfileSize;455if (info.vfileSize > MUSBUFFER_SIZE)456musFile->fileSize = MUSBUFFER_SIZE;457458FileRead(streamFile[currentStreamIndex].buffer, musFile->fileSize);459CloseFile();460461unsigned long long samples = 0;462ov_callbacks callbacks;463464callbacks.read_func = readVorbis;465callbacks.seek_func = seekVorbis;466callbacks.tell_func = tellVorbis;467callbacks.close_func = closeVorbis;468469int error = ov_open_callbacks(musFile, &strmInfo->vorbisFile, NULL, 0, callbacks);470if (error == 0) {471strmInfo->vorbBitstream = -1;472strmInfo->vorbisFile.vi = ov_info(&strmInfo->vorbisFile, -1);473474samples = (unsigned long long)ov_pcm_total(&strmInfo->vorbisFile, -1);475476#if RETRO_USING_SDL2477strmInfo->stream = SDL_NewAudioStream(AUDIO_S16, strmInfo->vorbisFile.vi->channels, (int)strmInfo->vorbisFile.vi->rate,478audioDeviceFormat.format, audioDeviceFormat.channels, audioDeviceFormat.freq);479if (!strmInfo->stream)480PrintLog("Failed to create stream: %s", SDL_GetError());481#endif482483#if RETRO_USING_SDL1484playbackInfo->spec.format = AUDIO_S16;485playbackInfo->spec.channels = playbackInfo->vorbisFile.vi->channels;486playbackInfo->spec.freq = (int)playbackInfo->vorbisFile.vi->rate;487#endif488489if (musicStartPos) {490uint oldPos = (uint)ov_pcm_tell(&streamInfo[oldStreamID].vorbisFile);491492float newPos = oldPos * ((float)musicRatio * 0.0001); // 8,000 == 0.8, 10,000 == 1.0 (ratio / 10,000)493musicStartPos = fmod(newPos, samples);494495ov_pcm_seek(&strmInfo->vorbisFile, musicStartPos);496}497musicStartPos = 0;498499musicStatus = MUSIC_PLAYING;500masterVolume = MAX_VOLUME;501trackID = currentMusicTrack;502strmInfo->trackLoop = musicTracks[currentMusicTrack].trackLoop;503strmInfo->loopPoint = musicTracks[currentMusicTrack].loopPoint;504strmInfo->loaded = true;505streamFilePtr = &streamFile[currentStreamIndex];506streamInfoPtr = &streamInfo[currentStreamIndex];507currentMusicTrack = -1;508musicPosition = 0;509}510else {511musicStatus = MUSIC_STOPPED;512PrintLog("Failed to load vorbis! error: %d", error);513switch (error) {514default: PrintLog("Vorbis open error: Unknown (%d)", error); break;515case OV_EREAD: PrintLog("Vorbis open error: A read from media returned an error"); break;516case OV_ENOTVORBIS: PrintLog("Vorbis open error: Bitstream does not contain any Vorbis data"); break;517case OV_EVERSION: PrintLog("Vorbis open error: Vorbis version mismatch"); break;518case OV_EBADHEADER: PrintLog("Vorbis open error: Invalid Vorbis bitstream header"); break;519case OV_EFAULT: PrintLog("Vorbis open error: Internal logic fault; indicates a bug or heap / stack corruption"); break;520}521}522}523else {524musicStatus = MUSIC_STOPPED;525}526UnlockAudioDevice();527}528529void SetMusicTrack(const char *filePath, byte trackID, bool loop, uint loopPoint)530{531LockAudioDevice();532TrackInfo *track = &musicTracks[trackID];533StrCopy(track->fileName, "Data/Music/");534StrAdd(track->fileName, filePath);535track->trackLoop = loop;536track->loopPoint = loopPoint;537UnlockAudioDevice();538}539540void SwapMusicTrack(const char *filePath, byte trackID, uint loopPoint, uint ratio)541{542if (StrLength(filePath) <= 0) {543StopMusic(true);544}545else {546LockAudioDevice();547TrackInfo *track = &musicTracks[trackID];548StrCopy(track->fileName, "Data/Music/");549StrAdd(track->fileName, filePath);550track->trackLoop = true;551track->loopPoint = loopPoint;552musicRatio = ratio;553UnlockAudioDevice();554PlayMusic(trackID, 1);555}556}557558bool PlayMusic(int track, int musStartPos)559{560if (!audioEnabled)561return false;562563if (musicTracks[track].fileName[0]) {564if (musicStatus != MUSIC_LOADING) {565LockAudioDevice();566if (track < 0 || track >= TRACK_COUNT) {567StopMusic(true);568currentMusicTrack = -1;569return false;570}571musicStartPos = musStartPos;572currentMusicTrack = track;573musicStatus = MUSIC_LOADING;574LoadMusic(NULL);575UnlockAudioDevice();576return true;577}578else {579PrintLog("WARNING music tried to play while music was loading!");580}581}582else {583StopMusic(true);584}585586return false;587}588589void SetSfxName(const char *sfxName, int sfxID)590{591int sfxNameID = 0;592int soundNameID = 0;593while (sfxName[sfxNameID]) {594if (sfxName[sfxNameID] != ' ')595sfxNames[sfxID][soundNameID++] = sfxName[sfxNameID];596++sfxNameID;597}598sfxNames[sfxID][soundNameID] = 0;599PrintLog("Set SFX (%d) name to: %s", sfxID, sfxName);600}601602void LoadSfx(char *filePath, byte sfxID)603{604if (!audioEnabled)605return;606607FileInfo info;608char fullPath[0x80];609610StrCopy(fullPath, "Data/SoundFX/");611StrAdd(fullPath, filePath);612613if (LoadFile(fullPath, &info)) {614#if !RETRO_USE_ORIGINAL_CODE615byte type = fullPath[StrLength(fullPath) - 3];616if (type == 'w') {617byte *sfx = new byte[info.vfileSize];618FileRead(sfx, info.vfileSize);619CloseFile();620621SDL_RWops *src = SDL_RWFromMem(sfx, info.vfileSize);622if (src == NULL) {623PrintLog("Unable to open sfx: %s", info.fileName);624}625else {626SDL_AudioSpec wav_spec;627uint wav_length;628byte *wav_buffer;629SDL_AudioSpec *wav = SDL_LoadWAV_RW(src, 0, &wav_spec, &wav_buffer, &wav_length);630631SDL_RWclose(src);632delete[] sfx;633if (wav == NULL) {634PrintLog("Unable to read sfx: %s", info.fileName);635}636else {637SDL_AudioCVT convert;638if (SDL_BuildAudioCVT(&convert, wav->format, wav->channels, wav->freq, audioDeviceFormat.format, audioDeviceFormat.channels,639audioDeviceFormat.freq)640> 0) {641convert.buf = (byte *)malloc(wav_length * convert.len_mult);642convert.len = wav_length;643memcpy(convert.buf, wav_buffer, wav_length);644SDL_ConvertAudio(&convert);645646LockAudioDevice();647StrCopy(sfxList[sfxID].name, filePath);648sfxList[sfxID].buffer = (Sint16 *)convert.buf;649sfxList[sfxID].length = convert.len_cvt / sizeof(Sint16);650sfxList[sfxID].loaded = true;651UnlockAudioDevice();652SDL_FreeWAV(wav_buffer);653}654else { // this causes errors, actually655PrintLog("Unable to read sfx: %s (error: %s)", info.fileName, SDL_GetError());656sfxList[sfxID].loaded = false;657SDL_FreeWAV(wav_buffer);658// LockAudioDevice()659// StrCopy(sfxList[sfxID].name, filePath);660// sfxList[sfxID].buffer = (Sint16 *)wav_buffer;661// sfxList[sfxID].length = wav_length / sizeof(Sint16);662// sfxList[sfxID].loaded = false;663// UnlockAudioDevice()664}665}666}667}668else if (type == 'o') {669// ogg sfx :(670OggVorbis_File vf;671ov_callbacks callbacks = OV_CALLBACKS_NOCLOSE;672vorbis_info *vinfo;673byte *buf;674SDL_AudioSpec spec;675int bitstream = -1;676long samplesize;677long samples;678int read, toRead;679680currentStreamIndex++;681currentStreamIndex %= STREAMFILE_COUNT;682683StreamFile *sfxFile = &streamFile[currentStreamIndex];684sfxFile->filePos = 0;685sfxFile->fileSize = info.vfileSize;686if (info.vfileSize > MUSBUFFER_SIZE)687sfxFile->fileSize = MUSBUFFER_SIZE;688689FileRead(streamFile[currentStreamIndex].buffer, sfxFile->fileSize);690CloseFile();691692callbacks.read_func = readVorbis;693callbacks.seek_func = seekVorbis;694callbacks.tell_func = tellVorbis;695callbacks.close_func = closeVorbis;696697// GetFileInfo(&info);698int error = ov_open_callbacks(sfxFile, &vf, NULL, 0, callbacks);699if (error != 0) {700ov_clear(&vf);701PrintLog("failed to load ogg sfx!");702return;703}704705vinfo = ov_info(&vf, -1);706707byte *audioBuf = NULL;708uint audioLen = 0;709memset(&spec, 0, sizeof(SDL_AudioSpec));710711spec.format = AUDIO_S16;712spec.channels = vinfo->channels;713spec.freq = (int)vinfo->rate;714spec.samples = 4096; /* buffer size */715716samples = (long)ov_pcm_total(&vf, -1);717718audioLen = spec.size = (Uint32)(samples * spec.channels * 2);719audioBuf = (byte *)malloc(audioLen);720buf = audioBuf;721toRead = audioLen;722723for (read = (int)ov_read(&vf, (char *)buf, toRead, 0, 2, 1, &bitstream); read > 0;724read = (int)ov_read(&vf, (char *)buf, toRead, 0, 2, 1, &bitstream)) {725if (read < 0) {726free(audioBuf);727ov_clear(&vf);728PrintLog("failed to read ogg sfx!");729return;730}731toRead -= read;732buf += read;733}734735ov_clear(&vf); // clears & closes vorbis file736737/* Don't return a buffer that isn't a multiple of samplesize */738samplesize = ((spec.format & 0xFF) / 8) * spec.channels;739audioLen &= ~(samplesize - 1);740741SDL_AudioCVT convert;742if (SDL_BuildAudioCVT(&convert, spec.format, spec.channels, spec.freq, audioDeviceFormat.format, audioDeviceFormat.channels,743audioDeviceFormat.freq)744> 0) {745convert.buf = (byte *)malloc(audioLen * convert.len_mult);746convert.len = audioLen;747memcpy(convert.buf, audioBuf, audioLen);748SDL_ConvertAudio(&convert);749750LockAudioDevice();751StrCopy(sfxList[sfxID].name, filePath);752sfxList[sfxID].buffer = (Sint16 *)convert.buf;753sfxList[sfxID].length = convert.len_cvt / sizeof(Sint16);754sfxList[sfxID].loaded = true;755UnlockAudioDevice();756free(audioBuf);757}758else {759LockAudioDevice();760StrCopy(sfxList[sfxID].name, filePath);761sfxList[sfxID].buffer = (Sint16 *)audioBuf;762sfxList[sfxID].length = audioLen / sizeof(Sint16);763sfxList[sfxID].loaded = true;764UnlockAudioDevice();765}766}767else {768// wtf lol769CloseFile();770PrintLog("Sfx format not supported!");771}772#endif773}774}775void PlaySfx(int sfx, bool loop)776{777LockAudioDevice();778int sfxChannelID = -1;779for (int c = 0; c < CHANNEL_COUNT; ++c) {780if (sfxChannels[c].sfxID == sfx || sfxChannels[c].sfxID == -1) {781sfxChannelID = c;782break;783}784}785786ChannelInfo *sfxInfo = &sfxChannels[sfxChannelID];787sfxInfo->sfxID = sfx;788sfxInfo->samplePtr = sfxList[sfx].buffer;789sfxInfo->sampleLength = sfxList[sfx].length;790sfxInfo->loopSFX = loop;791sfxInfo->pan = 0;792UnlockAudioDevice();793}794void SetSfxAttributes(int sfx, int loopCount, sbyte pan)795{796LockAudioDevice();797int sfxChannel = -1;798for (int i = 0; i < CHANNEL_COUNT; ++i) {799if (sfxChannels[i].sfxID == sfx) {800sfxChannel = i;801break;802}803}804if (sfxChannel == -1) {805UnlockAudioDevice();806return; // wasn't found807}808809ChannelInfo *sfxInfo = &sfxChannels[sfxChannel];810sfxInfo->loopSFX = loopCount == -1 ? sfxInfo->loopSFX : loopCount;811sfxInfo->pan = pan;812sfxInfo->sfxID = sfx;813UnlockAudioDevice();814}815816817