bartolsthoorn / NVDSP

iOS/OSX DSP for audio (with Novocaine)
MIT License
413 stars 80 forks source link

NVDSP not work with audioUnit render? #10

Closed jeffkit closed 10 years ago

jeffkit commented 10 years ago

I wrote a recorder in remote IO Unit.I want to calculate the sound level of the samples in the render callback. I found NVDSP project have an util method to getDBLevel:

- (float) getdBLevel:(float *)data numFrames:(UInt32)numFrames numChannels:(UInt32)numChannels;

So, I try to pass the AudioBuffer as parameters of this method:

static OSStatus performRender(void *inRefCon,
                          AudioUnitRenderActionFlags    *ioActionFlags,
                          const AudioTimeStamp      *inTimeStamp,
                          UInt32                        inBusNumber,
                          UInt32                        inNumberFrames,
                          AudioBufferList           *ioData){

AudioBuffer buf = ioData->mBuffers[0];
float db = [[[NVSoundLevelMeter alloc] init] getdBLevel:buf.mData numFrames:inNumberFrames numChannels:buf.mNumberChannels];

but this is not work as expect, it always return -50db.

Any idea?

bartolsthoorn commented 10 years ago

I think the way you are getting the buffer and numFrames and numChannels is correct. The problem is that the SoundLevelMeter code works with something like a moving average, and it seems you are re-allocating a new LevelMeter every render. You can see what I'm talking about at this line: NVSoundLevelMeter.m#L31. A few lines further you can also see that the first time you run it, it will start with -50dB.

So if it's possible in your design, alloc/init the SoundLevelMeter once and reuse it again and again on the buffers as you are processing them. The first time you run it the dBLevel will be -50dB but running it again will allow it to 'come up' from -50 dB.

The reason why I implemented it this way is because if your buffers are really small this will provide a more sensible (slower) dB signal. It's not the only solution but it worked for my applications. After a few buffers (less than a second in most of my cases) it's at a reasonable level and also changes quickly enough with changes in sound level. It's also a performance increase to allocate once and re-use the same thing again.

Please let me know if this works for you!

jeffkit commented 10 years ago

Thank you for reply! I followed you advise, alloc/init the soundLevelMeter only once。but it still not work for me, I got another db value '-inf'. Here is the log: 2014-02-24 10:51:02.889 Demo[46318:9107] db value -50.00 2014-02-24 10:51:02.897 Demo[46318:9107] db value -inf 2014-02-24 10:51:02.908 Demo[46318:9107] db value -50.00 2014-02-24 10:51:02.920 Demo[46318:9107] db value -inf 2014-02-24 10:51:02.932 Demo[46318:9107] db value -50.00 2014-02-24 10:51:02.943 Demo[46318:9107] db value -inf 2014-02-24 10:51:02.955 Demo[46318:9107] db value -50.00 2014-02-24 10:51:02.966 Demo[46318:9107] db value -inf .........

bartolsthoorn commented 10 years ago

Hmm, that's weird. By the way, I got this dB measuring code by looking at a piece of example code of the library of Novocaine: master/ViewController.m#L85

Try to change the getdBLevel method back to the code below (copied from the example above) You will also have to add the dbVal variable to the header file, and initialise it as 0.0 (dbVal is a block variable in the Novocaine example).

- (float) getdBLevel:(float *)data numFrames:(UInt32)numFrames numChannels:(UInt32)numChannels {
        vDSP_vsq(data, 1, data, 1, numFrames*numChannels);
        float meanVal = 0.0;
        vDSP_meanv(data, 1, &meanVal, numFrames*numChannels);

        float one = 1.0;
        vDSP_vdbcon(&meanVal, 1, &one, &meanVal, 1, 1, 0);
        dbVal = dbVal + 0.2*(meanVal - dbVal);
        printf("Decibel level: %f\n", dbVal);
}

Note that I later added code to make a copy of the data variable, because this measurement of dB will also alter the contents of data, I think it muted it, but I'm not sure. Maybe this fresh code will give you good db values!

jeffkit commented 10 years ago

sadly .. the dbVal is always 'nan'.

bartolsthoorn commented 10 years ago

Have you tried printing meanVal?

bartolsthoorn commented 10 years ago

Did things work out? I think you could also check the way the buffer is formatted vs how the buffer of the Novocaine library is formatted.