Using a void pointer?

Started by Midimaster, June 25, 2021, 08:58:47

Previous topic - Next topic

Midimaster

I tried to reduce three of my C-glue-functions into one. If I could use void-pointers I could use the same same function for the audio formats u8, s16, s32 ans f32.

So I replaced the fix Float-Pointers to universal Void-Pointer and depending on the given format I try o cast them into the necessary type:

before:
//one pass decoding 32bit float:
int MM_Decode32f(float *TSampleRAM){
....
float* pAudioData;
int result = ma_decode_file(...., &pAudioData);
....
for (i=0; i<100; i++){
TSampleRAM[i] =  pAudioData[i];
}
}


after:
//one pass decoding all formats:
int MM_Decode( void* TSampleRAM, int format){
...
void* pAudioData;
switch (format) {
....
case ma_format_f32:
TSampleRAM = (float*) TSampleRAM;
pAudioData = (float*) pAudioData;
break;
}
int result = ma_decode_file(...., &pAudioData);
...
for (i=0; i<100; i++){
TSampleRAM[i] =  pAudioData[i];
}
}


But now I get the Error Message:
C:/BlitzMaxNG/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c: In function 'MM_Decode':
C:/BlitzMaxNG/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:270:17:
error: invalid use of void expression
   TSampleRAM[i] =  pAudioData[i];
                 ^
Build Error: failed to compile (1) C:/BlitzMaxNG/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c
Process complete


What do I forget?
...on the way to Egypt

Steve Elliott


Perhaps you need to de-reference the pointer and typecast too - but use the address of (&TSampleRAM) ?

TSampleRAM = *((float*) &TSampleRAM));
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

Midimaster

wow! that looks complicate...

C is still not "my world"

Thank you steve. I will try it out immediately.
...on the way to Egypt

Midimaster

It looks like your's is no solution. I corrected the brackets. (was one to much):
int MM_Decode( void* TSampleRAM, int format){
...
TSampleRAM = *((float*) &TSampleRAM);



but already this gives a new error message:
C:/BlitzMaxNG/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c: In function 'MM_Decode':
C:/BlitzMaxNG/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:246:13:
error: incompatible types when assigning to type 'void *' from type 'float'

  TSampleRAM = *((float*) &TSampleRAM);
             ^



I tried a new approach:

This would work:
int MM_Decode( void* TSampleRAM, int format){
...
float* TSampleRAM_II;
TSampleRAM_II = (float *) TSampleRAM;
...
for (i=0; i<(frameCount*audioConfig.channels); i++){
TSampleRAM_II[i] =  1;
}


but when I try this inside the switch, it again does not compile:
int MM_Decode( void* TSampleRAM, int format){
...
switch (format) {
case ma_format_f32:
float* TSampleRAM_II;
TSampleRAM_II = (float *) TSampleRAM;
break;
}
...
for (i=0; i<(frameCount*audioConfig.channels); i++){
TSampleRAM_II[i] =  1;
}


now the error message is:
C:/BlitzMaxNG/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c: In function 'MM_Decode':
C:/BlitzMaxNG/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:252:4: error: a label can only be part of a statement and a declaration is not a statement
    float* TSampleRAM_II;
    ^~~~~
C:/BlitzMaxNG/mod/mima.mod/miniaudio.mod/miniaudiowrapper.c:259:3: error: 'TSampleRAM_II' undeclared (first use in this function)
   TSampleRAM_II[i] =  1;
   ^~~~~~~~~~~~~
...on the way to Egypt

Steve Elliott

Ah, it was off the top of my head.  But I wouldn't use void pointers anyway, I would use C++ function overloading for this, so you have the same functions but the data type variance would mean C++ would select the correct version:


eg)

calc( int data ) {
...
}

calc( float data ) {
...
}

So now if you call calc with calc( 4.5 ); then C++ would know to use the floating point version.


But if you have large functions then I would suggest breaking your functions into smaller functions.  Getting crazy with pointers can lead to confusing bug ridden code.
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

col

#5
Or template the function. One function, one code body, multiples types.
:)

Oh yeah, you're using c, and not c++ so templates dont exist in c.
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Steve Elliott

Aw C mainly, with a little C++ where absolutely necessary IMO Col lol.
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

col

but c doesn't have proper function overloading.
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Steve Elliott

I know, the sweet spot for me is C with only a little C++.
Win11 64Gb 12th Gen Intel i9 12900K 3.2Ghz Nvidia RTX 3070Ti 8Gb
Win11 16Gb 12th Gen Intel i5 12450H 2Ghz Nvidia RTX 2050 8Gb
Win11  Pro 8Gb Celeron Intel UHD Graphics 600
Win10/Linux Mint 16Gb 4th Gen Intel i5 4570 3.2GHz, Nvidia GeForce GTX 1050 2Gb
macOS 32Gb Apple M2Max
pi5 8Gb
Spectrum Next 2Mb

col

#9
Each to their own then eh :)

With c++ you can simplify the process to something such as:

template<typename T>
void DoDecode(void* pSampleRAM, void* pAudioData, size_t SampleDataSize)
{
for (size_t i = 0; i < SampleDataSize; i++) {
static_cast<T*>(pSampleRAM)[i] =  static_cast<T*>(pAudioData)[i];
}
}

extern"C"
{
int MM_Decode(char* FileName, void *TSampleRAM, ma_format format){
//DEBUG_OUTPUT("MM DECODER ONE PASS 32bit \n");

ma_decoder_config audioConfig = ma_decoder_config_init(format, 0, 0);
ma_uint64 frameCount;
void* pAudioData;
int result = ma_decode_file(FileName, &audioConfig, &frameCount, &pAudioData);
   
size_t SampleDataSize = frameCount * audioConfig.channels;
switch(format) {
case ma_format_s16:
DoDecode<short>(TSampleRAM, pAudioData, SampleDataSize);
break;
case ma_format_f32:
DoDecode<float>(TSampleRAM, pAudioData, SampleDataSize);
break;
case ma_format_s32:
DoDecode<int>(TSampleRAM, pAudioData, SampleDataSize);
break;
default:
DEBUG_OUTPUT(__FILE__, __LINE__, " Unknown sample format.");
}
DEBUG_OUTPUT("------ \n");
return 1;
}
}
https://github.com/davecamp

"When you observe the world through social media, you lose your faith in it."

Midimaster

this all looks for me looks like better staying on my current version with 4 nearly same functions and differ the cases on the BlitzMax side. This approach is easy and stabil.
...on the way to Egypt