zoukankan      html  css  js  c++  java
  • iOS 画音频波形曲线 根据音频数据版

    DrawView.h 

    1. #import <UIKit/UIKit.h>  
    2.   
    3. @interface DrawView : UIView  
    4.   
    5. @property shortshort *drawBuffer;  
    6. @property int  dataLen;  
    7. @property floatfloat *outRel;  
    8. @property floatfloat *outImg;  
    9. @property int bias;  
    10. @property int wSize;  
    11. - (void)genKernel;  
    12.   
    13.   
    14. @end  


    DrawView.m 

    1. #import "DrawView.h"  
    2.   
    3. @implementation DrawView  
    4.   
    5. #define KSIZE 20  
    6. #define BIAS 10000  
    7.   
    8. static double fk[KSIZE] = {0};  
    9. static double _filterData[2048];  
    10.   
    11.   
    12.   
    13. - (void)genKernel  
    14. {  
    15.     double fc = .05;  
    16.     for (int i = 0; i < KSIZE; i++)  
    17.     {  
    18.         if ((i - KSIZE/2) == 0)fk[i] = 22 * M_PI *fc;  
    19.         if ((i - KSIZE/2) != 0 )fk[i] = sin(22 * M_PI * fc * (i - KSIZE/2))/(i - KSIZE/2);  
    20.         fk[i] = fk[i] * (0.54 - 0.46 * cos(22 * M_PI * i / KSIZE ));  
    21.           
    22.     }  
    23.       
    24.     double sum = 0;  
    25.     for (int m = 0; m < KSIZE; m++)  
    26.         sum+=fk[m];  
    27.       
    28.     for (int n = 0; n < KSIZE; n++)  
    29.         fk[n]/=sum;  
    30. }  
    31.   
    32. - (void)improveSpectrum  
    33. {  
    34.     memset(_filterData, 0x0, sizeof(double) * 1024);  
    35.     short transData[(int)self.wSize];  
    36.     memcpy(transData, self.drawBuffer+_bias, _wSize * sizeof(short));  
    37.     for (int i = 0; i < _wSize; i++)  
    38.     {  
    39.         for (int j = 0; j < KSIZE; j++)  
    40.         {  
    41.             _filterData[i] = _filterData[i] + transData[ i - j] * fk[j];  
    42.         }  
    43.     }  
    44.       
    45. }  
    46.   
    47.   
    48. - (id)initWithFrame:(CGRect)frame  
    49. {  
    50.     self = [super initWithFrame:frame];  
    51.     if (self) {  
    52.     }  
    53.     return self;  
    54. }  
    55.   
    56.   
    57.   
    58. - (void)drawRect:(CGRect)rect  
    59. {  
    60.     float delta = 320. / _wSize;  
    61.     [self improveSpectrum];  
    62.   
    63.     [[UIColor grayColor] set];  
    64.     UIRectFill ([self bounds]);  
    65.       
    66.       
    67.     CGContextRef currentContext = UIGraphicsGetCurrentContext();  
    68.     CGContextBeginPath(currentContext);  
    69.     CGContextMoveToPoint(currentContext, 0., 230.);  
    70.     CGContextAddLineToPoint(currentContext, 320., 230.);  
    71.     [[UIColor blueColor] setStroke];  
    72.     CGContextStrokePath(currentContext);  
    73.   
    74.       
    75.     CGContextBeginPath(currentContext);  
    76.     CGContextMoveToPoint(currentContext, 0., 230.);  
    77.     for (int i = 0; i < _wSize; i++)  
    78.     {  
    79.         CGFloat x = i * delta;  
    80.         CGFloat y = _filterData[i] / 150.0 + 230.0;  
    81.           
    82.           
    83.           
    84.           
    85.           
    86.         CGContextAddLineToPoint(currentContext, x, y);  
    87.           
    88.     }  
    89.     [[UIColor redColor] setStroke];  
    90.     CGContextStrokePath(currentContext);  
    91.   
    92. }  
    93.   
    94.   
    95. @end  


    ViewController.h 

    1. #import <UIKit/UIKit.h>  
    2.   
    3. @interface ViewController : UIViewController  
    4.   
    5. @end  



    ViewController.m

     

    1. #import "ViewController.h"  
    2. #import "DrawView.h"  
    3.   
    4.   
    5. struct WavInfo  
    6. {  
    7.     int   size;  
    8.     char  *data;  
    9.     short channels;  
    10.     short block_align;  
    11.     short bits_per_sample;  
    12.     unsigned long sample_rate;  
    13.     unsigned long format_length;  
    14.     unsigned long format_tag;  
    15.     unsigned long avg_bytes_sec;  
    16.       
    17. };  
    18.   
    19.   
    20. @interface ViewController ()  
    21.   
    22. @end  
    23.   
    24. void decodeWaveInfo(const charchar *fname, struct WavInfo *info)  
    25. {  
    26.       
    27.     FILEFILE *fp;  
    28.     fp = fopen(fname, "rb");  
    29.   
    30.     if(fp)  
    31.     {  
    32.         char id[5];  
    33.         unsigned long dataSize,size;  
    34.           
    35.         fread(id, sizeof(char), 4, fp);  
    36.         id[4]='';  
    37.         if (!strcmp(id, "RIFF"))  
    38.         {  
    39.             fread(&size, sizeof(unsigned long), 1, fp);//read file size  
    40.             fread(id, sizeof(char), 4, fp);//read wave  
    41.             id[4]='';  
    42.               
    43.             if (!strcmp(id, "WAVE"))  
    44.             {  
    45.                 fread(id, sizeof(char), 4, fp);  
    46.                 fread(&info->format_length, sizeof(unsigned long), 1, fp);  
    47.                 fread(&info->format_tag, sizeof(short), 1, fp);  
    48.                 fread(&info->channels, sizeof(short), 1, fp);  
    49.                 fread(&info->sample_rate, sizeof(unsigned long), 1, fp);  
    50.                 fread(&info->avg_bytes_sec, sizeof(unsigned long), 1, fp);  
    51.                 fread(&info->block_align, sizeof(short), 1, fp);  
    52.                 fread(&info->bits_per_sample, sizeof(short), 1, fp);  
    53.                 fread(id, sizeof(char), 4, fp);  
    54.                 fread(&dataSize, sizeof(unsigned long), 1, fp);  
    55.                 info->size = dataSize;  
    56.                 info->data = ( charchar *)malloc(sizeof(char)*dataSize);  
    57.                 fread(info->data, sizeof(char), dataSize, fp);  
    58.                   
    59.             }  
    60.             else  
    61.             {  
    62.                 printf("Error ");  
    63.             }  
    64.         }  
    65.         else  
    66.         {  
    67.             printf("Error ");  
    68.         }  
    69.         fclose(fp);  
    70.     }  
    71. }  
    72.   
    73. @implementation ViewController  
    74.   
    75. - (void)viewDidLoad  
    76. {  
    77.     [super viewDidLoad];  
    78.     NSString *path = [[NSBundle mainBundle] pathForResource:@"effect1" ofType:@"wav"];  
    79.     struct WavInfo wavInfo;  
    80.     decodeWaveInfo([path UTF8String], &wavInfo);  
    81.       
    82.       
    83.     DrawView *d = (DrawView *)self.view;  
    84.     d.drawBuffer = (shortshort *)malloc(sizeof(short) * wavInfo.size / 2 );  
    85.     [d genKernel];  
    86.     d.dataLen = wavInfo.size / 2;  
    87.     d.wSize = 256;  
    88.     d.bias = 0;  
    89.       
    90.     int n = 0;  
    91.     for (int m = 0; m < wavInfo.size / 2; m++)  
    92.     {  
    93.         d.drawBuffer[n++] = wavInfo.data[m * 2 + 1] << 8 | wavInfo.data[m * 2];  
    94.     }  
    95.       
    96.     UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragView:)];  
    97.     [self.view addGestureRecognizer:pan];  
    98.       
    99.     UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchView:)];  
    100.     [self.view addGestureRecognizer:pinch];  
    101.   
    102.       
    103. }  
    104.   
    105. #pragma mark -  
    106. #pragma mark Gesture Recognizer callback  
    107.   
    108. - (void)dragView:(UIPanGestureRecognizer *)recognizer  
    109. {  
    110.     DrawView *d = (DrawView *)self.view;  
    111.       
    112.     CGPoint p = [recognizer translationInView:self.view];  
    113.     NSLog(@"translate point is : %@",NSStringFromCGPoint(p));  
    114.     d.bias -= p.x;  
    115.       
    116.     [self.view setNeedsDisplay];  
    117. }  
    118.   
    119. - (void)pinchView:(UIPinchGestureRecognizer *)recognizer  
    120. {  
    121.     DrawView *d = (DrawView *)self.view;  
    122.       
    123.     if (recognizer.scale > 1.0)  
    124.     {  
    125.         if (d.wSize > 128)  
    126.         {  
    127.             d.wSize *= 0.95;  
    128.         }  
    129.     }  
    130.     else  
    131.     {  
    132.         if (d.wSize < 1024)  
    133.         {  
    134.             d.wSize *= 1.05;  
    135.         }  
    136.     }  
    137.       
    138.     [self.view setNeedsDisplay];  
    139. }  
    140.   
    141.   
    142. - (void)didReceiveMemoryWarning  
    143. {  
    144.     [super didReceiveMemoryWarning];  
    145.     // Dispose of any resources that can be recreated.  
    146. }  
    147.   
    148. @end  


    代码下载:http://pan.baidu.com/s/1ACWXT

    参考:

    在 iPhone 应用或者是游戏的开发过程中,对声音的支持是必不可少的。在我做过的几个应用中,每个都涉及到音效,所以在这里做个简单的归纳,很多都是引用自 《iPhone Application Programming Guide》(需要有 Apple ID 才能打开链接),加了一些实际使用的经验。
    iPhone OS 主要提供以下了几种播放音频的方法:
    System Sound Services
    AVAudioPlayer 类
    Audio Queue Services
    OpenAL

    1. System Sound Services
    System Sound Services 是最底层也是最简单的声音播放服务,调用 AudioServicesPlaySystemSound 这个方法就可以播放一些简单的音频文件,使用此方法只适合播放一些很小的提示或者警告音,因为它有很多限制:
    ■ 声音长度要小于 30 秒
    ■ In linear PCM 或者 IMA4 (IMA/ADPCM) 格式的
    ■ 打包成 .caf, .aif, 或者 .wav 的文件
    ■ 不能控制播放的进度
    ■ 调用方法后立即播放声音
    ■ 没有循环播放和立体声控制
    另外,它还可以调用系统的震动功能,方法也很简单。具体的代码可以参考官方的示例 SysSound
    , 但是官方的示例只有一些简单的用法,从文档中我们发现可以通过 AudioServicesAddSystemSoundCompletion 方法为音频播放添加 CallBack 函数,有了 CallBack 函数我们可以解决不少问题,比如可以克服 System Sound Services 本身不支持循环播放的问题。以下代码可以实现一个在程序中循环播放的背景音乐:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    static void completionCallback (SystemSoundID  mySSID) {
        // Play again after sound play completion
        AudioServicesPlaySystemSound(mySSID);
    }
     
    - (void) playSound {
        // Get the main bundle for the app
        CFBundleRef mainBundle;
        SystemSoundID soundFileObject;
        mainBundle = CFBundleGetMainBundle ();
         
        // Get the URL to the sound file to play
        CFURLRef soundFileURLRef  = CFBundleCopyResourceURL (
                                                             mainBundle,
                                                             CFSTR ("background"),
                                                             CFSTR ("wav"),
                                                             NULL
                                                             );
        // Create a system sound object representing the sound file
        AudioServicesCreateSystemSoundID (
                                          soundFileURLRef,
                                          &soundFileObject
                                          );
        // Add sound completion callback
        AudioServicesAddSystemSoundCompletion (soundFileObject, NULL, NULL,
                                               completionCallback,
                                               (void*) self);
        // Play the audio
        AudioServicesPlaySystemSound(soundFileObject);
         
    }

      2. AVAudioPlayer 类

    AVAudioPlayer 是 AVFoundation.framework 中定义的一个类,所以使用要先在工程中引入 AVFoundation.framework。我们可以把 AVAudioPlayer 看作是一个高级的播放器,它支持广泛的音频格式,主要是以下这些格式:
    ■ AAC
    ■ AMR(AdaptiveMulti-Rate, aformatforspeech)
    ■ ALAC(AppleLossless)
    ■ iLBC(internetLowBitrateCodec, anotherformatforspeech)
    ■ IMA4(IMA/ADPCM)
    ■ linearPCM(uncompressed)
    ■ μ-lawanda-law
    ■ MP3(MPEG-1audiolayer3 
    AVAudioPlayer 可以播放任意长度的音频文件、支持循环播放、可以同步播放多个音频文件、控制播放进度以及从音频文件的任意一点开始播放等,更高级的功能可以参考 AVAudioPlayer 的文档。要使用 AVAudioPlayer 的对象播放文件,你只需为其指定一个音频文件并设定一个实现了 AVAudioPlayerDelegate 协议的 delegate 对象。这里举一个简单的例子,和上一个例子一样,实现一直循环播放的背景音乐:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    - (void) playBackgroundSoundEffect {
        NSString *soundFilePath =
        [[NSBundle mainBundle] pathForResource: @"background"
                                        ofType: @"wav"];
        NSURL *fileURL = [[NSURL alloc] initFileURLWithPath: soundFilePath];
        AVAudioPlayer *newPlayer =
        [[AVAudioPlayer alloc] initWithContentsOfURL: fileURL
                                               error: nil];
        [fileURL release];
        self.player = newPlayer;
        [newPlayer release];
        [self.player prepareToPlay];
         
        [self.player setDelegate: self];
        self.player.numberOfLoops = -1;    // Loop playback until invoke stop method
        [self.player play];
    }

      可以看到,只要将 AVAudioPlayer 的 numberOfLoops 属性设为负数,音频文件就会一直循环播放直到调用 stop 方法。
    AVAudioPlayer 同样支持 Callback,这是 AVAudioPlayerDelegate 的一个可选 delegate 方法:
    - (void) audioPlayerDidFinishPlaying: (AVAudioPlayer *) player successfully: (BOOL) flag { 
        if (player == self.player && flag == YES) { 
            NSLog(@"Playback finish.");
        } 

    另外,你可以随时控制 AVAudioPlayer 对象的播放、暂停以及停止,通过判断对象的状态,分别调用 play、pause 和 stop 方法即可:
    - (IBAction) playOrPause: (id) sender { 
        // if playing, pause 
        if (self.player.playing) { 
            [self.player pause]; 
        // if stopped or paused, start playing 
        } else { 
            [self.player play]; 
        } 
    虽 然 AVAudioPlayer 可以播放很多格式,但是我们在实际开发过程中还是最好使用一些没有压缩的格式,比如 WAVE 文件,这样可以减少系统处理单元的资源占用,以便更好的完成程序的其他功能。另外,在使用 AVAudioPlayer 连续播放 mp3 这类经过压缩的音频文件时,在连接处可能出现一定的间隔时间。

    3. Audio Queue Services
    如果以上两种音频播放的解决方案都无法满足你的需求,那么我想你肯定需要使用 Audio Queue Services。使用 Audio Queue Services 对音频进行播放,你可以完全实现对声音的控制。例如,你可以在声音数据从文件读到内存缓冲区后对声音进行一定处理再进行播放,从而实现对音频的快速/慢速 播放的功能。
    因为 Audio Queue Services 相对复杂很多,Apple 官方已经把它整理为一本书了,具体可以参考 Audio Queue Services Programming Guide 和 SpeakHere 的程序示例。
    4. OpenAL
    OpenAL 是一套跨平台的开源的音频处理接口,与图形处理的 OpenGL 类似,它为音频播放提供了一套更加优化的方案。它最适合开发游戏的音效,用法也与其他平台下相同。
    iPhone 支持 OpenAL 1.1,我没有在实际开发中使用过,具体的文档可以参考 OpenAL 的网站 http://openal.org和 oalTouch 的程序示例。

  • 相关阅读:
    PHP 页面编码声明方法详解(header或meta)
    淘客部分功能实现源码
    CSS3动画效果应用
    JavaScript之Tab标签(原始版)
    JavaScript之淡入淡出
    关于响应式布局
    深入理解 SVG 系列(一) —— SVG 基础
    面试题
    随记
    一道经典面试题-----setTimeout(function(){},0)
  • 原文地址:https://www.cnblogs.com/Free-Thinker/p/5357425.html
Copyright © 2011-2022 走看看