一 : 定义一个全局变量AVAudioRecorder的录音对象,并启动录音
//设置属性的字典
recordSetting = [[NSMutableDictionary alloc] init];
//1.格式
[recordSetting setObject:[NSNumber numberWithInt:kAudioFormatLinearPCM] forKey:AVFormatIDKey];
//2.采样率
[recordSetting setObject:[NSNumber numberWithInt:1600] forKey:AVSampleRateKey];
//3.声道 要转换mp3格式声道就必须设置为2
[recordSetting setObject:[NSNumber numberWithInt:2] forKey:AVNumberOfChannelsKey];
//4.采样位数
[recordSetting setObject:[NSNumber numberWithInt:16] forKey:AVLinearPCMBitDepthKey];
非PCM格式 比如IMA4
[recordSetting setValue :[NSNumber numberWithInt:kAudioFormatAppleIMA4] forKey:AVFormatIDKey];
[recordSetting setValue:[NSNumber numberWithFloat:1600.0] forKey:AVSampleRateKey];
[recordSetting setValue:[NSNumber numberWithInt: 1] forKey:AVNumberOfChannelsKey];
2.设置路径及其url,并清除上一次缓存录音文件,录取新的文件
NSString *recprderPath = [NSHomeDirectory() stringByAppendingPathComponent:@"recorder.wav"];
//路劲另一个方法:[NSString stringWithFormat:@"%@/Documents/MySound.caf", NSHomeDirectory()]];
}
NSURL *url = [NSURL fileURLWithPath:recprderPath];
NSError *err = nil;
err = nil;
//从路径下检查是否有文件
NSData *audioData = [NSData dataWithContentsOfFile:[url path] options: 0 error:&err];
if(audioData)
{
//如果有使用文件管理移除上一次录音文件
NSFileManager *fm = [NSFileManager defaultManager];
[fm removeItemAtPath:[url path] error:&err];
}
err = nil;
//用字典定义的属性配置录音(初始化)
recorder = [[ AVAudioRecorder alloc] initWithURL:url settings:recordSetting error:&err];
//如果录音配置失败
if(!recorder){
//打印错误信息
NSLog(@"recorder: %@ %ld %@", [err domain], [err code], [[err userInfo] description]);
UIAlertView *alert =
[[UIAlertView alloc] initWithTitle: @"Warning"
message: [err localizedDescription]
delegate: nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
return;
}
[recorder setDelegate:self];//设置代理
[recorder prepareToRecord];//准备录音
recorder.meteringEnabled = YES;//开启音量检测
[recorder recordForDuration:(NSTimeInterval) 180.0];//录音有效时长
//设置定时器,每0.05秒调用updateMeters的方法画出音频曲线
timer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(updateMeters) userInfo:nil repeats:YES];
//这里的updateMeters是重写父类方法
1. 写父类方法 获得当前音频功率值,调用averagePowerForChannel之前你必须调用这个方法
- (void)updateMeters {
[recorder updateMeters];
//如果录音的分贝小于-60并且时间超过180秒提交录音
if (([recorder averagePowerForChannel:0] < -60.0) && (recordTime > 180.0)) {
[self commitRecording];
return;
}
recordTime += 0.05;//和定时器时间一样
[self addSoundMeterItem:[recorder averagePowerForChannel:0]];
}
2. Sound meter operations
//定义一个宏和soundMeters[i]数值要一样
#define SOUND_METER_COUNT 40
- (void)shiftSoundMeterLeft {
for(int i=0; i1; i++) {
soundMeters[i] = soundMeters[i+1];
}
}
- (void)addSoundMeterItem:(int)lastValue {
[self shiftSoundMeterLeft];
[self shiftSoundMeterLeft];
soundMeters[SOUND_METER_COUNT - 1] = lastValue;
soundMeters[SOUND_METER_COUNT - 2] = lastValue;
[self setNeedsDisplay];
}
3. 设置取消按钮,即图中的标注中,以及其方法
#define HUD_SIZE 220
#define CANCEL_BUTTON_HEIGHT 40
//麦克风位置
CGRect hudRect;
hudRect = CGRectMake(self.center.x - (HUD_SIZE / 2), self.center.y - (HUD_SIZE / 2) - 20, HUD_SIZE, HUD_SIZE);
int x = (frame.size.width - HUD_SIZE) / 2;
btnCancel = [[UIButton alloc] initWithFrame:CGRectMake(x, hudRect.origin.y + HUD_SIZE - CANCEL_BUTTON_HEIGHT, HUD_SIZE, CANCEL_BUTTON_HEIGHT)];
[btnCancel setTitle:NSLocalizedString(@"标注中", nil) forState:UIControlStateNormal];
[btnCancel addTarget:self action:@selector(cancelled:) forControlEvents:UIControlEventTouchUpInside];
btnCancel.enabled = NO;
[self addSubview:btnCancel];
//取消按钮点击事件
- (void)cancelled:(id)sender {
self.alpha = 0.0;
[self setNeedsDisplay];
[timer invalidate];
[self cancelRecording];
}
//取消事件
- (void)cancelRecording {
//配合代理使用事件
if ([self.delegate respondsToSelector:@selector(voiceRecordCancelledByUser:)]) {
[self.delegate voiceRecordCancelledByUser:self];
}
[recorder stop];
}
4. 画出录音曲线 以及
- (void)drawRect:(CGRect)rect {
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = UIGraphicsGetCurrentContext();//上下文
UIColor *strokeColor = [UIColor colorWithRed:0.886 green:0.0 blue:0.0 alpha:0.8];
UIColor *fillColor = [UIColor colorWithRed:0.5827 green:0.5827 blue:0.5827 alpha:1.0];
UIColor *gradientColor = [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.8];
UIColor *color = [UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:1.0];
NSArray *gradientColors = [NSArray arrayWithObjects:
(id)fillColor.CGColor,
(id)gradientColor.CGColor, nil];
CGFloat gradientLocations[] = {0, 1};
CGGradientRef gradient = CGGradientCreateWithColors(colorSpace, (__bridge CFArrayRef)gradientColors, gradientLocations);
UIBezierPath *border = [UIBezierPath bezierPathWithRoundedRect:hudRect cornerRadius:10.0];
CGContextSaveGState(context);
[border addClip];
CGContextDrawRadialGradient(context, gradient,
CGPointMake(hudRect.origin.x+HUD_SIZE/2, 120), 10,
CGPointMake(hudRect.origin.x+HUD_SIZE/2, 195), 215,
kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGContextRestoreGState(context);
[strokeColor setStroke];
border.lineWidth = 3.0;
[border stroke];
// 画出音频波浪
[[UIColor colorWithRed:1.0 green:1.0 blue:1.0 alpha:0.4] set];
CGContextSetLineWidth(context, 3.0);
CGContextSetLineJoin(context, kCGLineJoinRound);
int baseLine = 250;//不同的机型 定义不一样 距离screen上端距离可能是310mm
int multiplier = 1;
int maxLengthOfWave = 50;
int maxValueOfMeter = 70;
for(CGFloat x = SOUND_METER_COUNT - 1; x >= 0; x--)
{
multiplier = ((int)x % 2) == 0 ? 1 : -1;
CGFloat y = baseLine + ((maxValueOfMeter * (maxLengthOfWave - abs(soundMeters[(int)x]))) / maxLengthOfWave) * multiplier;
if(x == SOUND_METER_COUNT - 1) {
CGContextMoveToPoint(context, x * (HUD_SIZE / SOUND_METER_COUNT) + hudRect.origin.x + 10, y);
CGContextAddLineToPoint(context, x * (HUD_SIZE / SOUND_METER_COUNT) + hudRect.origin.x + 7, y);
}
else {
CGContextAddLineToPoint(context, x * (HUD_SIZE / SOUND_METER_COUNT) + hudRect.origin.x + 10, y);
CGContextAddLineToPoint(context, x * (HUD_SIZE / SOUND_METER_COUNT) + hudRect.origin.x + 7, y);
}
}
CGContextStrokePath(context);
// 画出标题 即图中大字标注中
[color setFill];
[self.title drawInRect:CGRectInset(hudRect, 0, 20) withFont:[UIFont systemFontOfSize:30.0] lineBreakMode:UILineBreakModeWordWrap alignment:UITextAlignmentCenter];//标题的位置文字大小 等等
[imgMicrophone drawAtPoint:CGPointMake(hudRect.origin.x + hudRect.size.width/2 - imgMicrophone.size.width/2, hudRect.origin.y + hudRect.size.height/2 - imgMicrophone.size.height/2)];
[[UIColor colorWithWhite:0.8 alpha:1.0] setFill];
UIBezierPath *line = [UIBezierPath bezierPath];
[line moveToPoint:CGPointMake(hudRect.origin.x, hudRect.origin.y + HUD_SIZE - CANCEL_BUTTON_HEIGHT)];
[line addLineToPoint:CGPointMake(hudRect.origin.x + HUD_SIZE, hudRect.origin.y + HUD_SIZE - CANCEL_BUTTON_HEIGHT)];
[line setLineWidth:3.0];
[line stroke];
}
三 : 录音完成之后 开始转码 mp3
//导入头文件lame.h和其静态库
- (BOOL)audio_PCMtoMP3
{
NSString *mp3FilePath = [NSHomeDirectory() stringByAppendingPathComponent:@"mp3FilePath.mp3"];
mp3Path = mp3FilePath;
NSFileManager * fileManager=[ NSFileManager defaultManager ];
if ([fileManager removeItemAtPath :mp3FilePath error : nil ])
{
NSLog ( @" 删除 " );
}
@try {
int read, write;
FILE *pcm = fopen ([recorderFilePath cStringUsingEncoding : 1 ], "rb" );
//source 被 转换的音频文件位置
if (pcm == NULL )
{
NSLog ( @"file not found" );
}
else
{
fseek (pcm, 4 * 1024 , SEEK_CUR );
//skip file header
FILE *mp3 = fopen ([mp3FilePath cStringUsingEncoding : 1 ], "wb" );
//output 输出生成的 Mp3 文件位置
const int PCM_SIZE = 8192 ;
const int MP3_SIZE = 8192 ;
short int pcm_buffer[PCM_SIZE* 2 ];
unsigned char mp3_buffer[MP3_SIZE];
lame_t lame = lame_init ();
lame_set_num_channels (lame, 1 ); // 设置 1 为单通道,默认为 2 双通道
lame_set_in_samplerate (lame, 1600.0 ); //11025.0取频 采样
//lame_set_VBR(lame, vbr_default);
lame_set_brate (lame, 8 );
lame_set_mode (lame, 3 );
lame_set_quality (lame, 2 ); /* 2=high 5 = medium 7=low 音 质 */
lame_init_params (lame);
do {
read = fread (pcm_buffer, 2 * sizeof ( short int ), PCM_SIZE, pcm);
if (read == 0 )
write = lame_encode_flush (lame, mp3_buffer, MP3_SIZE);
else
write = lame_encode_buffer_interleaved (lame, pcm_buffer, read, mp3_buffer, MP3_SIZE);
fwrite (mp3_buffer, write, 1 , mp3);
} while (read != 0 );
lame_close (lame);//释放lame
fclose (mp3);
fclose (pcm);
return YES ;
}
return NO ;
}
@catch (NSException *exception) {
NSLog ( @"%@" ,[exception description ]);
return NO ;
}
@finally {
NSLog ( @" 转码执行完成 " );
}
}