iOS录音wav caf 及mp3转码 音频的曲线

来源:互联网 发布:小米手机远程擦除数据 编辑:程序博客网 时间:2024/04/30 21:34

一 : 定义一个全局变量AVAudioRecorder的录音对象,并启动录音

  1. PCM格式设置如下:
//设置属性的字典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; i<SOUND_METER_COUNT - 1; 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 ( @" 转码执行完成 " );    }}
0 0
原创粉丝点击