More Spectrum Analyzer work

This commit is contained in:
Thong Nguyen 2014-04-24 18:22:40 +01:00
parent 484285df84
commit e805e4740c
3 changed files with 99 additions and 1 deletions

View File

@ -40,6 +40,9 @@
///
@interface AudioPlayerView()
{
NSMutableArray* meters;
}
-(void) setupTimer;
-(void) updateControls;
@end
@ -55,6 +58,8 @@
{
self.audioPlayer = audioPlayerIn;
self.audioPlayer.spectrumAnalyzerEnabled = YES;
CGSize size = CGSizeMake(220, 50);
playFromHTTPButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
@ -114,9 +119,23 @@
statusLabel.textAlignment = NSTextAlignmentCenter;
meters = [[NSMutableArray alloc] init];
meter = [[UIView alloc] initWithFrame:CGRectMake(0, 450, 0, 20)];
meter.backgroundColor = [UIColor greenColor];
for (int i = 0; i < 256; i++)
{
UIView* freqMeter = [[UIView alloc] initWithFrame:CGRectMake(i, self.bounds.size.height, 1, 0)];
freqMeter.backgroundColor = [UIColor blueColor];
[self addSubview:freqMeter];
[meters addObject:freqMeter];
[self sendSubviewToBack:freqMeter];
}
[self addSubview:slider];
[self addSubview:playButton];
@ -193,9 +212,18 @@
statusLabel.text = audioPlayer.state == STKAudioPlayerStateBuffering ? @"buffering" : @"";
CGFloat newWidth = 320 * (([audioPlayer averagePowerInDecibelsForChannel:1] + 60) / 60);
CGFloat newWidth = 320 * (([audioPlayer testPowerWithIndex:100] + 96) / 96);
meter.frame = CGRectMake(0, 460, newWidth, 20);
for (int i = 0; i < 256; i++)
{
UIView* freqMeter = [meters objectAtIndex:i];
CGFloat height = 200 * (([audioPlayer testPowerWithIndex:i] + 96) / 96);
freqMeter.frame = CGRectMake(freqMeter.frame.origin.x, self.bounds.size.height - height, 1, height);
}
}
-(void) playFromHTTPButtonTouched

View File

@ -265,4 +265,6 @@ typedef void(^STKFrameFilter)(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UIn
/// Sets the gain value (from -96 low to +24 high) for an equalizer band (0 based index)
-(void) setGain:(float)gain forEqualizerBand:(int)bandIndex;
-(float) testPowerWithIndex:(int)index;
@end

View File

@ -255,9 +255,11 @@ static AudioStreamBasicDescription canonicalAudioStreamBasicDescription;
pthread_mutex_t mainThreadSyncCallMutex;
pthread_cond_t mainThreadSyncCallReadyCondition;
float* window;
float* obtainedReal;
float* originalReal;
int fftStride;
FFTSetup setupReal;
DSPSplitComplex fftInput;
@ -589,6 +591,7 @@ static void AudioFileStreamPacketsProc(void* clientData, UInt32 numberBytes, UIn
free(readBuffer);
free(originalReal);
free(obtainedReal);
free(window);
}
-(void) startSystemBackgroundTask
@ -2957,16 +2960,81 @@ static OSStatus OutputRenderCallback(void* inRefCon, AudioUnitRenderActionFlags*
obtainedReal = (float*)calloc(n, sizeof(float));
originalReal = (float*)calloc(n, sizeof(float));
window = (float*)calloc(maxSamples, sizeof(float));
vDSP_blkman_window(window, maxSamples, 0);
setupReal = vDSP_create_fftsetup(log2n, FFT_RADIX2);
}
[self appendFrameFilterWithName:@"STKSpectrumAnalyzerFilter" block:^(UInt32 channelsPerFrame, UInt32 bytesPerFrame, UInt32 frameCount, void* frames)
{
int log2n = log2f(frameCount);
int n = 1 << log2n;
int nOver2 = frameCount / 2;
SInt16* samples16 = (SInt16*)frames;
SInt32* samples32 = (SInt32*)frames;
if (bytesPerFrame / channelsPerFrame == 2)
{
for (int i = 0, j = 0; i < frameCount * channelsPerFrame; i+= channelsPerFrame, j += 2)
{
originalReal[j] = samples16[i] / 32768.0;
}
}
else if (bytesPerFrame / channelsPerFrame == 4)
{
for (int i = 0, j = 0; i < frameCount * channelsPerFrame; i+= channelsPerFrame, j+= 2)
{
originalReal[j] = samples32[i] / 32768.0;
}
}
vDSP_hann_window(window, n, 0);
vDSP_vmul(originalReal, 2, window, 1, originalReal, 2, n);
vDSP_ctoz((COMPLEX*)originalReal, 2, &fftInput, 1, nOver2);
vDSP_fft_zrip(setupReal, &fftInput, fftStride, log2n, FFT_FORWARD);
float one = 1;
float scale = (float)1.0 / (2 * n);
vDSP_vsmul(fftInput.realp, 1, &scale, fftInput.realp, 1, nOver2);
vDSP_vsmul(fftInput.imagp, 1, &scale, fftInput.imagp, 1, nOver2);
pthread_mutex_lock(&self->playerMutex);
vDSP_zvmags(&fftInput, 1, obtainedReal, 1, nOver2);
vDSP_vdbcon(obtainedReal, 1, &one, obtainedReal, 1, nOver2, 0);
float vmin = -96;
float vmax = 0;
vDSP_vclip(obtainedReal, 1, &vmin, &vmax, obtainedReal, 1, nOver2);
pthread_mutex_unlock(&self->playerMutex);
}];
}
}
-(float) testPowerWithIndex:(int)index
{
pthread_mutex_lock(&self->playerMutex);
if (!obtainedReal)
{
pthread_mutex_unlock(&self->playerMutex);
return 0;
}
float retval = obtainedReal[index];
pthread_mutex_unlock(&self->playerMutex);
return retval;
}
-(BOOL) meteringEnabled
{
return self->meteringEnabled;