How to write a wrapper?

Started by Midimaster, April 01, 2021, 14:59:29

Previous topic - Next topic

Midimaster

#165
Ok, miniaudio was also able to read the file returned by an online compressor. but....

there is no defined "PCM compressed format" (wikipedia). If a WAV-file looks like "compressed" the file remains only a container for other compressing formats. The "online compressor" shrinked my 44.1kHz to a 16kHz-anything with a undefined loss of quality without asking me. This is not what I would expect from a compressor. It looks like this "compression" is a "you never know, what you get"-compression.

Wikipedia points to old Win32 documentations for more information about  some "compressed" formats, but tell also, that they are all obsolet.

Compared to OGG or MP3 the results of this "WAV-compression "are unacceptable and unpredictable. Modern compression like you find it in FLAC is even lossless.


My original WAV was  1000kB
as ZIP it was 440kB
"compressed WAV" was 143kB
High quality OGG (level10) was 28kB



...back from Egypt

iWasAdam

one thing the have in the back of your mind about compression:
when the file is loaded and uncompressed - it takes up the amount of space it needs - not the amount on disk.

So in the above case of the 28k ogg - when it is loaded it will take up 1000k in memory

Now there is a way to make smaller memory use - half the file. take every other frame throw it away to make a new file half the size. To compensate on pitch you now need to lower any note values by 1 octave.

In general terms this works well for at least 1 or 2 times. beyond 3 or with very poor samples in the first place, sound degradation becomes noticeable

Streaming isn't an issue as that is doing something very different to simple playback
:)

Midimaster

I dont need to care about compression ratio. MiniAudio unpacks any files and return unkompressed PCM samples and tells me the space I need.

It is a two step loading procedure. first step tells me format, channels, length, frequency, etc.. so I can prepare the RAM for the content. Second step is filling this RAM with the datas.

There is also no need for making memory use smaller. For me is important quality first.


Did you check my example app in the main thread of speeding up speech without changing frequency in realtime?
https://www.syntaxbomb.com/index.php/topic,8419.msg347049834.html#msg347049834

Are you fit with FFT? HAMMING WINDOW? BIQUAD FILTERS?
...back from Egypt

iWasAdam

compression only becomes an issue if you are using audio for games where the smallest best sound is always needed ;)

I haven't checked the speech sample yet. but I'm interested to see how you did it.

FFT, filters is also something that is on my list. I have a variant FFT that 'generally' works but it's not brilliant. lol

Midimaster

#169
A user reported a bug under MAC OSX:

report was:
56: error: use of undeclared identifier 'id'      DEBUG_OUTPUT("Unregistering thread handle: 0x00000001\n", id);


We will change this immediately. But here is already a quick solution:
Go to miniaudiowrapper.c to line 63 and change
...
void mimaOnMAThreadExit() {
   void* handle = pthread_self();
   DEBUG_OUTPUT("Unregistering thread handle: 0x%08x\n", id);
   mimaThread** Threads = &maThreads;
....


with marking out this line:
...
void mimaOnMAThreadExit() {
   void* handle = pthread_self();
   //DEBUG_OUTPUT("Unregistering thread handle: 0x%08x\n", id);
   mimaThread** Threads = &maThreads;
...


perhaps this will be all that is necessary.

@Col: This happens only on MAC. I will replace this with:
...
   DEBUG_OUTPUT("Unregistering thread handle: 0x%08x\n", handle);
...



Testers wanted

It will be helpful, if some more members of the board could test the miniaudio.mod and report what they think about it. The source code is now avaiable at:
https://github.com/MidimasterSoft/BlitzMax-Miniaudio-Wrapper

Also the user reported, that there is still a lot of debug information displayed when you are using the module in your app. At the moment this still helps us to get detailed reports from the user but we will remove this in some days when we are going to publish the first stabil version.

...back from Egypt

Midimaster

Meanwhile the wrapper handles all audio formats from 8bit 16bit 32bit to 32bit-float. There is also a decoder for opening audio file and convert the content into any format you need. But this now caused a lot of very similar code (functions):

//one pass decoding 16bit:
int MM_Decode16bit(char* FileName, short *TSampleRAM){
printf("MM DECODER ONE PASS 16bit  \n");
ma_decoder_config audioConfig = ma_decoder_config_init(ma_format_s16, 0, 0);
long long frameCount;
short* pAudioData;
int result = ma_decode_file(FileName, &audioConfig, &frameCount, &pAudioData);
if(audioConfig.channels>2){
DEBUG_OUTPUT("ERROR NOT MONO or STEREO!!! Channels=%i \n", audioConfig.channels );
return 0;
}
    int i;
for (i=0; i<(frameCount*audioConfig.channels); i++){
TSampleRAM[i] =  pAudioData[i];
}
DEBUG_OUTPUT("------ \n");
return 1;
}





//one pass decoding 32bit float:
int MM_Decode32float(char* FileName, float *TSampleRAM){
printf("MM DECODER ONE PASS 32bit \n");
ma_decoder_config audioConfig = ma_decoder_config_init(ma_format_f32, 0, 0);
long long frameCount;
float* pAudioData;
int result = ma_decode_file(FileName, &audioConfig, &frameCount, &pAudioData);
   
int i;
for (i=0; i<(frameCount*audioConfig.channels); i++){
TSampleRAM[i] =  pAudioData[i];
}
DEBUG_OUTPUT("------ \n");
return 1;
}



//one pass decoding 32bit int:
int MM_Decode32(char* FileName, int *TSampleRAM){
printf("MM DECODER ONE PASS 32bit \n");
ma_decoder_config audioConfig = ma_decoder_config_init(ma_format_s32, 0, 0);
long long frameCount;
int* pAudioData;
int result = ma_decode_file(FileName, &audioConfig, &frameCount, &pAudioData);
   
int i;
for (i=0; i<(frameCount*audioConfig.channels); i++){
TSampleRAM[i] =  pAudioData[i];
}
DEBUG_OUTPUT("------ \n");
return 1;
}




I want to combine them into one function.
Now is my question is it better to do this with void pointers or should I simply work with byte pointer and only change the amount of loops in the FOR/NEXT?

Is this possible?
The function start with a parameter void pointer. Then this pointer will be casted to a INT pointer.
//one pass decoding 32bit int:
// format would be FORMAT_S32
int MM_Decode_Universal(char* FileName, void *TSampleRAM){
printf("MM DECODER ONE PASS 32bit \n");
ma_decoder_config audioConfig = ma_decoder_config_init(format, 0, 0);
long long frameCount;
int* pAudioData;
//????????????????????
        TSampleRAM = (int*) TSampleRam;
//????????????????????
int result = ma_decode_file(FileName, &audioConfig, &frameCount, &pAudioData);
   
int i;
for (i=0; i<(frameCount*audioConfig.channels); i++){
TSampleRAM[i] =  pAudioData[i];
}
DEBUG_OUTPUT("------ \n");
return 1;
}

If this would be possible I could use a simple SWITCH-CASE to differ between the formats.
...back from Egypt

col

Quote
@Col: This happens only on MAC. I will replace this with:
...
   DEBUG_OUTPUT("Unregistering thread handle: 0x%08x\n", handle);
...

Oops. Sorry about that!
I only have a Windows unit to test on, but still it is pretty obvious it would error out at that point so please accept my apologies.
https://github.com/davecamp

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

Midimaster

no problem. I remembered that you had no chance to test it on MAC, so I knew it must be a typo not a bug. Did you see my question about unifying four functions into one? What do you think about it?

I'm so glad you help me in this project.

...back from Egypt

col

QuoteAlso the user reported, that there is still a lot of debug information displayed when you are using the module in your app

You could tweak the wrapper to only output that information for debug builds only?

To do that you would change every printf statement in the wrapper to use the DEBUG_OUTPUT macro that's in there.
For example change:

printf("MM CREATE CONTEXT \n");
to
DEBUG_OUTPUT("MM CREATE CONTEXT \n");

then modify the DEBUG_OUTPUT piece of code from:

#define DEBUG_OUTPUT(...) printf(__VA_ARGS__); fflush(0)


to

#if !defined(NDEBUG)
#define DEBUG_OUTPUT(...) printf(__VA_ARGS__); fflush(0)
#define MA_DEBUG_OUTPUT
#else
#define DEBUG_OUTPUT
#endif


The debug information will only ever appear in debug builds  8)


PS.
You don't need #define MA_BLITZMAX_THREAD_COMPATIBILITY anymore now that the miniaudio author added in the MA_ON_THREAD_ENTRY and MA_ON_THREAD_EXIT macros that are used. So #define MA_BLITZMAX_THREAD_COMPATIBILITY can be removed from the wrapper.


https://github.com/davecamp

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

col

QuoteDid you see my question about unifying four functions into one? What do you think about it?
You could easily do that yes.

Being able to casually cast from one type of pointer to any other type of pointer is one of the strengths (and weakness) of C and C++.
https://github.com/davecamp

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

wadmixfm

actually it does it on windows as well when i run my compiled program i still get the black box and this :-

MM CREATE CONTEXT
length of  context 544
: Attempting to initialize WASAPI backend...
[miniaudio] Endian:  LE
[miniaudio] SSE2:    YES
[miniaudio] AVX2:    NO
[miniaudio] AVX512F: NO
[miniaudio] NEON:    NO
list of playback devices:
0 - Speaker/HP (2- Realtek High Definition Audio)
list of capture devices:
START_DEVICE_GLUE
------
FILL_VALUE_B
CREATE A DEVICE
INFO: [WASAPI]
INFO:   Speaker/HP (2- Realtek High Definition Audio) (Playback)
INFO:     Format:      16-bit Signed Integer -> 32-bit IEEE Floating Point
INFO:     Channels:    2 -> 2
INFO:     Sample Rate: 44000 -> 44000
INFO:     Buffer Size: 440*3 (1320)
INFO:     Conversion:
INFO:       Pre Format Conversion:    NO
INFO:       Post Format Conversion:   YES
INFO:       Channel Routing:          NO
INFO:       Resampling:               NO
INFO:       Passthrough:              NO


cheers

Lee


wadmixfm

to be honest , i have not tried it on mac even though i have written the app for both platforms

on the mac the latency is spot on and thus i dont need the mod

but windows on the other hand is a pain in the rear :)

the mod is doing a great job but i dont want the cmd prompt box on startup of my program :)

Lee

col

Quotethe mod is doing a great job but i dont want the cmd prompt box on startup of my program

Sounds like you have the IDE set to build a 'console' app, try setting it to build a 'gui' app instead?

Quoteactually it does it on windows
Does what?  :P
Still outputs the debug data?
Did you rebuild the module after the changes I suggested above?

The debug data will only be there when you run a 'debug build'. When you create a 'release build' you won't see any of that data.

https://github.com/davecamp

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

wadmixfm

yes Col Thank you

i have sorted it

i did not build the wrapper again

hehe

it works a treat now

lee

wadmixfm

ok

i get this when exiting the app

: Attempting to initialize WASAPI backend...
[miniaudio] Endian:  LE
[miniaudio] SSE2:    YES
[miniaudio] AVX2:    NO
[miniaudio] AVX512F: NO
[miniaudio] NEON:    NO
INFO: [WASAPI]
INFO:   Speaker/HP (2- Realtek High Definition Audio) (Playback)
INFO:     Format:      16-bit Signed Integer -> 32-bit IEEE Floating Point
INFO:     Channels:    2 -> 2
INFO:     Sample Rate: 44000 -> 44000
INFO:     Buffer Size: 440*3 (1320)
INFO:     Conversion:
INFO:       Pre Format Conversion:    NO
INFO:       Post Format Conversion:   YES
INFO:       Channel Routing:          NO
INFO:       Resampling:               NO
INFO:       Passthrough:              NO

Process complete

is this because i have not closed the miniaudio on exit ???

lee