用Matlab来放音乐,和用单片机加蜂鸣器放音乐的原理都差不多,就是把连续的声音信号事先转换成用数字信号,然后用扬声器按照一定的节奏放出来。换句话说,演唱者是把声音经过麦克风转换成电信号,录音设备对这个电信号按照一定的时间间隔(采样频率)进行采样,得到一长串数字。如果采样的频率高,即单位时间采样的点数多,同样长度的一首歌,得到的这串数字也越长。数字的大小表示电压的高低,也就是录制时声音的大小。这串数字就是原始的音频信号。

链接里给出的那段Matlab代码的功能,就是模拟产生那串代表音频信号的数字,把这串数字交给数字模拟转换器,生成对应的电压信号,再由扬声器把这个电信号(电能)转变成声音信号(机械能)。

我不懂音乐,就从信号的角度来解释吧。
%%----------------------------------------------------------------------
fs = 44100; % sample rate
dt = 1/fs; 
这一行定义了采样频率为44100赫兹,也就是说每秒钟需要播放44100个数字。为什么是44100Hz,或者44.1KHz,而不是其他更高或者更低的频率?因为我们的耳朵能够感受到的声音频率大约是20Hz ~ 20KHz(我最多只能听到17KHz左右),对于更高频率的声音我们的耳朵只能“呵呵”了。然后根据采样定理,“当采样频率大于信号中最高频率的2倍时,采样之后的数字信号可以完整地保留了原始信号中的信息”,所以理论上20KHz的信号至少用40KHz去采样。44.1KHz这个数字按照维基百科的说法是Sony公司在1979年先开始使用,然后被公司慢慢接受了。dt就是fs的倒数,即每两个数据点之间的时间间隔。

%%----------------------------------------------------------------------
T16 = 0.125; 
t16 = [0:dt:T16]; 
t4 = linspace(0,4*T16,4*k); 
t8 = linspace(0,2*T16,2*k); 
t16, t4, t8都是数组,他们的长度不一样。k表示t16数组的长度,是5513个点,也即44100的八分之一。i和j表示t4和t8数组的长度,分别是44100的二分之一和四分之一,这三个数组定义了每个音符播放的时间。以44100点为一秒钟,5513个点就表示持续八分之一秒的长度。

%%----------------------------------------------------------------------
mod4=(t4.^4).*exp(-30*(t4.^0.5)); 
mod4=mod4*(1/max(mod4)); 
mod8=(t8.^4).*exp(-50*(t8.^0.5)); 
mod8=mod8*(1/max(mod8)); 
mod16=(t16.^4).*exp(-90*(t16.^0.5)); 
mod16=mod16*(1/max(mod16)); 
f0 = 2*146.8; % reference frequency

ScaleTable = [2/3 3/4 5/6 15/16 ... 
1 9/8 5/4 4/3 3/2 5/3 9/5 15/8 ... 
2 9/4 5/2 8/3 3 10/3 15/4 4 ... 
1/2 9/16 5/8];

% 1/4 notes 
do0f = mod4.*cos(2*pi*ScaleTable(21)*f0*t4); 
这一步相当于是生成一个调幅的包络函数,我们可以单独把mod4画出来看一看。
最上面的图形就是mod4的函数图形,中间是cos(2*pi*ScaleTable(21)*f0*t4)的图形,下面是前两个的乘积,也就是do0f的图形。f0的频率是2*146.8 = 293.6Hz,查表是知道是D4,把他当做一个基准频率(我严重怀疑这个频率偏低了,听上去很不舒服,把f0改成880Hz就好听很多)。那么中间的图形是频率为ScaleTable(21)*f0 = 0.5*293.6 = 146.8Hz的正弦波。两个相乘得到了do0f的函数图形。do0f是1/4拍,它是一个22052个元素的数组,表示这个音符的频率是146.8Hz(this is weird!),播放0.5秒长度。
但是,这是一个频率单一的信号,且信号的幅度都一样,音符间的切换都很生硬。你可以动手试一试把每个音符前面相乘的mod4, mod8, mod16注释掉,然后再播放,你会发现真的很难听。如果大伯大妈每天晚上在广场上这个音乐跳舞,环保局的投诉电话肯定打爆了。所以,就用最上面的包络函数和正弦信号相乘,让每个音符柔和的飘过来,再缓缓的离开,这样的音乐就好听很多。
包络函数一般使用一个叫做ADSR的方法,就是把整个包络线分成四段,attack time, decay time, sustain level and relearse time. 每一段都根据需要有各自的函数和参数。

Synthesizer

%%----------------------------------------------------------------------
% 1/4 notes 
do0f = mod4.*cos(2*pi*ScaleTable(21)*f0*t4); 
re0f = mod4.*cos(2*pi*ScaleTable(22)*f0*t4); 
mi0f = mod4.*cos(2*pi*ScaleTable(23)*f0*t4);
......
...... 
接下去的就是给每个音符定义一个数组,主要的参数就是节拍和频率。懂音乐的同学可以帮忙解释一下频率之间的关系,像我这样的乐盲就只能直接查表。

%%----------------------------------------------------------------------
% Melody by Schau_mal 
part0 = [mi1f la0e la0e do1f mi1f ... 
re1e re1s mi1s re1e do1e re1e do1e la0f ... 
......
......
在接下去的一步是根据乐谱来生成一个大数组。对照着《最炫民族风》的乐谱,一一对应的写到数组里保存。这一步就相当于演唱者把他的声音录在了磁带里存放。下面的图是V1数组最开始的一段,就好比是磁带的一小段,或者说光盘的几圈。如果继续放大图像,看到的就是一个个点连成的折现,每44100个点需要一秒钟的时间播放。

%%----------------------------------------------------------------------
s = v1; 
s = s/max(s);

sound(s,fs); 
最后把数值归一化到[-1,1]区间。用Matlab自带的sound()函数播放。sound()函数需要两个参数,一个是音频信号的一个数组,另一个采样频率千万不要忘记。同一段信号用44100Hz播放是正常效果,用88200Hz就成了快进播放。

http://www.zhihu.com/question/20248007/answer/21230323

matlab演奏最炫民族风的代码注释的更多相关文章

  1. Matlab 代码注释

    Matlab 代码注释 一直在找类似doxygen一样将程序注释发表成手册的方法,现在发现,Matlab的publish功能自己就能做到. Publish 简介 并非所有注释都能作为文本进行输出,MA ...

  2. IT荐书|10个最“牛叉”的代码注释

    下面是 网友针对“你看到过的最好的代码注释是什么样的?”这个问题给出的回答的前10条: 1. // 亲爱的维护者: // 如果你尝试了对这段程序进行‘优化’, // 并认识到这种企图是大错特错,请增加 ...

  3. java代码注释规范

    java代码注释规范   代码注释是架起程序设计者与程序阅读者之间的通信桥梁,最大限度的提高团队开发合作效率.也是程序代码可维护性的重要环节之一.所以我们不是为写注释而写注释.下面说一下我们在诉求网二 ...

  4. PHPDocument 代码注释规范总结

    PHPDocument 代码注释规范 1. 安装phpDocumentor(不推荐命令行安装)在http://manual.phpdoc.org/下载最新版本的PhpDoc放在web服务器目录下使得通 ...

  5. [转]java代码注释规范

    代码注释是架起程序设计者与程序阅读者之间的通信桥梁,最大限度的提高团队开发合作效率.也是程序代码可维护性的重要环节之一.所以我们不是为写注释而写注释.下面说一下我们在诉求网二期开发中使用的代码注释规范 ...

  6. MATLAB Coder从MATLAB生成C/C++代码步骤

    MATLAB Coder可以从MATLAB代码生成独立的.可读性强.可移植的C/C++代码. 使用MATLAB Coder产生代码的3个步骤: 准备用于产生代码的MATLAB算法: 检查MATLAB代 ...

  7. vs2010代码注释自动生成api文档

    最近做了一些接口,提供其他人调用,要写个api文档,可是我想代码注释已经写了说明,能不能直接把代码注释生成api?于是找到以下方法 环境:vs2010 先下载安装Sandcastle 和Sandcas ...

  8. 【转】Objective-C代码注释和文档输出的工具和方法

    http://blog.xcodev.com/blog/2013/11/01/code-comment-and-doc-gen-tools-for-objc/ 代码注释可以让代码更容易接受和使用,特别 ...

  9. VVDocumenter - Xcod代码注释工具

    刚接触IOS开发时,发现XCODE非常的强大的,后续的代码实践中发现XOCDE的代码文档注释非常的差, 每次都要用手敲,蛋疼至极: 随着不断学习发现XCODE有代码片段内嵌一说(如:for .bloc ...

随机推荐

  1. 告别硬编码-发个获取未导出函数地址的Dll及源码

    还在为找内核未导出函数地址而苦恼嘛? 还在为硬编码通用性差而不爽吗? 还在为暴搜内核老蓝屏而痛苦吗? 请看这里: 最近老要用到内核未导出的函数及一些结构,不想再找特征码了,准备到网上找点符号文件解析的 ...

  2. move

    <span id="span{{$index}}" ng-click="goTab({{$index}})" ng-class="{tabFon ...

  3. mysql数据库 安装 (原创)

    1.首先下载mysql 数据库,我安装的是mysql5.1版本,直接安装就行,但是如果以后你想在数据库里显示中文的话,要把字符集设置为gb2312 2.配置数据源odbc.  mysql-connec ...

  4. POJ 1741 树的点分治

    题目大意: 树上找到有多少条路径的边权值和>=k 这里在树上进行点分治,需要找到重心保证自己的不会出现过于长的链来降低复杂度 #include <cstdio> #include & ...

  5. 解决 “fatal error C1083: ”无法打开包括文件

    添加该项目的附加路径 . 1)右键查看该项目的属性 2)点击配置属性——〉  C/C++  ——〉  常规  ——〉 附加包含目录——〉将缺失文件所在目录添加进去

  6. Linux Lab

    ssh vi /etc/apt/sources.list su ssh username@ipaddress eg : ssh root@172.16.247.143 实验一 fdisk /dev/s ...

  7. java基础-008

     57.面向对象软件开发的优点 代码开发模块化,更易于维护 代码复用 增强代码的可靠性和灵活性 增强代码的可理解性 面向对象编程有很多重要的特性,比如:封装,继承,多态和抽象  58.封装 封装给对象 ...

  8. 乌龟棋(noip2010)

    分析:该题是经典的动态规划题目. 题目中涉及到卡片数.卡片分4类.格子数等若干信息,又每张卡片仅能使用一次.求到达终点最多能能获得多少分. 从题目中可知卡片的使用顺序影响最终得分,我们可知状态转移和使 ...

  9. 走进科学之WAF(Web Appllication Firewall)篇

    小编P.S:文章非常详尽对WAF领域进行了一次科普,能有让人快速了解当前WAF领域的相关背景及现状,推荐所有WAF领域的同学阅读本文. 1. 前言 当WEB应用越来越为丰富的同时,WEB 服务器以其强 ...

  10. EasyUI 验证框使用方法

    使用过程中的一积累,备查. EasyUI 验证框使用方法://***************************missingMessage:未填写时显示的信息validType:验证类型见下示例 ...