Advertisement
Kitomas

kit_sdl2_acodecPCM.c as of 2023-9-28

Sep 29th, 2023
674
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.09 KB | None | 0 0
  1. #include "../include/kit_sdl2/kit_acodec.h"
  2. #include "../_private/include/_kit_privmacro.h"
  3.  
  4.  
  5.  
  6.  
  7. int kit_acodecPCMDestroy(kit_acodecPCM** pcm_p){
  8.   _IF_SDLERR(pcm_p==NULL,;,"!pcm_p")
  9.   kit_acodecPCM* pcm = *pcm_p;
  10.   _IF_GOTO(pcm==NULL,_noerr_,;) //exit early if already destroyed
  11.  
  12.   SDL_free(pcm); //yep, that's it!
  13.   *pcm_p = NULL;
  14.  
  15.   _noerr_: return  0;
  16.   _error_: return -1;
  17. }
  18.  
  19.  
  20.  
  21. kit_acodecPCM* kit_acodecPCMCreate(SDL_AudioFormat format, Uint16 channels,
  22.                                    Uint32 sampleRate, Uint64 numSamples)
  23. {
  24.   kit_acodecPCM* pcm = NULL; int failed = 0;
  25.   Uint8 bitsPerSample = SDL_AUDIO_BITSIZE(format);
  26.   _IF_SDLERR(bitsPerSample==0,;,"bitsPerSample=0")
  27.   _IF_SDLERR(channels==0,;,"channels=0")
  28.   _IF_SDLERR(sampleRate==0,;,"sampleRate=0")
  29.   //(numSamples being 0 is technically allowed)
  30.  
  31.  
  32.   _IF_GOTO_ERROR(kit_coreRealloc(&pcm, 0,sizeof(kit_acodecPCM)),;)
  33.   pcm->magic        = KPCM_MAGIC;
  34.   pcm->format       = format;
  35.   pcm->headerSize   = sizeof(kit_acodecPCM);
  36.   pcm->loopStart    = 0;
  37.   pcm->loopEnd      = numSamples;
  38.   pcm->numSamples   = numSamples;
  39.   pcm->sampleRate   = sampleRate;
  40.   pcm->loopCount    = 0; //play once without looping
  41.   pcm->channels     = channels;
  42.   pcm->bitRemainder = bitsPerSample%8;
  43.   pcm->userflags    = 0;
  44.   pcm->uservalue    = 0;
  45.   pcm->userdata     = NULL;
  46.   pcm->data         = NULL;
  47.    //stuff that requires previous values
  48.   pcm->bitRate  = bitsPerSample*channels*sampleRate;
  49.   pcm->dataSize = (bitsPerSample*channels*numSamples)/8;
  50.   if(pcm->bitRemainder) ++pcm->dataSize; //offsets integer division truncation
  51.  
  52.   failed = kit_coreRealloc(&pcm,sizeof(kit_acodecPCM),
  53.                                 sizeof(kit_acodecPCM)+pcm->dataSize);
  54.  
  55.  
  56.   _error_:
  57.   if(pcm!=NULL && failed){
  58.     SDL_free(pcm);
  59.     pcm = NULL;
  60.   }
  61.   return pcm;
  62. }
  63.  
  64.  
  65.  
  66. kit_acodecPCM* kit_acodecPCMCopy(kit_acodecPCM* pcm){
  67.   kit_acodecPCM* pcmOut = NULL;
  68.   SDL_bool success = SDL_FALSE;
  69.   _IF_SDLERR(pcm==NULL,;,"!pcm")
  70.  
  71.  
  72.   size_t totalSize = pcm->headerSize + pcm->dataSize;
  73.  
  74.   pcmOut = SDL_malloc(totalSize);
  75.   _IF_SDLERR(pcmOut==NULL,;,"!pcmOut")
  76.   kit_coreMemcpy(pcmOut, pcm, totalSize);
  77.   pcmOut->data = (void*)pcmOut + pcmOut->headerSize;
  78.  
  79.  
  80.   success = SDL_TRUE;
  81.   _error_:
  82.   if(!success) kit_acodecPCMDestroy(&pcmOut);
  83.   return pcmOut;
  84. }
  85.  
  86.  
  87.  
  88.  
  89. kit_acodecPCM* kit_acodecPCMRead(const char* filePath){
  90.   kit_acodecPCM* pcm = NULL;
  91.   SDL_bool success = SDL_FALSE;
  92.   _IF_SDLERR(filePath==NULL,;,"!filePath")
  93.  
  94.  
  95.   _IF_GOTO_ERROR(!kit_coreFileReadBin(filePath, &pcm, 0),;)
  96.   _IF_SDLERR(pcm->magic!=KPCM_MAGIC,;,"pcm->magic!=\"kPCM\"")
  97.   pcm->data = (void*)pcm + pcm->headerSize;
  98.  
  99.  
  100.   success = SDL_TRUE;
  101.   _error_:
  102.   if(!success) kit_acodecPCMDestroy(&pcm);
  103.   return pcm;
  104. }
  105.  
  106.  
  107.  
  108. int kit_acodecPCMWrite(kit_acodecPCM* pcm, const char* filePath){
  109.   _IF_SDLERR(filePath==NULL,;,"!filePath")
  110.   _IF_SDLERR(pcm==NULL,;,"!pcm")
  111.  
  112.  
  113.   //set pointers to 0 before writing
  114.   void* userdata = pcm->userdata;
  115.   void*     data = pcm->data;
  116.   pcm->userdata = 0,  pcm->data = 0;
  117.  
  118.  
  119.   //calculate size before writing to file
  120.   size_t totalSize = pcm->headerSize + pcm->dataSize;
  121.   _IF_GOTO_ERROR(kit_coreFileWriteBin(filePath, pcm, totalSize, 0),;)
  122.  
  123.  
  124.   //restore pointers before returning
  125.   pcm->userdata = userdata,  pcm->data = data;
  126.  
  127.  
  128.   /*!err*/ return  0;
  129.   _error_: return -1;
  130. }
  131.  
  132.  
  133.  
  134.  
  135. int kit_acodecPCMSetNumSamples(kit_acodecPCM** pcm_p, Uint64 numSamples){
  136.   _IF_SDLERR(pcm_p==NULL,;,"!pcm_p")
  137.   kit_acodecPCM* pcm = *pcm_p;
  138.   _IF_SDLERR(pcm==NULL,;,"!*pcm_p")
  139.  
  140.  
  141.   kit_acodecPCM _pcm = *pcm;
  142.   Uint8 bitsPerSample = SDL_AUDIO_BITSIZE(_pcm.format);
  143.   _pcm.numSamples   = numSamples;
  144.   _pcm.dataSize     = (bitsPerSample*_pcm.channels*numSamples)/8;
  145.   if(_pcm.bitRemainder) ++_pcm.dataSize; //offsets integer division truncation
  146.  
  147.  
  148.   size_t oldSize = pcm->headerSize + pcm->dataSize;
  149.   size_t newSize = _pcm.headerSize + _pcm.dataSize;
  150.   _IF_GOTO_ERROR(kit_coreRealloc(&pcm, oldSize,newSize),;)
  151.  
  152.  
  153.   *pcm = _pcm;
  154.   pcm->data = (void*)pcm + pcm->headerSize;
  155.   *pcm_p = pcm; //apply changes only if realloc succeeded
  156.  
  157.   /*!err*/ return  0;
  158.   _error_: return -1;
  159. }
  160.  
  161.  
  162.  
  163. kit_acodecPCM* kit_acodecPCMConvertStereo(kit_acodecPCM* pcm, SDL_bool toStereo){
  164.   kit_acodecPCM* pcmOut = NULL;
  165.   SDL_bool success = SDL_FALSE;
  166.   _IF_SDLERR(pcm==NULL,;,"!pcm")
  167.   _IF_SDLERR(pcm->channels==0,;,"pcm->channels=0")
  168.   _IF_SDLERR(pcm->channels>2,;,"pcm->channels>2")
  169.  
  170.   SDL_AudioFormat format = pcm->format;
  171.   Uint64      numSamples = pcm->numSamples;
  172.   Uint32      sampleRate = pcm->sampleRate;
  173.   Uint16      channelsIn = pcm->channels;
  174.   Uint16     channelsOut = 1+toStereo;
  175.   if(channelsIn == channelsOut) return kit_acodecPCMCopy(pcm);
  176.  
  177.  
  178.   pcmOut = kit_acodecPCMCreate(format, channelsOut, sampleRate, numSamples);
  179.   _IF_GOTO_ERROR(pcmOut==NULL,;)
  180.   kit_acodecPCMSamples in  = { .data = pcm->data    };
  181.   kit_acodecPCMSamples out = { .data = pcmOut->data };
  182.  
  183.  
  184.   if(toStereo){
  185.     #define _TO_STEREO(_type)  out._type[i].l = out._type[i].r
  186.     switch(format){
  187.     case AUDIO_U8 : for(Uint64 i=0; i<numSamples; ++i){ _TO_STEREO(u_8s) = in.u_8[i]; } break;
  188.     case AUDIO_S16: for(Uint64 i=0; i<numSamples; ++i){ _TO_STEREO(i16s) = in.i16[i]; } break;
  189.     case AUDIO_S32: for(Uint64 i=0; i<numSamples; ++i){ _TO_STEREO(i32s) = in.i32[i]; } break;
  190.     case AUDIO_F32: for(Uint64 i=0; i<numSamples; ++i){ _TO_STEREO(f32s) = in.f32[i]; } break;
  191.     default: _IS_SDLERR(;,"unknown format 0x%04X",format) }
  192.  
  193.   } else { //to mono
  194.     #define _FROM_STEREO(_type)  (in._type[i].l + in._type[i].r) * 0.5f
  195.     switch(format){
  196.     case AUDIO_U8 : for(Uint64 i=0; i<numSamples; ++i){ out.u_8[i] = _FROM_STEREO(u_8s); } break;
  197.     case AUDIO_S16: for(Uint64 i=0; i<numSamples; ++i){ out.i16[i] = _FROM_STEREO(i16s); } break;
  198.     case AUDIO_S32: for(Uint64 i=0; i<numSamples; ++i){ out.i32[i] = _FROM_STEREO(i32s); } break;
  199.     case AUDIO_F32: for(Uint64 i=0; i<numSamples; ++i){ out.f32[i] = _FROM_STEREO(f32s); } break;
  200.     default: _IS_SDLERR(;,"unknown format 0x%04X",format) }
  201.  
  202.   }
  203.  
  204.  
  205.   success = SDL_TRUE;
  206.   _error_:
  207.   if(!success) kit_acodecPCMDestroy(&pcmOut);
  208.   return pcmOut;
  209. }
  210.  
  211.  
  212.  
  213. kit_acodecPCM* kit_acodecPCMConvertFormat(kit_acodecPCM* pcm, SDL_AudioFormat format){
  214.   kit_acodecPCM* pcmOut = NULL;
  215.   float* f32_buffer = NULL;
  216.   SDL_bool success = SDL_FALSE;
  217.   _IF_SDLERR(pcm==NULL,;,"!pcm")
  218.   if(pcm->format == format) return kit_acodecPCMCopy(pcm);
  219.  
  220.  
  221.   Uint64 numSamples = pcm->numSamples;
  222.   Uint32 sampleRate = pcm->sampleRate;
  223.   Uint16 channels   = pcm->channels;
  224.   Uint64 numSamplesRaw = numSamples*channels;
  225.   size_t f32_buffer_size = numSamplesRaw*sizeof(float);
  226.  
  227.  
  228.   //input will be converted to f32 as an intermediate format...
  229.   f32_buffer = SDL_malloc(f32_buffer_size);
  230.   _IF_SDLERR(f32_buffer==NULL,;,"!malloc")
  231.  
  232.   float sample;
  233.   Uint8*  u_8_samples;  Sint16* i16_samples;
  234.   Sint32* i32_samples;  float*  f32_samples;
  235.   switch(pcm->format){
  236.   case AUDIO_U8 : u_8_samples = pcm->u_8;
  237.   for(Uint64 i=0; i<numSamplesRaw; ++i){
  238.     sample = (float)(u_8_samples[i]-0x80) * invi_8;
  239.     f32_buffer[i] = (sample>=-1.0f) ? sample : -1.0f;
  240.   } break;
  241.  
  242.   case AUDIO_S16: i16_samples = pcm->i16;
  243.   for(Uint64 i=0; i<numSamplesRaw; ++i){
  244.     sample = (float)i16_samples[i] * invi16;
  245.     f32_buffer[i] = (sample>=-1.0f) ? sample : -1.0f;
  246.   } break;
  247.  
  248.   case AUDIO_S32: i32_samples = pcm->i32;
  249.   for(Uint64 i=0; i<numSamplesRaw; ++i){
  250.     sample = (float)i32_samples[i] * invi32;
  251.     f32_buffer[i] = (sample>=-1.0f) ? sample : -1.0f;
  252.   } break;
  253.  
  254.   case AUDIO_F32: f32_samples = pcm->f32;
  255.   for(Uint64 i=0; i<numSamplesRaw; ++i){
  256.     sample = f32_samples[i];
  257.     f32_buffer[i] = CLAMP(sample, -1.0f,1.0f);
  258.   } break;
  259.  
  260.   default: _IS_SDLERR(;,"input format=0x%04X",pcm->format) }
  261.  
  262.  
  263.   //...before being converted from f32 to the output format
  264.   pcmOut = kit_acodecPCMCreate(format, channels, sampleRate, numSamples);
  265.   _IF_GOTO_ERROR(pcmOut==NULL,;)
  266.  
  267.   switch(format){
  268.   case AUDIO_U8 : u_8_samples = pcmOut->u_8;
  269.   for(Uint64 i=0; i<numSamplesRaw; ++i){
  270.     u_8_samples[i] = f32_samples[i]*I_8_MAX + 0x80;
  271.   } break;
  272.  
  273.   case AUDIO_S16: i16_samples = pcmOut->i16;
  274.   for(Uint64 i=0; i<numSamplesRaw; ++i){
  275.     i16_samples[i] = f32_samples[i]*I16_MAX;
  276.   } break;
  277.  
  278.   case AUDIO_S32: i32_samples = pcmOut->i32;
  279.   for(Uint64 i=0; i<numSamplesRaw; ++i){
  280.     i32_samples[i] = f32_samples[i]*I32_MAX;
  281.   } break;
  282.  
  283.   //lol
  284.   case AUDIO_F32: kit_coreMemcpy(pcmOut->f32, f32_buffer, f32_buffer_size); break;
  285.  
  286.   default: _IS_SDLERR(;,"output format=0x%04X",format) }
  287.  
  288.  
  289.   success = SDL_TRUE;
  290.   _error_:
  291.   if(!success) kit_acodecPCMDestroy(&pcmOut);
  292.   if(f32_buffer != NULL) SDL_free(f32_buffer);
  293.   return pcmOut;
  294. }
  295.  
  296.  
  297.  
  298. //linear interpolation
  299. static inline int _kit_acodecPCMResampleLinear(kit_acodecPCM* pcmIn, kit_acodecPCM* pcmOut,
  300.                                                double ratio, Uint16 channels, Uint64 numSamplesRaw)
  301. {
  302.   #define _SIMLERP(_v0,_v1, _t) ( (_v0) + (_t)*((_v1)-(_v0)) )
  303.   double src_pos = 0; //source position, in sample frames
  304.   double pos_mod; // = src_pos % 1
  305.   Uint64 pos_int;
  306.  
  307.   switch(pcmOut->format){
  308.   /*
  309.   case AUDIO_U8 :; Uint8*  u_8_src = pcmIn->u_8,  *u_8_dst = pcmOut->u_8;
  310.     Uint8 u_8_smp0, u_8_smp1;
  311.   case AUDIO_S16:; Sint16* i16_src = pcmIn->i16,  *i16_dst = pcmOut->i16;
  312.     Sint32 i16_smp0, i16_smp1;
  313.   case AUDIO_S32:; Sint32* i32_src = pcmIn->i32,  *i32_dst = pcmOut->i32;
  314.     Sint32 i32_smp0, i32_smp1;
  315.   */
  316.   case AUDIO_F32:; float*  f32_src = pcmIn->f32,  *f32_dst = pcmOut->f32;
  317.     for(Uint64 s=0; s<numSamplesRaw; s+=channels){
  318.       pos_int = src_pos;
  319.       pos_mod = src_pos-pos_int;
  320.       pos_int *= channels;
  321.       for(Uint32 c=0; c<channels; ++c){
  322.         float f32_smp0 = f32_src[pos_int + c];
  323.         float f32_smp1 = f32_src[pos_int + c + channels];
  324.         f32_dst[s+c] = _SIMLERP(f32_smp0,f32_smp1, pos_mod);
  325.       }
  326.       src_pos += ratio;
  327.     } break;
  328.  
  329.   default: _IS_SDLERR(;,"unknown format 0x%04X",pcmOut->format)
  330.   }
  331.  
  332.   /*!err*/ return  0;
  333.   _error_: return -1;
  334. }
  335. //nearest neighbor interpolation
  336. static inline int _kit_acodecPCMResampleNearest(kit_acodecPCM* pcmIn, kit_acodecPCM* pcmOut,
  337.                                                 double ratio, Uint16 channels, Uint64 numSamplesRaw)
  338. {
  339.   double src_pos = 0; //source position, in sample frames
  340.   Uint64 pos_int;
  341.  
  342.   switch(pcmOut->format){
  343.   case AUDIO_U8 :; Uint8* u_8_src = pcmIn->u_8,  *u_8_dst = pcmOut->u_8;
  344.     for(Uint64 s=0; s<numSamplesRaw; s+=channels){
  345.       pos_int = src_pos+0.5; pos_int *= channels;
  346.       for(Uint32 c=0; c<channels; ++c)
  347.         u_8_dst[s + c] = u_8_src[pos_int + c];
  348.       src_pos += ratio;
  349.     } break;
  350.  
  351.   case AUDIO_S16:; Sint16* i16_src = pcmIn->i16,  *i16_dst = pcmOut->i16;
  352.     for(Uint64 s=0; s<numSamplesRaw; s+=channels){
  353.       pos_int = src_pos+0.5;  pos_int *= channels;
  354.       for(Uint32 c=0; c<channels; ++c)
  355.         i16_dst[s + c] = i16_src[pos_int + c];
  356.       src_pos += ratio;
  357.     } break;
  358.  
  359.   case AUDIO_S32:; Sint32* i32_src = pcmIn->i32,  *i32_dst = pcmOut->i32;
  360.     for(Uint64 s=0; s<numSamplesRaw; s+=channels){
  361.       pos_int = src_pos+0.5;  pos_int *= channels;
  362.       for(Uint32 c=0; c<channels; ++c)
  363.         i32_dst[s + c] = i32_src[pos_int + c];
  364.       src_pos += ratio;
  365.     } break;
  366.  
  367.   case AUDIO_F32:; float* f32_src = pcmIn->f32,  *f32_dst = pcmOut->f32;
  368.     for(Uint64 s=0; s<numSamplesRaw; s+=channels){
  369.       pos_int = src_pos+0.5;  pos_int *= channels;
  370.       for(Uint32 c=0; c<channels; ++c)
  371.         f32_dst[s + c] = f32_src[pos_int + c];
  372.       src_pos += ratio;
  373.     } break;
  374.  
  375.   default: _IS_SDLERR(;,"unknown format 0x%04X",pcmOut->format)
  376.   }
  377.  
  378.   /*!err*/ return  0;
  379.   _error_: return -1;
  380. }
  381. kit_acodecPCM* kit_acodecPCMResample(kit_acodecPCM* pcm, Uint32 sampleRate,
  382.                                      SDL_bool linearInterpolation)
  383. {
  384.   kit_acodecPCM* pcmOut = NULL;
  385.   SDL_bool success = SDL_FALSE;
  386.   _IF_SDLERR(pcm==NULL,;,"!pcm")
  387.   _IF_SDLERR(pcm->sampleRate==0,;,"pcm->sampleRate=0")
  388.   _IF_SDLERR(sampleRate==0,;,"sampleRate=0")
  389.   linearInterpolation &= 1;
  390.  
  391.  
  392.   SDL_AudioFormat   format = pcm->format;
  393.   Uint16          channels = pcm->channels;
  394.   double             ratio = (double)pcm->sampleRate/sampleRate;
  395.   Uint64        numSamples = pcm->numSamples*ratio;
  396.   Uint64     numSamplesRaw = numSamples*channels;
  397.  
  398.   pcmOut = kit_acodecPCMCreate(format, channels, sampleRate, numSamples);
  399.   _IF_GOTO_ERROR(pcmOut==NULL,;)
  400.   pcmOut->loopStart = pcm->loopStart;
  401.   pcmOut->loopEnd   = pcm->loopEnd;
  402.   pcmOut->loopCount = pcm->loopCount;
  403.   pcmOut->userflags = pcm->userflags;
  404.   pcmOut->uservalue = pcm->uservalue;
  405.   pcmOut->userdata  = pcm->userdata;
  406.  
  407.  
  408.   if(linearInterpolation){
  409.     _IF_GOTO_ERROR(_kit_acodecPCMResampleLinear(pcm,pcmOut, ratio,
  410.                                                 channels,numSamplesRaw),;)
  411.   } else { //otherwise, use nearest neighbor interpolation
  412.     _IF_GOTO_ERROR(_kit_acodecPCMResampleNearest(pcm,pcmOut, ratio,
  413.                                                  channels,numSamplesRaw),;)
  414.   }
  415.  
  416.  
  417.   success = SDL_TRUE;
  418.   _error_:
  419.   if(!success) kit_acodecPCMDestroy(&pcmOut);
  420.   return pcmOut;
  421. }
  422.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement