How to retrieve Playing QTMovie volume level?

Discussion in 'Mac Programming' started by Aquis, Apr 2, 2008.

  1. macrumors member

    Joined:
    Aug 7, 2007
    Location:
    Staffordshire, UK
    #1
    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!
     
  2. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
  3. macrumors 601

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #3
    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).
     
  4. thread starter macrumors member

    Joined:
    Aug 7, 2007
    Location:
    Staffordshire, UK
    #4
    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!
     
  5. macrumors 601

    HiRez

    Joined:
    Jan 6, 2004
    Location:
    Western US
    #5
    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 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):
    Code:
    - (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];
    	}
    }
     
  6. thread starter macrumors member

    Joined:
    Aug 7, 2007
    Location:
    Staffordshire, UK
    #6
    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
    Code:
    #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
    Code:
    #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!
     
  7. Moderator emeritus

    kainjow

    Joined:
    Jun 15, 2000
    #7
    Maybe you need to link in the QuickTime framework directly, in addition to QTKit?
     
  8. thread starter macrumors member

    Joined:
    Aug 7, 2007
    Location:
    Staffordshire, UK
    #8
    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...
     
  9. thread starter macrumors member

    Joined:
    Aug 7, 2007
    Location:
    Staffordshire, UK
    #9
    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!
     

Share This Page