Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include "../include/kit_sdl2/kit_acodec.h"
- #include "../_private/include/_kit_privmacro.h"
- int kit_acodecPCMDestroy(kit_acodecPCM** pcm_p){
- _IF_SDLERR(pcm_p==NULL,;,"!pcm_p")
- kit_acodecPCM* pcm = *pcm_p;
- _IF_GOTO(pcm==NULL,_noerr_,;) //exit early if already destroyed
- SDL_free(pcm); //yep, that's it!
- *pcm_p = NULL;
- _noerr_: return 0;
- _error_: return -1;
- }
- kit_acodecPCM* kit_acodecPCMCreate(SDL_AudioFormat format, Uint16 channels,
- Uint32 sampleRate, Uint64 numSamples)
- {
- kit_acodecPCM* pcm = NULL; int failed = 0;
- Uint8 bitsPerSample = SDL_AUDIO_BITSIZE(format);
- _IF_SDLERR(bitsPerSample==0,;,"bitsPerSample=0")
- _IF_SDLERR(channels==0,;,"channels=0")
- _IF_SDLERR(sampleRate==0,;,"sampleRate=0")
- //(numSamples being 0 is technically allowed)
- _IF_GOTO_ERROR(kit_coreRealloc(&pcm, 0,sizeof(kit_acodecPCM)),;)
- pcm->magic = KPCM_MAGIC;
- pcm->format = format;
- pcm->headerSize = sizeof(kit_acodecPCM);
- pcm->loopStart = 0;
- pcm->loopEnd = numSamples;
- pcm->numSamples = numSamples;
- pcm->sampleRate = sampleRate;
- pcm->loopCount = 0; //play once without looping
- pcm->channels = channels;
- pcm->bitRemainder = bitsPerSample%8;
- pcm->userflags = 0;
- pcm->uservalue = 0;
- pcm->userdata = NULL;
- pcm->data = NULL;
- //stuff that requires previous values
- pcm->bitRate = bitsPerSample*channels*sampleRate;
- pcm->dataSize = (bitsPerSample*channels*numSamples)/8;
- if(pcm->bitRemainder) ++pcm->dataSize; //offsets integer division truncation
- failed = kit_coreRealloc(&pcm,sizeof(kit_acodecPCM),
- sizeof(kit_acodecPCM)+pcm->dataSize);
- _error_:
- if(pcm!=NULL && failed){
- SDL_free(pcm);
- pcm = NULL;
- }
- return pcm;
- }
- kit_acodecPCM* kit_acodecPCMCopy(kit_acodecPCM* pcm){
- kit_acodecPCM* pcmOut = NULL;
- SDL_bool success = SDL_FALSE;
- _IF_SDLERR(pcm==NULL,;,"!pcm")
- size_t totalSize = pcm->headerSize + pcm->dataSize;
- pcmOut = SDL_malloc(totalSize);
- _IF_SDLERR(pcmOut==NULL,;,"!pcmOut")
- kit_coreMemcpy(pcmOut, pcm, totalSize);
- pcmOut->data = (void*)pcmOut + pcmOut->headerSize;
- success = SDL_TRUE;
- _error_:
- if(!success) kit_acodecPCMDestroy(&pcmOut);
- return pcmOut;
- }
- kit_acodecPCM* kit_acodecPCMRead(const char* filePath){
- kit_acodecPCM* pcm = NULL;
- SDL_bool success = SDL_FALSE;
- _IF_SDLERR(filePath==NULL,;,"!filePath")
- _IF_GOTO_ERROR(!kit_coreFileReadBin(filePath, &pcm, 0),;)
- _IF_SDLERR(pcm->magic!=KPCM_MAGIC,;,"pcm->magic!=\"kPCM\"")
- pcm->data = (void*)pcm + pcm->headerSize;
- success = SDL_TRUE;
- _error_:
- if(!success) kit_acodecPCMDestroy(&pcm);
- return pcm;
- }
- int kit_acodecPCMWrite(kit_acodecPCM* pcm, const char* filePath){
- _IF_SDLERR(filePath==NULL,;,"!filePath")
- _IF_SDLERR(pcm==NULL,;,"!pcm")
- //set pointers to 0 before writing
- void* userdata = pcm->userdata;
- void* data = pcm->data;
- pcm->userdata = 0, pcm->data = 0;
- //calculate size before writing to file
- size_t totalSize = pcm->headerSize + pcm->dataSize;
- _IF_GOTO_ERROR(kit_coreFileWriteBin(filePath, pcm, totalSize, 0),;)
- //restore pointers before returning
- pcm->userdata = userdata, pcm->data = data;
- /*!err*/ return 0;
- _error_: return -1;
- }
- int kit_acodecPCMSetNumSamples(kit_acodecPCM** pcm_p, Uint64 numSamples){
- _IF_SDLERR(pcm_p==NULL,;,"!pcm_p")
- kit_acodecPCM* pcm = *pcm_p;
- _IF_SDLERR(pcm==NULL,;,"!*pcm_p")
- kit_acodecPCM _pcm = *pcm;
- Uint8 bitsPerSample = SDL_AUDIO_BITSIZE(_pcm.format);
- _pcm.numSamples = numSamples;
- _pcm.dataSize = (bitsPerSample*_pcm.channels*numSamples)/8;
- if(_pcm.bitRemainder) ++_pcm.dataSize; //offsets integer division truncation
- size_t oldSize = pcm->headerSize + pcm->dataSize;
- size_t newSize = _pcm.headerSize + _pcm.dataSize;
- _IF_GOTO_ERROR(kit_coreRealloc(&pcm, oldSize,newSize),;)
- *pcm = _pcm;
- pcm->data = (void*)pcm + pcm->headerSize;
- *pcm_p = pcm; //apply changes only if realloc succeeded
- /*!err*/ return 0;
- _error_: return -1;
- }
- kit_acodecPCM* kit_acodecPCMConvertStereo(kit_acodecPCM* pcm, SDL_bool toStereo){
- kit_acodecPCM* pcmOut = NULL;
- SDL_bool success = SDL_FALSE;
- _IF_SDLERR(pcm==NULL,;,"!pcm")
- _IF_SDLERR(pcm->channels==0,;,"pcm->channels=0")
- _IF_SDLERR(pcm->channels>2,;,"pcm->channels>2")
- SDL_AudioFormat format = pcm->format;
- Uint64 numSamples = pcm->numSamples;
- Uint32 sampleRate = pcm->sampleRate;
- Uint16 channelsIn = pcm->channels;
- Uint16 channelsOut = 1+toStereo;
- if(channelsIn == channelsOut) return kit_acodecPCMCopy(pcm);
- pcmOut = kit_acodecPCMCreate(format, channelsOut, sampleRate, numSamples);
- _IF_GOTO_ERROR(pcmOut==NULL,;)
- kit_acodecPCMSamples in = { .data = pcm->data };
- kit_acodecPCMSamples out = { .data = pcmOut->data };
- if(toStereo){
- #define _TO_STEREO(_type) out._type[i].l = out._type[i].r
- switch(format){
- case AUDIO_U8 : for(Uint64 i=0; i<numSamples; ++i){ _TO_STEREO(u_8s) = in.u_8[i]; } break;
- case AUDIO_S16: for(Uint64 i=0; i<numSamples; ++i){ _TO_STEREO(i16s) = in.i16[i]; } break;
- case AUDIO_S32: for(Uint64 i=0; i<numSamples; ++i){ _TO_STEREO(i32s) = in.i32[i]; } break;
- case AUDIO_F32: for(Uint64 i=0; i<numSamples; ++i){ _TO_STEREO(f32s) = in.f32[i]; } break;
- default: _IS_SDLERR(;,"unknown format 0x%04X",format) }
- } else { //to mono
- #define _FROM_STEREO(_type) (in._type[i].l + in._type[i].r) * 0.5f
- switch(format){
- case AUDIO_U8 : for(Uint64 i=0; i<numSamples; ++i){ out.u_8[i] = _FROM_STEREO(u_8s); } break;
- case AUDIO_S16: for(Uint64 i=0; i<numSamples; ++i){ out.i16[i] = _FROM_STEREO(i16s); } break;
- case AUDIO_S32: for(Uint64 i=0; i<numSamples; ++i){ out.i32[i] = _FROM_STEREO(i32s); } break;
- case AUDIO_F32: for(Uint64 i=0; i<numSamples; ++i){ out.f32[i] = _FROM_STEREO(f32s); } break;
- default: _IS_SDLERR(;,"unknown format 0x%04X",format) }
- }
- success = SDL_TRUE;
- _error_:
- if(!success) kit_acodecPCMDestroy(&pcmOut);
- return pcmOut;
- }
- kit_acodecPCM* kit_acodecPCMConvertFormat(kit_acodecPCM* pcm, SDL_AudioFormat format){
- kit_acodecPCM* pcmOut = NULL;
- float* f32_buffer = NULL;
- SDL_bool success = SDL_FALSE;
- _IF_SDLERR(pcm==NULL,;,"!pcm")
- if(pcm->format == format) return kit_acodecPCMCopy(pcm);
- Uint64 numSamples = pcm->numSamples;
- Uint32 sampleRate = pcm->sampleRate;
- Uint16 channels = pcm->channels;
- Uint64 numSamplesRaw = numSamples*channels;
- size_t f32_buffer_size = numSamplesRaw*sizeof(float);
- //input will be converted to f32 as an intermediate format...
- f32_buffer = SDL_malloc(f32_buffer_size);
- _IF_SDLERR(f32_buffer==NULL,;,"!malloc")
- float sample;
- Uint8* u_8_samples; Sint16* i16_samples;
- Sint32* i32_samples; float* f32_samples;
- switch(pcm->format){
- case AUDIO_U8 : u_8_samples = pcm->u_8;
- for(Uint64 i=0; i<numSamplesRaw; ++i){
- sample = (float)(u_8_samples[i]-0x80) * invi_8;
- f32_buffer[i] = (sample>=-1.0f) ? sample : -1.0f;
- } break;
- case AUDIO_S16: i16_samples = pcm->i16;
- for(Uint64 i=0; i<numSamplesRaw; ++i){
- sample = (float)i16_samples[i] * invi16;
- f32_buffer[i] = (sample>=-1.0f) ? sample : -1.0f;
- } break;
- case AUDIO_S32: i32_samples = pcm->i32;
- for(Uint64 i=0; i<numSamplesRaw; ++i){
- sample = (float)i32_samples[i] * invi32;
- f32_buffer[i] = (sample>=-1.0f) ? sample : -1.0f;
- } break;
- case AUDIO_F32: f32_samples = pcm->f32;
- for(Uint64 i=0; i<numSamplesRaw; ++i){
- sample = f32_samples[i];
- f32_buffer[i] = CLAMP(sample, -1.0f,1.0f);
- } break;
- default: _IS_SDLERR(;,"input format=0x%04X",pcm->format) }
- //...before being converted from f32 to the output format
- pcmOut = kit_acodecPCMCreate(format, channels, sampleRate, numSamples);
- _IF_GOTO_ERROR(pcmOut==NULL,;)
- switch(format){
- case AUDIO_U8 : u_8_samples = pcmOut->u_8;
- for(Uint64 i=0; i<numSamplesRaw; ++i){
- u_8_samples[i] = f32_samples[i]*I_8_MAX + 0x80;
- } break;
- case AUDIO_S16: i16_samples = pcmOut->i16;
- for(Uint64 i=0; i<numSamplesRaw; ++i){
- i16_samples[i] = f32_samples[i]*I16_MAX;
- } break;
- case AUDIO_S32: i32_samples = pcmOut->i32;
- for(Uint64 i=0; i<numSamplesRaw; ++i){
- i32_samples[i] = f32_samples[i]*I32_MAX;
- } break;
- //lol
- case AUDIO_F32: kit_coreMemcpy(pcmOut->f32, f32_buffer, f32_buffer_size); break;
- default: _IS_SDLERR(;,"output format=0x%04X",format) }
- success = SDL_TRUE;
- _error_:
- if(!success) kit_acodecPCMDestroy(&pcmOut);
- if(f32_buffer != NULL) SDL_free(f32_buffer);
- return pcmOut;
- }
- //linear interpolation
- static inline int _kit_acodecPCMResampleLinear(kit_acodecPCM* pcmIn, kit_acodecPCM* pcmOut,
- double ratio, Uint16 channels, Uint64 numSamplesRaw)
- {
- #define _SIMLERP(_v0,_v1, _t) ( (_v0) + (_t)*((_v1)-(_v0)) )
- double src_pos = 0; //source position, in sample frames
- double pos_mod; // = src_pos % 1
- Uint64 pos_int;
- switch(pcmOut->format){
- /*
- case AUDIO_U8 :; Uint8* u_8_src = pcmIn->u_8, *u_8_dst = pcmOut->u_8;
- Uint8 u_8_smp0, u_8_smp1;
- case AUDIO_S16:; Sint16* i16_src = pcmIn->i16, *i16_dst = pcmOut->i16;
- Sint32 i16_smp0, i16_smp1;
- case AUDIO_S32:; Sint32* i32_src = pcmIn->i32, *i32_dst = pcmOut->i32;
- Sint32 i32_smp0, i32_smp1;
- */
- case AUDIO_F32:; float* f32_src = pcmIn->f32, *f32_dst = pcmOut->f32;
- for(Uint64 s=0; s<numSamplesRaw; s+=channels){
- pos_int = src_pos;
- pos_mod = src_pos-pos_int;
- pos_int *= channels;
- for(Uint32 c=0; c<channels; ++c){
- float f32_smp0 = f32_src[pos_int + c];
- float f32_smp1 = f32_src[pos_int + c + channels];
- f32_dst[s+c] = _SIMLERP(f32_smp0,f32_smp1, pos_mod);
- }
- src_pos += ratio;
- } break;
- default: _IS_SDLERR(;,"unknown format 0x%04X",pcmOut->format)
- }
- /*!err*/ return 0;
- _error_: return -1;
- }
- //nearest neighbor interpolation
- static inline int _kit_acodecPCMResampleNearest(kit_acodecPCM* pcmIn, kit_acodecPCM* pcmOut,
- double ratio, Uint16 channels, Uint64 numSamplesRaw)
- {
- double src_pos = 0; //source position, in sample frames
- Uint64 pos_int;
- switch(pcmOut->format){
- case AUDIO_U8 :; Uint8* u_8_src = pcmIn->u_8, *u_8_dst = pcmOut->u_8;
- for(Uint64 s=0; s<numSamplesRaw; s+=channels){
- pos_int = src_pos+0.5; pos_int *= channels;
- for(Uint32 c=0; c<channels; ++c)
- u_8_dst[s + c] = u_8_src[pos_int + c];
- src_pos += ratio;
- } break;
- case AUDIO_S16:; Sint16* i16_src = pcmIn->i16, *i16_dst = pcmOut->i16;
- for(Uint64 s=0; s<numSamplesRaw; s+=channels){
- pos_int = src_pos+0.5; pos_int *= channels;
- for(Uint32 c=0; c<channels; ++c)
- i16_dst[s + c] = i16_src[pos_int + c];
- src_pos += ratio;
- } break;
- case AUDIO_S32:; Sint32* i32_src = pcmIn->i32, *i32_dst = pcmOut->i32;
- for(Uint64 s=0; s<numSamplesRaw; s+=channels){
- pos_int = src_pos+0.5; pos_int *= channels;
- for(Uint32 c=0; c<channels; ++c)
- i32_dst[s + c] = i32_src[pos_int + c];
- src_pos += ratio;
- } break;
- case AUDIO_F32:; float* f32_src = pcmIn->f32, *f32_dst = pcmOut->f32;
- for(Uint64 s=0; s<numSamplesRaw; s+=channels){
- pos_int = src_pos+0.5; pos_int *= channels;
- for(Uint32 c=0; c<channels; ++c)
- f32_dst[s + c] = f32_src[pos_int + c];
- src_pos += ratio;
- } break;
- default: _IS_SDLERR(;,"unknown format 0x%04X",pcmOut->format)
- }
- /*!err*/ return 0;
- _error_: return -1;
- }
- kit_acodecPCM* kit_acodecPCMResample(kit_acodecPCM* pcm, Uint32 sampleRate,
- SDL_bool linearInterpolation)
- {
- kit_acodecPCM* pcmOut = NULL;
- SDL_bool success = SDL_FALSE;
- _IF_SDLERR(pcm==NULL,;,"!pcm")
- _IF_SDLERR(pcm->sampleRate==0,;,"pcm->sampleRate=0")
- _IF_SDLERR(sampleRate==0,;,"sampleRate=0")
- linearInterpolation &= 1;
- SDL_AudioFormat format = pcm->format;
- Uint16 channels = pcm->channels;
- double ratio = (double)pcm->sampleRate/sampleRate;
- Uint64 numSamples = pcm->numSamples*ratio;
- Uint64 numSamplesRaw = numSamples*channels;
- pcmOut = kit_acodecPCMCreate(format, channels, sampleRate, numSamples);
- _IF_GOTO_ERROR(pcmOut==NULL,;)
- pcmOut->loopStart = pcm->loopStart;
- pcmOut->loopEnd = pcm->loopEnd;
- pcmOut->loopCount = pcm->loopCount;
- pcmOut->userflags = pcm->userflags;
- pcmOut->uservalue = pcm->uservalue;
- pcmOut->userdata = pcm->userdata;
- if(linearInterpolation){
- _IF_GOTO_ERROR(_kit_acodecPCMResampleLinear(pcm,pcmOut, ratio,
- channels,numSamplesRaw),;)
- } else { //otherwise, use nearest neighbor interpolation
- _IF_GOTO_ERROR(_kit_acodecPCMResampleNearest(pcm,pcmOut, ratio,
- channels,numSamplesRaw),;)
- }
- success = SDL_TRUE;
- _error_:
- if(!success) kit_acodecPCMDestroy(&pcmOut);
- return pcmOut;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement