iOS 画音频波形曲线 根据音频数据版
效果图
DrawView.h
- #import <UIKit/UIKit.h>
- @interface DrawView : UIView
- @property shortshort *drawBuffer;
- @property int dataLen;
- @property floatfloat *outRel;
- @property floatfloat *outImg;
- @property int bias;
- @property int wSize;
- - (void)genKernel;
- @end
DrawView.m
- #import "DrawView.h"
- @implementation DrawView
- #define KSIZE 20
- #define BIAS 10000
- static double fk[KSIZE] = {0};
- static double _filterData[2048];
- - (void)genKernel
- {
- double fc = .05;
- for (int i = 0; i < KSIZE; i++)
- {
- if ((i - KSIZE/2) == 0)fk[i] = 22 * M_PI *fc;
- if ((i - KSIZE/2) != 0 )fk[i] = sin(22 * M_PI * fc * (i - KSIZE/2))/(i - KSIZE/2);
- fk[i] = fk[i] * (0.54 - 0.46 * cos(22 * M_PI * i / KSIZE ));
- }
- double sum = 0;
- for (int m = 0; m < KSIZE; m++)
- sum+=fk[m];
- for (int n = 0; n < KSIZE; n++)
- fk[n]/=sum;
- }
- - (void)improveSpectrum
- {
- memset(_filterData, 0x0, sizeof(double) * 1024);
- short transData[(int)self.wSize];
- memcpy(transData, self.drawBuffer+_bias, _wSize * sizeof(short));
- for (int i = 0; i < _wSize; i++)
- {
- for (int j = 0; j < KSIZE; j++)
- {
- _filterData[i] = _filterData[i] + transData[ i - j] * fk[j];
- }
- }
- }
- - (id)initWithFrame:(CGRect)frame
- {
- self = [super initWithFrame:frame];
- if (self) {
- }
- return self;
- }
- - (void)drawRect:(CGRect)rect
- {
- float delta = 320. / _wSize;
- [self improveSpectrum];
- [[UIColor grayColor] set];
- UIRectFill ([self bounds]);
- CGContextRef currentContext = UIGraphicsGetCurrentContext();
- CGContextBeginPath(currentContext);
- CGContextMoveToPoint(currentContext, 0., 230.);
- CGContextAddLineToPoint(currentContext, 320., 230.);
- [[UIColor blueColor] setStroke];
- CGContextStrokePath(currentContext);
- CGContextBeginPath(currentContext);
- CGContextMoveToPoint(currentContext, 0., 230.);
- for (int i = 0; i < _wSize; i++)
- {
- CGFloat x = i * delta;
- CGFloat y = _filterData[i] / 150.0 + 230.0;
- CGContextAddLineToPoint(currentContext, x, y);
- }
- [[UIColor redColor] setStroke];
- CGContextStrokePath(currentContext);
- }
- @end
ViewController.h
- #import <UIKit/UIKit.h>
- @interface ViewController : UIViewController
- @end
ViewController.m
- #import "ViewController.h"
- #import "DrawView.h"
- struct WavInfo
- {
- int size;
- char *data;
- short channels;
- short block_align;
- short bits_per_sample;
- unsigned long sample_rate;
- unsigned long format_length;
- unsigned long format_tag;
- unsigned long avg_bytes_sec;
- };
- @interface ViewController ()
- @end
- void decodeWaveInfo(const charchar *fname, struct WavInfo *info)
- {
- FILEFILE *fp;
- fp = fopen(fname, "rb");
- if(fp)
- {
- char id[5];
- unsigned long dataSize,size;
- fread(id, sizeof(char), 4, fp);
- id[4]='\0';
- if (!strcmp(id, "RIFF"))
- {
- fread(&size, sizeof(unsigned long), 1, fp);//read file size
- fread(id, sizeof(char), 4, fp);//read wave
- id[4]='\0';
- if (!strcmp(id, "WAVE"))
- {
- fread(id, sizeof(char), 4, fp);
- fread(&info->format_length, sizeof(unsigned long), 1, fp);
- fread(&info->format_tag, sizeof(short), 1, fp);
- fread(&info->channels, sizeof(short), 1, fp);
- fread(&info->sample_rate, sizeof(unsigned long), 1, fp);
- fread(&info->avg_bytes_sec, sizeof(unsigned long), 1, fp);
- fread(&info->block_align, sizeof(short), 1, fp);
- fread(&info->bits_per_sample, sizeof(short), 1, fp);
- fread(id, sizeof(char), 4, fp);
- fread(&dataSize, sizeof(unsigned long), 1, fp);
- info->size = dataSize;
- info->data = ( charchar *)malloc(sizeof(char)*dataSize);
- fread(info->data, sizeof(char), dataSize, fp);
- }
- else
- {
- printf("Error\n");
- }
- }
- else
- {
- printf("Error\n");
- }
- fclose(fp);
- }
- }
- @implementation ViewController
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- NSString *path = [[NSBundle mainBundle] pathForResource:@"effect1" ofType:@"wav"];
- struct WavInfo wavInfo;
- decodeWaveInfo([path UTF8String], &wavInfo);
- DrawView *d = (DrawView *)self.view;
- d.drawBuffer = (shortshort *)malloc(sizeof(short) * wavInfo.size / 2 );
- [d genKernel];
- d.dataLen = wavInfo.size / 2;
- d.wSize = 256;
- d.bias = 0;
- int n = 0;
- for (int m = 0; m < wavInfo.size / 2; m++)
- {
- d.drawBuffer[n++] = wavInfo.data[m * 2 + 1] << 8 | wavInfo.data[m * 2];
- }
- UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragView:)];
- [self.view addGestureRecognizer:pan];
- UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchView:)];
- [self.view addGestureRecognizer:pinch];
- }
- #pragma mark -
- #pragma mark Gesture Recognizer callback
- - (void)dragView:(UIPanGestureRecognizer *)recognizer
- {
- DrawView *d = (DrawView *)self.view;
- CGPoint p = [recognizer translationInView:self.view];
- NSLog(@"translate point is : %@",NSStringFromCGPoint(p));
- d.bias -= p.x;
- [self.view setNeedsDisplay];
- }
- - (void)pinchView:(UIPinchGestureRecognizer *)recognizer
- {
- DrawView *d = (DrawView *)self.view;
- if (recognizer.scale > 1.0)
- {
- if (d.wSize > 128)
- {
- d.wSize *= 0.95;
- }
- }
- else
- {
- if (d.wSize < 1024)
- {
- d.wSize *= 1.05;
- }
- }
- [self.view setNeedsDisplay];
- }
- - (void)didReceiveMemoryWarning
- {
- [super didReceiveMemoryWarning];
- // Dispose of any resources that can be recreated.
- }
- @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 画音频波形曲线 根据音频数据版的更多相关文章
- 调用CImg库显示WAV格式音频波形
最近在做傅里叶变换和小波变换时经常要通过显示波形来检验算法,但通过visual studio之类显示波形又显得麻烦,而且不能跨平台. CImg是一个跨平台的C++的图像处理库,提供的图像处理等功能十分 ...
- egret 篇——关于ios环境下微信浏览器的音频自动播放问题
前段时间公司突然想用egret(白鹭引擎)做一个金币游戏,大半个月边看文档边写吭哧吭哧也总算是弄完了.期间遇到一个问题,那就是ios环境下微信浏览器的音频自动播放问题. 个人感觉吧,egret自己封装 ...
- 常用音频协议介绍&&有关音频编码的知识与技术参数
(转载)常用音频协议介绍 会议电视常用音频协议介绍及对比白皮书 一.数字化音频原理:声音其实是一种能量波,因此也有频率和振幅的特征,频率对应于时间轴线,振幅对应于电平轴线.通常人耳可以听到的频率在20 ...
- C# NAudio录音和播放音频文件-实时绘制音频波形图(从音频流数据获取,而非设备获取)
NAudio的录音和播放录音都有对应的类,我在使用Wav格式进行录音和播放录音时使用的类时WaveIn和WaveOut,这两个类是对功能的回调和一些事件触发. 在WaveIn和WaveOut之外还有对 ...
- IOS Animation-贝塞尔曲线与Layer简单篇(一)
IOS Animation-贝塞尔曲线与Layer简单篇 swift篇 1.介绍 贝塞尔曲线: 贝塞尔曲线是计算机图形图像造型的基本工具,是图形造型运用得最多的基本线条之一.它通过控制曲线上的四个点( ...
- ios怎样实现快速将显卡中数据读出压缩成视频在cocos2dx扩展开发中
如果解决ios怎样实现快速将显卡中数据读出压缩成视频在cocos2dx扩展开发中 手机平台性能是个关键问题. 压缩视频分成3个步骤: 读取显卡数据, 使用编码器压缩,保存文件. 使用libav 压缩的 ...
- ggplot2在一幅图上画两条曲线
ggplot2在一幅图上画两条曲线 print(data)后的结果是 C BROWN.P MI.P 0 0.9216 0.9282 30 0.9240 0.9282 100 0.9255 0.9282 ...
- HMS Core音频编辑服务3D音频技术,助力打造沉浸式听觉盛宴
2022年6月28日,HDD·HMS Core.Sparkle影音娱乐沙龙在线上与开发者们见面.HMS Core音频编辑服务(Audio Editor Kit)专家为大家详细分享了基于分离的3D音乐创 ...
- 现有新的iOS更新可用,请从iOS12 beta版进行更新.解决方案
问题描述: ios系统一直弹出“现有新的iOS更新可用,请从iOS12 beta版进行更新”的提示,很烦的. 应该只出现在安装测试版ios12的手机上. 解决方案: 删除描述文件无法解决. 有网友机制 ...
随机推荐
- 破解Windows Server 2003只允许3个用户远程登陆
导读:WIN2003在使用远程桌面登录的时候,一台机器默认情况下只允许3个用户同时登录. 这很不方便.我们修改WIN2003远程桌面的连接数,可以设置3个以上用户远程桌面. 1.启动终端服务:在&qu ...
- SQL用row_number进行高速循环
SQL用row_number进行循环查询 declare @count int=0,@R int=0select row_number()over(order by RoomID) as R,* in ...
- java 对list中对象按属性排序
实体对象类 --略 排序类----实现Comparator接口,重写compare方法 package com.tang.list; import java.util.Comparator; publ ...
- SQL server概述
sqlserver中包含的对象: 数据库.事务日志.索引.文件组.数据库关系图.视图.存储过程.用户自定义函数.用户.角色.程序集.表.报表.全文目录.用户自定义数据类型 数据库实际上是最高层对象,其 ...
- js鼠标右键操作
一个页面中,BODY中用oncontextmenu='return false'来取消鼠标右键: 在JS中设置oncontextmenu='return true'用window.document. ...
- PHP如何防止SQL注入及开发安全 53
PHP如何防止SQL注入及开发安全 [php] function inject_check($sql_str) { $check=eregi('select|insert|update|de ...
- C++ AO读取shapefile的属性值
C++ AO读取一个shapefile文件的所有属性值 #include "stdafx.h" #include "iostream.h" #inc ...
- python中的列表和字典
列表和字典的区别: 列表是有序排列的一些物件,而字典是将一些物件(键)对应到另外一些物件(值)的数据结构; 应用场景: 字典 各种需要通过某个值去查看另一个值的场合,也就是一个虚拟的“查询表”,实现方 ...
- Speed-BI报表按钮链接设置
使用Speed-BI开发报表的时候,常常会需要增加一个链接按钮,点击按钮可跳转到其他报表或外部链接:那么我们可以通过新增‘仪表盘’--‘文本框’图表(如图1), <ignore_js_op> ...
- DDMS中File Explorer无法查看data/data文件解决办法
http://www.cnblogs.com/smyhvae/p/3881477.html 找了个连接 问题描述:最近在学习Android SQLite中的SQLiteOpenHelper,使用SQ ...