iOS 画音频波形曲线 根据音频数据版

效果图

DrawView.h

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

DrawView.m

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

ViewController.h

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

ViewController.m

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

时间: 2024-10-18 21:43:27

iOS 画音频波形曲线 根据音频数据版的相关文章

调用CImg库显示WAV格式音频波形

在做傅里叶变换和小波变换时经常要通过显示波形来检验算法,但通过visual studio之类显示波形又显得麻烦,而且不能跨平台. CImg是一个跨平台的C++的图像处理库,提供的图像处理等功能十分强大,而且加入项目中十分轻便,只需将头文件包含在项目中即可,十分轻便. 可自行到http://www.cimg.eu/下载 利用它来在linux.Mac OS X中显示波形,再合适不过了,下面是音频波形显示的代码. 主函数 main.cpp #include <iostream> #include &

阿里云移动端播放器高级功能---截图和音频波形

基本介绍如果用户对视频播放中的某一帧画面特别感兴趣,可以使用截图功能将这一帧视频保存起来.另外有一种场景想知道是否有声音,或者想感知声音的大小震动频率等,可以通过显示一个声音的波形来形象的表示.如下图所示:那么播放器提供了类似的方法可以让用户有办法去实现音频波形这个功能.那么这种通常在音乐播放器中比较常见,或者在直播场景中来标识对方讲话是否有声音等,有一定的应用场景. 视频截图实现接口iOS接口如下: /** 功能:截取当前正在播放图像 /-(UIImage) snapshot;Android接

基于matlab的音频波形实时采集显示 v0.1

robj = audiorecorder(44100,16,1); %设置采样频率.采样位数.通道数 recordblocking(robj,1); %采集初步数据(1s长度) rdata = getaudiodata(robj); %获取音频数据 plot(rdata); %绘制波形 axis([1,44100,-0.1,0.1]); %设置固定坐标轴 drawnow %刷新显示 n = 100; %设定后续的采样更新次数,n与m可联合计算后续更新时间长度 m = 0.1; %设定更新间隔,m

iOS开发:AVPlayer实现流音频边播边存

iOS开发:AVPlayer实现流音频边播边存 概述 1. AVPlayer简介 AVPlayer存在于AVFoundation中,可以播放视频和音频,可以理解为一个随身听 AVPlayer的关联类: AVAsset:一个抽象类,不能直接使用,代表一个要播放的资源.可以理解为一个磁带子类AVURLAsset是根据URL生成的包含媒体信息的资源对象.我们就是要通过这个类的代理实现音频的边播边下的 AVPlayerItem:可以理解为一个装在磁带盒子里的磁带 2. AVPlayer播放原理 给播放器

iOS音频技术的研究-音频格式

**什么是音频格式** 这个问题我也是查了很久才弄明白的.音频格式其实是指容器的类型,在通俗一点就是声音文件的类型,比如说"我爱你中国.mp3",这个声音文件的音频格式就是MP3. 这里稍微引入一些音频编码的东西.很多第一次涉及这个领域的(比如说我哈),很容易弄不清音频格式和音频编码的区别和联系,比如音频格式中有MP3格式,音频编码中有MP3编码,这时候多数人就不明白了. 音频编码本质是一种算法,我们拿到声音的原始数据之后,总不能直接就放到文件中用,我们需要根据不同的用途对于这些数据进

常用音频协议介绍&amp;&amp;有关音频编码的知识与技术参数

(转载)常用音频协议介绍 会议电视常用音频协议介绍及对比白皮书 一.数字化音频原理:声音其实是一种能量波,因此也有频率和振幅的特征,频率对应于时间轴线,振幅对应于电平轴线.通常人耳可以听到的频率在20Hz到20KHz的声波称为为可听声,低于20Hz的成为次声,高于20KHz的为超声,多媒体技术中只研究可听声部分. 可听声中,话音信号的频段在80Hz到3400Hz之间,音乐信号的频段在20Hz-20kHz之间,语音(话音)和音乐是多媒体技术重点处理的对象. 由于模拟声音在时间上是连续的,麦克风采集

C++从零实现深度神经网络之五——模型的保存和加载以及画出实时输出曲线

本文由@星沉阁冰不语出品,转载请注明作者和出处. 文章链接:http://blog.csdn.net/xingchenbingbuyu/article/details/53704085 微博:http://weibo.com/xingchenbing  一.模型的保存和加载 在我们完成对神经网络的训练之后,一般要把模型保存起来.不然每次使用模型之前都需要先训练模型,对于data hungry的神经网络来说,视数据多寡和精度要求高低,训练一次的时间从几分钟到数百个小时不等,这是任何人都耗不起的.把

深度分析:Android4.3下MMS发送到附件为音频文件(音频为系统内置音频)的彩信给自己,添加音频-发送彩信-接收彩信-下载音频附件-预览-播放(二,发送彩信&lt;1&gt;)

当准备工作(添加附件,输入文本内容)完成之后,我们这里开始进行该流程分析的第二阶段,也就是发送彩信.这里我们从ComposeMessageActivity类的点击发送按钮(mSendButtonMms)的点击事件开始:<TAG 1-1> @Override public void onClick(View v) { if (mShowTwoButtons && (v == mSendButtonSmsViewSec || v == mSendButtonMmsViewSec)

iOS平台基于KVC的JSON与数据对象绑定

iOS平台基于KVC的JSON与数据对象绑定 作者:chszs,未经博主允许不得转载.经许可的转载需注明作者和博客主页:http://blog.csdn.net/chszs 在iOS平台上,要操纵JSON数据并不困难,但是,我们还有更简单的解决方案,使用KVC,全称是Key-Value Coding. 假设开发者(你)开发了一款应用,它的数据来自于外部对Web服务,要从Web服务中取回一些JSON数据,数据如下: {"count": 3, "sum": 9.0, &