存在意义

tinyplay常用于音频测试,一般是通过播放wav文件来测试开发板音频模块是否有问题,但是wav是没有经过压缩的文件,所以会占用较多内存,对于一些内存较小的开发板我们可以通过反复播放一段正弦波来测试音频模块

思路设计

简单的说就是通过C标准库提供的sin函数生成波形的采样点,然后将数据填充到buffer,再写一个循环反复写入PCM设备即可

重点难点

1. 想要实现这个功能必须对tinyplay的播放流程有大致的了解(用户层即可)

2. 理清楚采样频率a、采样点数b和正弦波频率c的关系:波形在一个周期内的b=a/c,也就是说我们可以通过控制a和b来播放特定频率的正弦波。这里补充一点,人耳能听到的声音频率为20Hz到20KHz,但是一般人能发出的声音频率就是几十到一千赫兹,所以声波频率设置成该频率听起来比较舒适

3. 正弦波的振幅一般调到最大便于测试,而最大值则是根据传入的样本长度参数确定(16、24、32)

4. 既然是反复写入同一段数据到PCM那么,填充buffer时注意前后边缘不能出现数据断层(最好就是一个周期:从零开始到0结束),不然播放时声音会不丝滑

源码

/* tinyplay.c
**
** Copyright 2011, The Android Open Source Project
**
** Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are met:
**     * Redistributions of source code must retain the above copyright
**       notice, this list of conditions and the following disclaimer.
**     * Redistributions in binary form must reproduce the above copyright
**       notice, this list of conditions and the following disclaimer in the
**       documentation and/or other materials provided with the distribution.
**     * Neither the name of The Android Open Source Project nor the names of
**       its contributors may be used to endorse or promote products derived
**       from this software without specific prior written permission.
**
** THIS SOFTWARE IS PROVIDED BY The Android Open Source Project ``AS IS'' AND
** ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
** IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
** ARE DISCLAIMED. IN NO EVENT SHALL The Android Open Source Project BE LIABLE
** FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
** DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
** CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
** LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
** OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
** DAMAGE.
*/#include <tinyalsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <endian.h>
#include <time.h>
#include <math.h>#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT  0x20746d66
#define ID_DATA 0x61746164struct riff_wave_header {uint32_t riff_id;uint32_t riff_sz;uint32_t wave_id;
};struct chunk_header {uint32_t id;uint32_t sz;
};struct chunk_fmt {uint16_t audio_format;uint16_t num_channels;uint32_t sample_rate;uint32_t byte_rate;uint16_t block_align;uint16_t bits_per_sample;
};static int close = 0;void display_progress(float len, float all_len);
void play_sample(unsigned int card, unsigned int device, unsigned int channels,unsigned int rate, unsigned int bits, unsigned int period_size,unsigned int period_count);void stream_close(int sig)
{/* allow the stream to be closed gracefully */signal(sig, SIG_IGN);close = 1;
}int main(int argc, char **argv)
{unsigned int device = 0;unsigned int card = 0;unsigned int period_size = 1000;unsigned int period_count = 4;unsigned int channels = 1;unsigned int rate = 44100;unsigned int bits = 16;if(argc < 2) {fprintf(stderr, "Usage: %s file.wav [-D card] [-d device] [-p period_size]"" [-n n_periods] [-b bits] [-v vol]\n", argv[0]);}/* parse command line arguments */argv += 2;while (*argv) {if (strcmp(*argv, "-d") == 0) {argv++;if (*argv)device = atoi(*argv);}if (strcmp(*argv, "-p") == 0) {argv++;if (*argv)period_size = atoi(*argv);}if (strcmp(*argv, "-n") == 0) {argv++;if (*argv)period_count = atoi(*argv);}if (strcmp(*argv, "-c") == 0) {argv++;if (*argv)channels = atoi(*argv);}if (strcmp(*argv, "-b") == 0) {argv++;if (*argv)bits = atoi(*argv);}if (strcmp(*argv, "-D") == 0) {argv++;if (*argv)card = atoi(*argv);}if (*argv)argv++; }play_sample(card, device, channels, rate, bits, period_size, period_count);return 0;
}int check_param(struct pcm_params *params, unsigned int param, unsigned int value,char *param_name, char *param_unit)
{unsigned int min;unsigned int max;int is_within_bounds = 1;min = pcm_params_get_min(params, param);if (value < min) {fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,param_unit, min, param_unit);is_within_bounds = 0;}max = pcm_params_get_max(params, param);if (value > max) {fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,param_unit, max, param_unit);is_within_bounds = 0;}return is_within_bounds;
}int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels,unsigned int rate, unsigned int bits, unsigned int period_size,unsigned int period_count)
{struct pcm_params *params;int can_play;params = pcm_params_get(card, device, PCM_OUT);if (params == NULL) {fprintf(stderr, "Unable to open PCM device %u.\n", device);return 0;}can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", " frames");can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", " periods");pcm_params_free(params);return can_play;
}void play_sample(unsigned int card, unsigned int device, unsigned int channels,unsigned int rate, unsigned int bits, unsigned int period_size,unsigned int period_count)
{struct pcm_config config;struct pcm *pcm;uint16_t *buffer;unsigned int size;unsigned int i;unsigned int points = 100;   /* 采样点数 */memset(&config, 0, sizeof(config));config.channels = channels;config.rate = rate;config.period_size = period_size;config.period_count = period_count;if (bits == 32)config.format = PCM_FORMAT_S32_LE;else if (bits == 24)config.format = PCM_FORMAT_S24_3LE;else if (bits == 16)config.format = PCM_FORMAT_S16_LE;config.start_threshold = 0;config.stop_threshold = 0;config.silence_threshold = 0;if (!sample_is_playable(card, device, channels, rate, bits, period_size, period_count)) {return;}pcm = pcm_open(card, device, PCM_OUT, &config);if (!pcm || !pcm_is_ready(pcm)) {fprintf(stderr, "Unable to open PCM device %u (%s)\n",device, pcm_get_error(pcm));return;}size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));buffer = malloc(size);if (!buffer) {fprintf(stderr, "Unable to allocate %d bytes\n", size);printf("3\n");free(buffer);pcm_close(pcm);return;}/* f = rate / points */for(i = 0; i < size / 2; i ++){buffer[i] = 32768 * sin(2 * 3.14159 / points * (i % points)) + 32768;}printf("Playing sample: %u ch, %u hz, %u bit\n", channels, rate, bits);/* catch ctrl-c to shutdown cleanly */signal(SIGINT, stream_close);do {pcm_write(pcm, buffer, size);} while (!close);printf("\n");free(buffer);pcm_close(pcm);
}

tinyplay扩展-播放自制正弦波相关推荐

  1. ExoPlayer+Shaka-packager播放自制DRM视频

    1. 工具说明 1.1 ExoPlayer ExoPlayer是google开源的应用级媒体播放器项目,构建在Android的底层多媒体API之上.该开源项目包含ExoPlayer库和演示demo. ...

  2. Android下音频tinyalsa(tinymix/tinycap/tinyplay/tinypcminfo)--------mark详细

    Android下音频tinyalsa(tinymix/tinycap/tinyplay/tinypcminfo) 2017年05月29日 10:02:03 songze_lee 阅读数:10224更多 ...

  3. Android下音频tinyalsa(tinymix/tinycap/tinyplay/tinypcminfo)

    转载于:http://blog.csdn.net/radianceblau/article/details/64125411 audio代码比较复杂,除了音频参数,我们平时客制化的地方不多.所以没有太 ...

  4. iOS开发系列--音频播放、录音、视频播放、拍照、视频录制(转)

    概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像 ...

  5. 牛人iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

    概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像 ...

  6. 玩转前端 Video 播放器

    Web 开发者们一直以来想在 Web 中使用音频和视频,但早些时候,传统的 Web 技术不能够在 Web 中嵌入音频和视频,所以一些像 Flash.Silverlight 的专利技术在处理这些内容上变 ...

  7. 【Web技术】662- 玩转前端 Video 播放器

    Web 开发者们一直以来想在 Web 中使用音频和视频,但早些时候,传统的 Web 技术不能够在 Web 中嵌入音频和视频,所以一些像 Flash.Silverlight 的专利技术在处理这些内容上变 ...

  8. iOS开发系列--音频播放、录音、视频播放、拍照、视频录制

    概览 随着移动互联网的发展,如今的手机早已不是打电话.发短信那么简单了,播放音乐.视频.录音.拍照等都是很常用的功能.在iOS中对于多媒体的支持是非常强大的,无论是音视频播放.录制,还是对麦克风.摄像 ...

  9. iOS音效和音乐播放

    在iOS中音频播放从形式上可以分为音效播放和音乐播放.前者主要指的是一些短音频播放,通常作为点缀音频,对于这类音频不需要进行进度.循环等控制.后者指的是一些较长的音频,通常是主音频,对于这些音频的播放 ...

最新文章

  1. python三步实现人脸识别
  2. js 外部文件加载处理
  3. python保存几位小数 format
  4. matlab 交叉验证 代码,交叉验证(Cross Validation)方法思想简介
  5. Android 编程下 px - dp 的相互转换
  6. PAT_B_1051_Java(15分)
  7. jaxb转xml空值双标签_单品运营思维:标签-词路-聚焦-直搜-超直
  8. Java EE CDI程序化依赖关系消歧示例–注入点检查
  9. mysql和oracle的通用存储,MySQL与Oracle在使用上的一些区别
  10. python virtualenv conda_在vscode中启动conda虚拟环境的思路详解
  11. tar 打包压缩与解压缩
  12. 内核仿阿里巴巴小说网站源码 PC端+WAP端
  13. Java实现批量图片生成PDF文件
  14. H5网页去除苹果手机底部白边
  15. 程序员 做头发 奇遇记
  16. Access denied for user ‘‘@‘localhost‘ (using password: YES)报错原因分享
  17. 别在让你的 await Streaking 了
  18. HtmlHelper、TagHelper、局部视图、视图组件
  19. 中国大学mooc微型计算机答案,微机系统-中国大学mooc-题库零氪
  20. edge打开pdf不显示印章_win10 Edge浏览器打不开pdf文件的解决方法

热门文章

  1. utils/rpm_resign.sh
  2. How to resign the Android APK
  3. 程序设计与算法(二)分蛋糕
  4. 日志文件转运工具Filebeat笔记|万字长文
  5. php des加密解密 16位,php DES加密解密的代码一例
  6. PS人像磨皮调色插件ultimate retouch中文汉化版
  7. 【阅读书籍】嵌入式软件方向(推荐阅读书籍)
  8. 电大c语言形考作业网上作业,C语言程序设计电大形考作业
  9. 京东版“拼多多”也要来了
  10. 开源笔记编辑器MarkText安装,设置GitHub图床