PDA

View Full Version : How to retrieve Playing QTMovie volume level?




Aquis
Apr 2, 2008, 04:54 PM
Okay, so I've loaded a sound as a QTMovie instance and I've played it. What I'd like to do is periodically check the current volume level so that I can put it into (a single) NSLevelInidcator, similar to the two which reside in GarageBand. I've been looking for some method's to do this for ages, but haven't found anything which relates to what I'm after. Is there a way for me to check how "loud" a QTMovie instance is playing at a particular moment?

Thanks!



kainjow
Apr 2, 2008, 05:36 PM
Look at the volume and setVolume: methods :)

HiRez
Apr 2, 2008, 06:15 PM
Are you looking for the overall volume of the movie, or the loudness/level at any given point in the movie (in other words, you want dynamic level metering)? If the latter, you can't do that from Cocoa AFAIK, you'll probably have to dig into the QuickTime or CoreAudio C-based APIs to do it, which is non-trivial (read: a PITA if you're not familiar with this).

Aquis
Apr 3, 2008, 07:46 AM
Yeah, I'm looking for the volume at a particular point, so unfortunately it's not as simple as the volume:, setVolume: methods. But, HiRez, your dynamic based metering is exactly what I want. Shame I can't do that with Cocoa, but thanks for the tips! I'll have a look at them and see if I can get them to work...

Thanks again!

HiRez
Apr 3, 2008, 04:54 PM
Yeah, I'm looking for the volume at a particular point, so unfortunately it's not as simple as the volume:, setVolume: methods. But, HiRez, your dynamic based metering is exactly what I want. Shame I can't do that with Cocoa, but thanks for the tips! I'll have a look at them and see if I can get them to work...Actually it looks like they added some support in QuickTime 7 to make this a lot easier (not from QTKit, but not too hard to implement from a Cocoa-based app). Check out this tech note (http://developer.apple.com/qa/qa2005/qa1459.html) to find out about it. For reference, here's how I was doing it using CoreAudio (it's a Cocoa project, but using the C CoreAudio API):
- (void)updateAudioMetering:(NSTimer*)aTimer {
Float32 lVol;
Float32 *lVolPtr = &lVol;

err = AudioUnitGetParameter(triggerMixUnit, kStereoMixerParam_PostAveragePower+0, kAudioUnitScope_Output, 0, lVolPtr);
NSAssert(err == noErr, @"Reading left channel post average power failed.");

Float32 rVol;
Float32 *rVolPtr = &rVol;

err = AudioUnitGetParameter(triggerMixUnit, kStereoMixerParam_PostAveragePower+1, kAudioUnitScope_Output, 0, rVolPtr);
NSAssert(err == noErr, @"Reading right channel post average power failed.");

float left = *lVolPtr;
float right = *rVolPtr;

[leftMeterView setValue:left];
[leftMeterView setNeedsDisplay:YES];
if ([[self currentTrack] channelCount] == 1) { // mono
[rightMeterView setValue:left];
[rightMeterView setNeedsDisplay:YES];
}
}

Aquis
Apr 5, 2008, 03:44 AM
Thanks a lot for the code and the link! After looking at the example provided by the link, I decided to subclass QTMovie to give it extra functionality - i.e. giving it a method to return the volume level at a current point. Unfortunately, I'm getting a rather cryptic error when trying to build it - the error being, "symbol(s) not found" and the, I assume, symbols being the functions SetMovieAudioFrequencyMeteringNumBands and GetMovieAudioFrequencyLevels - the only thing I can think of is that I need to include their header files, but I'm not sure where to locate them. In any case, here's the class I made - it'd probably be full of errors anyway, but...

LoadedMovie.h
#import <Cocoa/Cocoa.h>
#import <QTKit/QTKit.h>

@interface LoadedMovie : QTMovie {
unsigned long numberOfBandLevels;
unsigned long numberOfChannels;

QTAudioFrequencyLevels *freqResults;
}

+(id)movieFromFile:(NSString *)file;
-(float)currentVolumeLevel;

@end

LoadedMovie.m
#import "LoadedMovie.h"


@implementation LoadedMovie
- init {
if ((self = [super init])) {
numberOfBandLevels = 1;
numberOfChannels = 1;
freqResults = NULL;
}
return self;
}

-(void)initBands {
SetMovieAudioFrequencyMeteringNumBands([self quickTimeMovie], kQTAudioMeter_MonoMix, &numberOfBandLevels);
freqResults = malloc(offsetof(QTAudioFrequencyLevels,level[numberOfBandLevels * numberOfChannels]));
freqResults->numChannels = numberOfChannels;
freqResults->numFrequencyBands = numberOfBandLevels;
}

+(id)movieFromFile:(NSString *)file {
LoadedMovie * mov = [LoadedMovie movieWithFile:file error:nil];
[mov initBands];
return mov;
}

-(float)currentVolumeLevel {
GetMovieAudioFrequencyLevels([self quickTimeMovie], kQTAudioMeter_MonoMix, freqResults);
return freqResults->level[0];
}
@end

Hope you can help, and thanks again!

kainjow
Apr 5, 2008, 09:19 AM
Maybe you need to link in the QuickTime framework directly, in addition to QTKit?

Aquis
Apr 5, 2008, 11:53 AM
Hmmm,well I have placed the QTKit.framework in the frameworks folder - I don't believe there is anything else I need to do?

Also, I added a completely random function (random letters) and I got exactly the same error - the compiler really hasn't heard of them before...

EDIT: Sorry, yes I see what you mean, I'll try that...
EDIT: Yes, thanks! How could I have been so stupid! Now all I'm trying to figure out is why I keep getting a value of 2.000001 from currentVolumeLevel...

Aquis
Apr 14, 2008, 08:56 AM
Well, after much fiddling and moving the code from the subclass I made, it works! Now, I have one more last question about this topic...

I have so many, say 10, bars for the volume levels of the different frequencies. How to I change that into one bar? I.e., how do I find the current volume level for all the bands based on the know values of several bands? At the moment, I'm averaging them, but I doubt that's the right way to do it...I've also thought that it may be the max of all the frequencies, but that doesn't seem right either...

Thanks!