/*
File: MyController.m
Author: David Stolarsky
Change History (most recent first): <1> 05/26/06 began modifying Apple's sample code to drive SZG graphics with the Quicktime FFT
<2> 11/24/05 initial release
© Copyright 2006 David Stolarsky. All rights reserved.
*/
#import "MyController.h"
static UInt32 numberOfBandLevels = 8; // increase this number for more frequency bands
static UInt32 numberOfChannels = 1; // for StereoMix - If using DeviceMix, you need to get the channel count of the device.
static UInt8 FFTsPerSecond = 100;
static UInt8 LengthOfFFTHistory = 100;
UInt8 currentFFTIndex = 0;
extern cosmos_loop(QTAudioFrequencyLevels*);
@implementation MyController
- (void)awakeFromNib
{
UInt32 i;
mFreqResultsHist = malloc(sizeof(QTAudioFrequencyLevels*) * LengthOfFFTHistory);
for(i = 0; i < LengthOfFFTHistory; i++) {
// allocate memory for the QTAudioFrequencyLevels struct and set it up
// depending on the number of channels and frequency bands you want
mFreqResultsHist[i] = malloc(offsetof(QTAudioFrequencyLevels, level[numberOfBandLevels * numberOfChannels]));
mFreqResultsHist[i]->numChannels = numberOfChannels;
mFreqResultsHist[i]->numFrequencyBands = numberOfBandLevels;
}
blank_mFreq = malloc(offsetof(QTAudioFrequencyLevels, level[numberOfBandLevels * numberOfChannels]));
blank_mFreq->numChannels = numberOfChannels;
blank_mFreq->numFrequencyBands = numberOfBandLevels;
for(i = 0; i < numberOfBandLevels * numberOfChannels; i++) {
blank_mFreq->level[i] = 0.0;
}
// set up a timer and add it to the run loop
mTimer = [NSTimer timerWithTimeInterval:1.0/FFTsPerSecond target:self selector:@selector(myTimerFireMethod:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:mTimer forMode:(NSString *)kCFRunLoopCommonModes];
}
#pragma mark ---- panel callbacks ----
// movie opening panel
- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
{
if (NSOKButton == returnCode) {
NSString *theFilename = [[sheet filenames] objectAtIndex:0];
[sheet close];
[self openMovie:theFilename];
}
}
#pragma mark ---- timer ----
// timer method to display the frequency levels in the UI
- (void)myTimerFireMethod:(NSTimer*)theTimer
{
UInt8 i, j;
// get the levels from the movie
OSStatus err = GetMovieAudioFrequencyLevels([mMovie quickTimeMovie], kQTAudioMeter_MonoMix, mFreqResultsHist[currentFFTIndex]);
if (err) {
// something went wrong so send blank levels
[mWindow setTitle:[NSString stringWithFormat:@"%d on GetMovieAudioFrequencyLevels", err]];
cosmos_loop(blank_mFreq);
return;
}
cosmos_loop(mFreqResultsHist[i]);
}
#pragma mark ---- open movie/set up metering ----
// select a file to open
- (IBAction)doOpen:(id)sender
{
[[NSOpenPanel openPanel] beginSheetForDirectory:nil
file:nil
types:nil
modalForWindow:mWindow
modalDelegate:self
didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
contextInfo:nil];
}
// open the QTMovie and set it in the view replacing the movie that was there
- (void)openMovie:(NSString *)inFile
{
NSAlert *alert = nil;
NSError *error = nil;
if (mMovie != nil) {
[mMovieView pause:self];
[mMovieView setMovie:nil];
}
mMovie = [QTMovie movieWithFile:inFile error:&error];
if (nil == error) {
[mWindow setTitle:[mMovie attributeForKey:QTMovieDisplayNameAttribute]];
[mMovieView setMovie:mMovie];
[mMovieView setNeedsDisplay:TRUE];
if (TRUE == [[mMovie attributeForKey:QTMovieHasAudioAttribute] boolValue]) {
// do this once per movie to establish metering
OSStatus err = SetMovieAudioFrequencyMeteringNumBands([mMovie quickTimeMovie], kQTAudioMeter_MonoMix, &numberOfBandLevels);
if (err) {
// if something went wrong turn it off
[mWindow setTitle:[NSString stringWithFormat:@"Error %d", err]];
[self toggleFreqLevels:self];
} else {
}
} else {
alert = [NSAlert alertWithMessageText:@"No Sound Track!"
defaultButton:@"OK"
alternateButton:nil
otherButton:nil
informativeTextWithFormat:@"Open some media that contains audio if you're planing to see some frequency levels."];
[alert runModal];
}
} else {
alert = [NSAlert alertWithError:error];
[alert runModal];
}
}
#pragma mark ---- application delegates ----
// split when window is closed
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
@end