效果图

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 的程序示例。

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

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

    最近在做傅里叶变换和小波变换时经常要通过显示波形来检验算法,但通过visual studio之类显示波形又显得麻烦,而且不能跨平台. CImg是一个跨平台的C++的图像处理库,提供的图像处理等功能十分 ...

  2. egret 篇——关于ios环境下微信浏览器的音频自动播放问题

    前段时间公司突然想用egret(白鹭引擎)做一个金币游戏,大半个月边看文档边写吭哧吭哧也总算是弄完了.期间遇到一个问题,那就是ios环境下微信浏览器的音频自动播放问题. 个人感觉吧,egret自己封装 ...

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

    (转载)常用音频协议介绍 会议电视常用音频协议介绍及对比白皮书 一.数字化音频原理:声音其实是一种能量波,因此也有频率和振幅的特征,频率对应于时间轴线,振幅对应于电平轴线.通常人耳可以听到的频率在20 ...

  4. C# NAudio录音和播放音频文件-实时绘制音频波形图(从音频流数据获取,而非设备获取)

    NAudio的录音和播放录音都有对应的类,我在使用Wav格式进行录音和播放录音时使用的类时WaveIn和WaveOut,这两个类是对功能的回调和一些事件触发. 在WaveIn和WaveOut之外还有对 ...

  5. IOS Animation-贝塞尔曲线与Layer简单篇(一)

    IOS Animation-贝塞尔曲线与Layer简单篇 swift篇 1.介绍 贝塞尔曲线: 贝塞尔曲线是计算机图形图像造型的基本工具,是图形造型运用得最多的基本线条之一.它通过控制曲线上的四个点( ...

  6. ios怎样实现快速将显卡中数据读出压缩成视频在cocos2dx扩展开发中

    如果解决ios怎样实现快速将显卡中数据读出压缩成视频在cocos2dx扩展开发中 手机平台性能是个关键问题. 压缩视频分成3个步骤: 读取显卡数据, 使用编码器压缩,保存文件. 使用libav 压缩的 ...

  7. ggplot2在一幅图上画两条曲线

    ggplot2在一幅图上画两条曲线 print(data)后的结果是 C BROWN.P MI.P 0 0.9216 0.9282 30 0.9240 0.9282 100 0.9255 0.9282 ...

  8. HMS Core音频编辑服务3D音频技术,助力打造沉浸式听觉盛宴

    2022年6月28日,HDD·HMS Core.Sparkle影音娱乐沙龙在线上与开发者们见面.HMS Core音频编辑服务(Audio Editor Kit)专家为大家详细分享了基于分离的3D音乐创 ...

  9. 现有新的iOS更新可用,请从iOS12 beta版进行更新.解决方案

    问题描述: ios系统一直弹出“现有新的iOS更新可用,请从iOS12 beta版进行更新”的提示,很烦的. 应该只出现在安装测试版ios12的手机上. 解决方案: 删除描述文件无法解决. 有网友机制 ...

随机推荐

  1. 注意在insert插入数据库时的int类型问题

    比如,一个语句,insert into mbProduct(p_UserID,p_BigID,p_qq)values("+getUserid+",'"+getdrpdl+ ...

  2. An attempt to attach an auto-named database for file

    在用VS自带的 .mdf读取(joint)时,报错: Server Error in '/' Application. An attempt to attach an auto-named datab ...

  3. Linux文件和目录操作管理命令

    1.pwd:显示工作目录路径 -p:显示实际物理路径 -l:显示链接路径 2.cd:更改工作目录路径 cd:进入用户主目录 cd~:进入用户主目录 cd-:返回进入此目录之前所在的目录 cd..:返回 ...

  4. msi软件包无法安装

    安装某些msi软件包,提示“This advertised application will not be installed because it might be unsafe. Contact ...

  5. PHP Directory 函数

    PHP 5 Directory 函数 函数 描述 chdir() 改变当前的目录. chroot() 改变根目录. closedir() 关闭目录句柄. dir() 返回 Directory 类的实例 ...

  6. java Byte.toString 方法与String.ValueOf(Byte)效率比较

    int times = 10000000; Byte[] li = new Byte[times]; for (int i = 0; i < times; i++) { li[i] = (byt ...

  7. react-native-router-flux 下部导航

    github url:https://github.com/aksonov/react-native-router-flux API: https://github.com/aksonov/react ...

  8. 武汉科技大学ACM :1003: 零起点学算法78——牛牛

    Problem Description 牛牛是一种纸牌游戏,总共5张牌,规则如下: 如果找不到3张牌的点数之和是10的倍数,则为没牛: 如果其中3张牌的点数之和是10的倍数,则为有牛,剩下两张牌的点数 ...

  9. jquery获取浏览器高度、宽度和滚动条高度(来自网络)

    Jquery代码: alert($(window).height()); //浏览器时下窗口可视区域高度 alert($(document).height()); //浏览器时下窗口文档的高度 ale ...

  10. MySQL如何执行关联查询

    MySQL中‘关联(join)’ 一词包含的意义比一般意义上理解的要更广泛.总的来说,MySQL认为任何一个查询都是一次‘关联’ --并不仅仅是一个查询需要到两个表的匹配才叫关联,索引在MySQL中, ...