1. 系统功能设计与分析
(1)噪声分贝检测功能模块
为了实现用户对周围声音进行分贝实时监测的功能,用户通过点击开
始按钮开始进行监测,和当前检测到的噪声的大小。用户上传的噪声信息会关联到分享模块中,获取用户的手机坐标位置是为了在地图上定位,以便绘制噪声地图,这样的得到的噪声地图,有时间、声音大小、更真实、形象,也更符合大众的生活化需求。在噪声检测页面,为了考虑用户的视觉多元化需求,设计了以波浪线的表达方式动态显示噪声的变化,同时为了直观精确,在旁边又加入了数字表达的方式,满足了多年龄层人群的不同需求,不仅有动画效果的趣味性,而且有数字显示保证准确性。主界面效果图如下所示。
(2)噪声频率监测模块:这个模块主要是为用户提供一些有关噪声频率信息,是用户能够更全面了解身边的声音信息。
2. 实现思路及核心代码
(1)噪声分贝模块
声音采集使用系统的AVFoundation框架,首先在工程引入该框架。该框架中的AVAudioSession单利类负责大部分音频的处理。其中噪声检测模块主要使用AVAudioRecorder创建一个录音机获取噪音输入。在使用前必须进行音频会话的初始化:
-(void)setAudioSession{
AVAudioSession *audioSession=[AVAudioSession sharedInstance];
//设置为播放和录音状态,以便可以在录制完之后播放录音
[audioSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil];
[audioSession setActive:YES error:nil];
}
进行录音文件的设置:
- (NSDictionary *)getAudioSetting {
NSMutableDictionary *dicM = [NSMutableDictionary dictionary];
// 设置录音格式为lpcm
[dicM setObject:@(kAudioFormatLinearPCM) forKey:AVFormatIDKey];
// 设置录音采样率,8000是电话采样率,对于一般录音已经够了
[dicM setObject:@(8000) forKey:AVSampleRateKey];
// 声道
[dicM setObject:@(2) forKey:AVNumberOfChannelsKey];
// 每个采样点位数
[dicM setObject:@(8) forKey:AVLinearPCMBitDepthKey];
// 是否使用浮点数采样
[dicM setObject:@(YES) forKey:AVLinearPCMIsFloatKey];
// 录音品质
[dicM setObject:@(AVAudioQualityHigh) forKey:AVSampleRateConverterAudioQualityKey];
return dicM;
}
因为要实时的检测当前环境的噪音分贝值,所以需要开启定时器:
-(NSTimer *)timer { \\使用延迟加载的方式
if (!_timer) {
_timer = [NSTimer scheduledTimerWithTimeInterval:0.1f target:self selector:@selector(audioPowerChange) userInfo:nil repeats:YES];
}
return _timer;
}
接下来进行声音分贝的计算,power 为均值,powerMax为峰值,注意每次计算之前要调用updateMeters进行更新测量值, 获取到分贝值后使用setGaugeValue 进行UI表盘的刻度显示。
-(void)audioPowerChange{
[self.audioRecorder updateMeters];//更新测量值
float power = [self.audioRecorder averagePowerForChannel:0];
float powerMax = [self.audioRecorder peakPowerForChannel:0];
NSLog(@"power = %f, powerMax = %f",power, powerMax);
CGFloat progress = (1.0 / 160.0) * (power + 160.0);
power = power + 160 - 50;
int dB = 0;
if (power < 0.f) {
dB = 0;
} else if (power < 40.f) {
dB = (int)(power * 0.875);
} else if (power < 100.f) {
dB = (int)(power - 15);
} else if (power < 110.f) {
dB = (int)(power * 2.5 - 165);
} else {
dB = 110;
}
NSLog(@"progress = %f, dB = %d", progress, dB);
self.test.retLabel.text = [NSString stringWithFormat:@"%d db", dB];
[self.test setGaugeValue:dB animation:YES];
}
(2)频率监测模块
该模块使用控制器HZViewController完成。该控制器含有四个成员。
其中EZAudioPlot继承自UIView,该类负责实时显示当前的频率图谱的绘制,EZMicrophone负责采集音频,EZAudioFFTRolling负责生意相关的傅立叶计算。因为EZAudioPlot相关类基于AVFoundation框架,所以在使用前必须设置AVAudioSession:
AVAudioSession *session = [AVAudioSession sharedInstance];
NSError *error;
[session setCategory:AVAudioSessionCategoryPlayAndRecord error:&error];
HZViewController控制器必须实现代理EZMicrophoneDelegate
#pragma mark - EZMicrophoneDelegate
//------------------------------------------------------------------------------
-(void) microphone:(EZMicrophone *)microphone
hasAudioReceived:(float **)buffer
withBufferSize:(UInt32)bufferSize
withNumberOfChannels:(UInt32)numberOfChannels
{
//
// Calculate the FFT, will trigger EZAudioFFTDelegate
//
[self.fft computeFFTWithBuffer:buffer[0] withBufferSize:bufferSize];
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf.audioPlotTime updateBuffer:buffer[0]
withBufferSize:bufferSize];
});
}
//------------------------------------------------------------------------------
#pragma mark - EZAudioFFTDelegate
//------------------------------------------------------------------------------
- (void) fft:(EZAudioFFT *)fft
updatedWithFFTData:(float *)fftData
bufferSize:(vDSP_Length)bufferSize
{
float maxFrequency = [fft maxFrequency];
NSString *noteName = [EZAudioUtilities noteNameStringForFrequency:maxFrequency
includeOctave:YES];
NSLog(@"---->%@", noteName);
__weak typeof (self) weakSelf = self;
dispatch_async(dispatch_get_main_queue(), ^{
// weakSelf.maxFrequencyLabel.text = [NSString stringWithFormat:@"Highest Note: %@,\nFrequency: %.2f", noteName, maxFrequency];
weakSelf.coorView.heighNoteLabel.text = noteName;
weakSelf.coorView.hzValueLabel.text = [NSString stringWithFormat:@"%.2f", maxFrequency];
[weakSelf.audioPlotFreq updateBuffer:fftData withBufferSize:(UInt32)bufferSize];
});
}
WHCoordinateView类继承自UIView,该类负责x,y坐标系的绘制。