iOS 上的波形

2024-01-07

我正在寻找如何绘制声音幅度。

I found http://supermegaultragroovy.com/2009/10/06/drawing-waveforms/ http://supermegaultragroovy.com/2009/10/06/drawing-waveforms/但我有一些问题。如何获取代表音频的浮点值列表?


谢谢大家。

我在这里找到了这个例子:使用 AVAssetReader 绘制波形 https://stackoverflow.com/questions/5032775/drawing-waveform-with-avassetreader,对其进行了更改并在此基础上开发了一个新类。

该类返回 UIImageView。

//.h file
#import <UIKit/UIKit.h>

@interface WaveformImageVew : UIImageView{

}
-(id)initWithUrl:(NSURL*)url;
- (NSData *) renderPNGAudioPictogramLogForAssett:(AVURLAsset *)songAsset;
@end


//.m file
#import "WaveformImageVew.h"

#define absX(x) (x<0?0-x:x)
#define minMaxX(x,mn,mx) (x<=mn?mn:(x>=mx?mx:x))
#define noiseFloor (-50.0)
#define decibel(amplitude) (20.0 * log10(absX(amplitude)/32767.0))
#define imgExt @"png"
#define imageToData(x) UIImagePNGRepresentation(x)

@implementation WaveformImageVew

-(id)initWithUrl:(NSURL*)url{
    if(self = [super init]){
        AVURLAsset * urlA = [AVURLAsset URLAssetWithURL:url options:nil];
        [self setImage:[UIImage imageWithData:[self renderPNGAudioPictogramLogForAssett:urlA]]];
    }
    return self;
}

-(UIImage *) audioImageLogGraph:(Float32 *) samples
                   normalizeMax:(Float32) normalizeMax
                    sampleCount:(NSInteger) sampleCount 
                   channelCount:(NSInteger) channelCount
                    imageHeight:(float) imageHeight {

    CGSize imageSize = CGSizeMake(sampleCount, imageHeight);
    UIGraphicsBeginImageContext(imageSize);
    CGContextRef context = UIGraphicsGetCurrentContext();

    CGContextSetFillColorWithColor(context, [UIColor blackColor].CGColor);
    CGContextSetAlpha(context,1.0);
    CGRect rect;
    rect.size = imageSize;
    rect.origin.x = 0;
    rect.origin.y = 0;

    CGColorRef leftcolor = [[UIColor whiteColor] CGColor];
    CGColorRef rightcolor = [[UIColor redColor] CGColor];

    CGContextFillRect(context, rect);

    CGContextSetLineWidth(context, 1.0);

    float halfGraphHeight = (imageHeight / 2) / (float) channelCount ;
    float centerLeft = halfGraphHeight;
    float centerRight = (halfGraphHeight*3) ; 
    float sampleAdjustmentFactor = (imageHeight/ (float) channelCount) / (normalizeMax - noiseFloor) / 2;

    for (NSInteger intSample = 0 ; intSample < sampleCount ; intSample ++ ) {
        Float32 left = *samples++;
        float pixels = (left - noiseFloor) * sampleAdjustmentFactor;
        CGContextMoveToPoint(context, intSample, centerLeft-pixels);
        CGContextAddLineToPoint(context, intSample, centerLeft+pixels);
        CGContextSetStrokeColorWithColor(context, leftcolor);
        CGContextStrokePath(context);

        if (channelCount==2) {
            Float32 right = *samples++;
            float pixels = (right - noiseFloor) * sampleAdjustmentFactor;
            CGContextMoveToPoint(context, intSample, centerRight - pixels);
            CGContextAddLineToPoint(context, intSample, centerRight + pixels);
            CGContextSetStrokeColorWithColor(context, rightcolor);
            CGContextStrokePath(context); 
        }
    }

    // Create new image
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();

    // Tidy up
    UIGraphicsEndImageContext();   

    return newImage;
}



- (NSData *) renderPNGAudioPictogramLogForAssett:(AVURLAsset *)songAsset {

    NSError * error = nil;    

    AVAssetReader * reader = [[AVAssetReader alloc] initWithAsset:songAsset error:&error];

    AVAssetTrack * songTrack = [songAsset.tracks objectAtIndex:0];

    NSDictionary* outputSettingsDict = [[NSDictionary alloc] initWithObjectsAndKeys:

                                        [NSNumber numberWithInt:kAudioFormatLinearPCM],AVFormatIDKey,
                                        //     [NSNumber numberWithInt:44100.0],AVSampleRateKey, /*Not Supported*/
                                        //     [NSNumber numberWithInt: 2],AVNumberOfChannelsKey,    /*Not Supported*/

                                        [NSNumber numberWithInt:16],AVLinearPCMBitDepthKey,
                                        [NSNumber numberWithBool:NO],AVLinearPCMIsBigEndianKey,
                                        [NSNumber numberWithBool:NO],AVLinearPCMIsFloatKey,
                                        [NSNumber numberWithBool:NO],AVLinearPCMIsNonInterleaved,

                                        nil];


    AVAssetReaderTrackOutput* output = [[AVAssetReaderTrackOutput alloc] initWithTrack:songTrack outputSettings:outputSettingsDict];

    [reader addOutput:output];
    [output release];

    UInt32 sampleRate,channelCount;

    NSArray* formatDesc = songTrack.formatDescriptions;
    for(unsigned int i = 0; i < [formatDesc count]; ++i) {
        CMAudioFormatDescriptionRef item = (CMAudioFormatDescriptionRef)[formatDesc objectAtIndex:i];
        const AudioStreamBasicDescription* fmtDesc = CMAudioFormatDescriptionGetStreamBasicDescription (item);
        if(fmtDesc ) {

            sampleRate = fmtDesc->mSampleRate;
            channelCount = fmtDesc->mChannelsPerFrame;

            //    NSLog(@"channels:%u, bytes/packet: %u, sampleRate %f",fmtDesc->mChannelsPerFrame, fmtDesc->mBytesPerPacket,fmtDesc->mSampleRate);
        }
    }

    UInt32 bytesPerSample = 2 * channelCount;
    Float32 normalizeMax = noiseFloor;
    NSLog(@"normalizeMax = %f",normalizeMax);
    NSMutableData * fullSongData = [[NSMutableData alloc] init];
    [reader startReading];    

    UInt64 totalBytes = 0; 

    Float64 totalLeft = 0;
    Float64 totalRight = 0;
    Float32 sampleTally = 0;

    NSInteger samplesPerPixel = sampleRate / 50;    

    while (reader.status == AVAssetReaderStatusReading){

        AVAssetReaderTrackOutput * trackOutput = (AVAssetReaderTrackOutput *)[reader.outputs objectAtIndex:0];
        CMSampleBufferRef sampleBufferRef = [trackOutput copyNextSampleBuffer];

        if (sampleBufferRef){
            CMBlockBufferRef blockBufferRef = CMSampleBufferGetDataBuffer(sampleBufferRef);

            size_t length = CMBlockBufferGetDataLength(blockBufferRef);
            totalBytes += length;


            NSAutoreleasePool *wader = [[NSAutoreleasePool alloc] init];

            NSMutableData * data = [NSMutableData dataWithLength:length];
            CMBlockBufferCopyDataBytes(blockBufferRef, 0, length, data.mutableBytes);


            SInt16 * samples = (SInt16 *) data.mutableBytes;
            int sampleCount = length / bytesPerSample;
            for (int i = 0; i < sampleCount ; i ++) {

                Float32 left = (Float32) *samples++;
                left = decibel(left);
                left = minMaxX(left,noiseFloor,0);

                totalLeft  += left;



                Float32 right;
                if (channelCount==2) {
                    right = (Float32) *samples++;
                    right = decibel(right);
                    right = minMaxX(right,noiseFloor,0);

                    totalRight += right;
                }

                sampleTally++;

                if (sampleTally > samplesPerPixel) {

                    left  = totalLeft / sampleTally; 
                    if (left > normalizeMax) {
                        normalizeMax = left;
                    }                    
                    // NSLog(@"left average = %f, normalizeMax = %f",left,normalizeMax);                    

                    [fullSongData appendBytes:&left length:sizeof(left)];

                    if (channelCount==2) {
                        right = totalRight / sampleTally; 


                        if (right > normalizeMax) {
                            normalizeMax = right;
                        }                        

                        [fullSongData appendBytes:&right length:sizeof(right)];
                    }

                    totalLeft   = 0;
                    totalRight  = 0;
                    sampleTally = 0;

                }
            }                        

            [wader drain];            

            CMSampleBufferInvalidate(sampleBufferRef);

            CFRelease(sampleBufferRef);
        }
    }    

    NSData * finalData = nil;

    if (reader.status == AVAssetReaderStatusFailed || reader.status == AVAssetReaderStatusUnknown){
        // Something went wrong. Handle it.
    }

    if (reader.status == AVAssetReaderStatusCompleted){
        // You're done. It worked.

        NSLog(@"rendering output graphics using normalizeMax %f",normalizeMax);

        UIImage *test = [self audioImageLogGraph:(Float32 *) fullSongData.bytes 
                                    normalizeMax:normalizeMax 
                                     sampleCount:fullSongData.length / (sizeof(Float32) * 2) 
                                    channelCount:2
                                     imageHeight:100];

        finalData = imageToData(test);
    }        

    [fullSongData release];
    [reader release];

    return finalData;
}

@end
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS 上的波形 的相关文章

随机推荐

  • 创建一个事件接收器来记录列表中用户所做的更改

    我正在开发一个 SharePoint 发布网站 我想在 SharePoint 列表中 记录 用户所做的所有更改 网上的一些搜索引导我找到了 EventReceiver 但我的 EventReceiver 必须是通用的并附加到网站集中的所有列
  • 模块构建失败:错误:TypeScript 编译中缺少 index.ts

    项目描述 我的项目是通过package json下载到node module 包 json dependencies myllc application core git ssh email protected cdn cgi l emai
  • 通过文本别名引用 Javascript 变量

    是否可以通过文本别名引用 JavaScript 变量 例如 var x 2 var y convertToVariableRef x 调用上述函数后 y将是相同的参考x而不仅仅是简单地复制值x into y 如果你声明一个没有任何函数作用域
  • Hakyll 网站的根源是什么?

    我看到创建函数需要一个标识符列表 ghci gt t create create Identifier gt Rules gt Rules 我应该使用什么标识符列表来匹配网站的根目录 例如 我只想制作一个出现在 www example co
  • GPS信号强度计算

    我想使用 NET CF 显示 GPS 设备的信号栏 我能够读取 NMEA 数据并获取 SNR 信号 但它们是许多卫星 有些处于活动状态 有些处于不活动状态 信噪比各不相同 我考虑过获取总 SNR 的平均值 但它不会给出准确的值 因为三颗强信
  • 编辑摊牌:在句子末尾保留换行符

    编辑非所见即所得 LaTeX HTML 等 散文时 您可能希望在句子末尾添加换行符 这有几个优点 更容易重新排列句子 更容易注释句子 更容易发现连续 过长的句子 评论更方便on句子 例如 The following isn t strict
  • 是否可以在 Selenium 中捕获 POST 数据?

    我正在与Selenium http seleniumhq comWebDriver 工具 我想知道该工具是否提供了一种捕获提交表单时生成的 POST 数据的方法 我正在使用 django 测试框架来测试我的数据是否在后端正确处理 我想使用
  • 这是什么 ANT 版本?

    我是 java Eclipse 的新手 我安装了 eclipse 并使用它作为 IDE 来处理 JAVA 1 4 文件 我更改了代码并保存了它并想要运行 cntr F11 或调试 F11 每次我得到 select what to run A
  • WTForms:FormField 的 FieldList 无法加载嵌套数据

    我在 FieldList 内的 FormField 内有一个自定义字段 地点 class LocationForm Form id HiddenField id title StringField l Title Required loca
  • 加载特定 MIME 类型的本机客户端 Chrome 扩展

    我为 Google Chrome Web 浏览器创建了一个本机客户端应用程序 用于播放特殊类型的音频文件 伟大的 此时该部分效果很好 我已准备好进入下一阶段 与世界分享这个应用程序 我需要这部分的帮助 根据我的理解 分发此应用程序的最佳方法
  • 如何预加载 angular2 视图,以便在首次加载时不会闪烁白页?

    我正在用纯 JS 构建一个 Angular 2 应用程序 我的问题是 当我从一个页面更改到另一个页面时 它会闪烁白色页面 直到呈现新视图 仅当我第一次访问所有组件时 才会发生这种情况 如果我第二次转到相同的路线 则页面加载时不会出现白页 我
  • 如何调整分面 tmap 图中的分面行标签高度?

    我正在使用带有行和列的 tmap 包绘制多面地图 我无法调整行的分面标签的高度 这会导致分面标签在大于特定大小或旋转时被裁剪 我已经尝试调整所有tm layout 小组的论据包括panel label height panel label
  • Ansible 循环相关问题

    我有一个剧本 其中有多个角色和串行设置 因此它首先在一台机器上运行 然后在其余机器上运行 在其中一个角色中 我有以下任务 name getting dbnodes IP addresses local action shell echo f
  • WPF 组合框样式

    下面是我的 ComboBox 样式代码 想法是在 ComboBox 周围放置边框并重用该样式
  • 我无法运行 hello.py 并获取 SyntaxError: invalid syntax

    我对 Python 和整个编程都很陌生 很抱歉问了一个看似重复的问题 但是 我无法使用以下格式运行我自己的代码 C Users Archangel gt python hello py 这是 hello py 包含的内容 Define a
  • 递归或循环[重复]

    这个问题在这里已经有答案了 我有这个方法可以计算一些统计数据 public void calculateAverage int hour if hour 20 int data 0 int times 0 for CallQueue cq
  • “+”(加号)CSS 选择器是什么意思?

    这个问题的答案是社区努力 help privileges edit community wiki 编辑现有答案以改进这篇文章 目前不接受新的答案或互动 例如 p p Some declarations 我不知道是什么 方法 这和仅仅定义样式
  • HTTPS 从根域(即 apex 或“naked”)重定向到“www”子域,而浏览器不会抛出异常?

    DNS A 记录要求将 IP 地址硬编码到应用程序的 DNS 配置中 哪个Heroku 建议避免 https devcenter heroku com articles apex domains Heroku 建议两种解决方法 使用在顶端支
  • 定期刷新 golang 中的通道

    我需要定期刷新频道的内容 我用 len 做到了这一点 我想知道是否有更好的方法来做到这一点 http play golang org p YzaI 2c F http play golang org p YzaI 2c F package
  • iOS 上的波形

    我正在寻找如何绘制声音幅度 I found http supermegaultragroovy com 2009 10 06 drawing waveforms http supermegaultragroovy com 2009 10 0