More Spectrum Analyzer work
This commit is contained in:
parent
484285df84
commit
e805e4740c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue