/* 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