音乐分析与合成 您所在的位置:网站首页 matlab音频信号处理流程图 音乐分析与合成

音乐分析与合成

2024-06-25 15:24| 来源: 网络整理| 查看: 265

(写在前边:《信号与系统》这门课的实验报告,同学们比较头疼,要么没有思路。属实折磨。到最后,大家都是东抄抄,西学学。我们小组的项目题目是“音乐分析与合成”。本着互相帮助的精神,同时也是让我们的实验报告发挥更大的价值,所以这里给我们的matlab代码(全部代码在最后)和报告;希望可以帮助你,同学。

请你给我们点个赞,或者评论说点什么,都是捧个场。感谢!!

《信号分析与处理》

课程大作业设计报告

组长

组员

报告日期:2XXX年MM月DD日

                 

报告撰写说明

1. 按照参考模板的内容和格式撰写报告

2. 理论部分须结合本课程知识分析问题

3. 程序设计部分应给出设计思路、主要流程图和关键函数的说明;结果分析不能只是简单给出结论,应结合具体问题,对关键参数或算法在不同取值条件下对结果的影响情况进行分析和总结。

4. 组内互评,相互评价彼此的贡献。

目 录

1 问题描述

2 理论部分

3 程序设计

3.1 编程思路

3.2 主要流程图及说明

3.3 结果分析

4 组内互评

5 总结与体会

参考文献

1 问题描述 当今时代,音乐越来越成为人们生活中不可缺少的娱乐活动。一些音乐播放、听歌识曲软件如雨后春笋般涌现。这些软件是如何来处理音频信号的呢?通过本学期《信号与分析》这门课程的学习,我们了解到:信号与系统的概念及分析方法广泛应用于通信、自动控制、电子信息等领域。MATLAB是国际上公认的优秀的科技应用软件,随着版本的不断升级,内容也在不断扩充。基于MATLAB的音乐分析与合成是较为常见、简单易操作的音乐处理方法。所以,我们决定用matlab对一段音乐进行分析、分解,并完成对乐音的指数包络的合成,演奏出自己合成的音乐。 2 理论部分

乐音的基本特征可以用基波频率、谐波频谱和包络波形三个方面描述。用C、D、E、F、G、A、B表示每个乐音的“音名”,当指定某一音名,它对应固定的基波信号频率。钢琴键盘上的部分琴键对应的乐音和基波频率如图1。在音乐中谐波起着音色变化的作用。当指定音调之后,仅指定了乐音信号的基波而未说明谐波情况,通常我们听到不同的乐器在某一音调下有明显不同感觉,这是由于谐波成分有所区别,频谱结构各异。不同类型的乐器,包络形状也不相同。在音乐合成的实验中,为了简化程序描述,我们通常把复杂的包络函数用少量的直线近似或者用指数衰减的形式表示。

音乐信号表示与分析:音乐信号通常可用时域、频域、时频域等多种方式表示,MATLAB中可以利用傅里叶变换等方法将时域信号转化为频域信号进行分析,可以对谱图、频谱密度、功率谱等参数进行计算和处理。

音乐合成:音乐合成是指通过各种数学算法模拟真实乐器发声原理,将数字信号转化为音频信号,在MATLAB中常见的方法有加性合成、减性合成、FM合成、物理模拟合成等。

音乐效果处理:音乐效果处理是指通过各种数字信号处理技术对音频信号进行改变,从而实现多种音乐效果,如回声、均衡器、压缩、失真等,MATLAB中可以使用数字滤波器实现这些效果。

音乐特征提取:音乐特征提取是指从音频信号中提取出一些数学参数,以描述音频的特征,如音高、节奏、旋律等,常见的方法包括傅里叶变换、小波变换、短时傅里叶变换、梅尔倒谱系数等。

傅里叶变换:

傅里叶变换是一种将时间域信号转换为频域信号的技术,可以将一个复杂的音频信号分解成不同频率的简单正弦波。因此,使用傅里叶变换可以绘制出每个乐音的时域波形和频谱图。

首先,在时域上,通过对音频信号进行采样和量化,我们可以获取到一组离散的采样值,这些采样值代表了声波在一段时间内的振幅。

然后,应用傅里叶变换算法将这些时域采样值转换为频域频率和振幅的表示。这样,就可以得到该音频信号在不同频率下的频谱信息,并且可以确定哪些频率分量对于该音乐乐器的音质和音色非常重要。

最后,将获得的频域信息再通过反向傅里叶变换转换回时域,即可得到原始音频信号的时域波形。同时,在频域图上,也可以表示出各频率成分的能量,以及它们之间的相对重要性。

3 程序设计

3.1 编程思路

使用matlab读入一小段音乐;

绘制真实音乐的时域波形;

根据时域波形截取出单个乐音信号; 

对每个乐音进行傅里叶变换,绘制每个乐音的频谱;

根据乐音的频率、幅值和持续时间信息进行指数包络的合成;

绘制合成音乐的频域波形(频域波形可视化效果更佳);

播放真实音乐和合成音乐,比较效果。

3.2 主要流程图及说明

A.流程图

图1.  主要流程图

具体思路和实现流程

1.加载歌曲。

%setting up song

clear; clc; clf; close all

mute=false;

[song,Fs]=audioread('Fur Elise_3.mp3');

%sound(song,Fs);    %play the song

Fs=Fs*4;

figure, plot(song(:,1)),title('Fur Elise')

%set parameters

length(song)

t1=10; t2=565104;%start & end length

%analyse a window of the song

y=song(t1:t2);

n=length(y);

t=linspace(t1,t2,n);

audiowrite('Fur Elise.wav',y,Fs)%output .wav file

代码说明:

首先,通过audioread函数读取名为"Fur Elise_3.mp3"的音乐文件,并将音频数据存储在变量song中,采样率存储在变量Fs中。将采样率Fs乘以4,将其值赋给变量Fs,相当于将音乐的播放速率加快了4倍。

t1和t2为位置参数,起始位置t1设为10,结束位置t2设为565104。(记得根据自己的歌曲改动!!)

song中提取了位于t1到t2之间的部分音频数据,并将其存储在变量y中。变量n表示音频数据的长度。

生成等间距的时间向量t,用于在后续的分析中使用。

最后将提取的音频数据y以采样率Fs保存为"Fur Elise.wav"的.wav文件。

2.使用平均滤波器将其采样20次,去掉一些音频的高频内容,减少matlab运算量,提高程序分析速度。

%downsampled by m

clc;

m=20;

Fsm=round(Fs/m);

p=floor(n/m);

y_avg=zeros(1,p);

for i=1:p

    y_avg(i)=mean(y(m*(i-1)+1:m*i));

end

 figure, subplot(2,1,1), plot(linspace(0,100,n),abs(y))

         title('Discrete notes of song')

         legend('Original')

         subplot(2,1,2), plot(linspace(0,100,p),abs(y_avg))

         legend('20-point averaged and down-sampled')

代码说明:

将变量Fs除以下采样倍数m并四舍五入,得到下采样后的采样率Fsm。

计算下采样后的音频数据的长度p,即原始音频数据长度n除以下采样倍数m并向下取整。

然后创建了一个长度为p的全零向量y_avg,用于存储下采样后的音频数据。

接下来,通过一个for循环,代码对原始音频数据y进行平均滤波处理。循环变量i从1到p遍历,每次取出长度为m的音频数据段,然后计算这个段数据的平均值,并将结果存储在y_avg(i)中。

最后绘制了两个图。第一个图显示了原始音频数据的离散点图。第二个显示了经过20点平均滤波和下采样处理后的音频数据的离散点图。

3.使用移动平均阈值对音频进行阈值,来检测音符的峰值。%threshold to find notes

y_thresh=zeros(1,p);

i=1;

while(ithresh)

        for j=0:500

            if(i+j20)

                i_note=i_note+1;

                fundamentals(i_note)=f(index)*2;

                figure, plot(f,abs(Note(1:length(f))))  %plotting fft of each note

                title(['Fundamental frequency = ',num2str(fundamentals(i_note)),'Hz'])

            end

            i=i+50;

        end

        clear note;

        break

    end

    end

    i=i+1;

end

代码说明:

清除命令窗口然后显示 "find frequencies of each note"以在命令行提示程序进度。

初始化外部循环变量i为1,内部循环变量j为1,以及i_note为0。

通过一个外部的while循环,代码遍历音频数据的每个采样点,直到i的值小于p。再进入一个内部的while循环,提取每个音符的阈值化后的音频数据。

内部循环中,代码将当前采样点的阈值化后的音频数据存储在note数组中,并将i和j分别增加1。

如果当前采样点的阈值化后的音频数据不为零,则将end_note设为20,表示检测到一个新的音符。否则,end_note减少1,用于判断音符是否结束。

当end_note减少到0时,表示检测到一个完整的音符。此时,代码检查音符的长度j是否大于25(用于滤除较短的噪音),如果是,则在音符末尾填充零以进行补齐,然后对音符进行快速傅里叶变换(FFT)得到频域表示。

计算FFT结果的长度Ns,生成一个等间距的频率向量f,然后找到频域表示中幅度最大的频率分量的索引index。如果该频率大于20Hz,则将其存储在fundamentals数组中,并绘制频域表示的图形。

将外部循环变量i增加50,跳过已经处理过的一段音频数据。

最后,清除note数组,继续外部循环的下一次迭代。

5.检查所有音符并且播放,为重新创建的音乐生成一个.wav音频。

%play back notes

%(and, of course, closing all windows)

%close all

amp=1;

fs=20500;

duration= .49;

rec_song=zeros(1,duration*fs*length(fundamentals));

for i=1:length(fundamentals)

    [letter(i,1),freq(i)]=FreqToNote(fundamentals(i));

    values=0:1/fs:duration;

    a=amp*sin(2*pi*freq(i)*values*2);

    rec_song((i-1)*fs*duration+1:i*fs*duration+1)=a;

    sound(a,fs)

    pause(.5)

end

letter

audiowrite('Recreated_Music1.wav',rec_song,fs);

代码说明:

设置几个参数:

变量amp表示音符的振幅,fs表示采样率,duration表示每个音符的持续时间。全零向量rec_song,用于存储重新创建的音乐。

遍历fundamentals数组中存储的每个频率:

For循环中,调用FreqToNote将频率转换为对应的音符名称,并将结果存储在letter数组中,同时将频率存储在freq数组中。

时间向量values,从0到持续时间duration,以采样率fs进行间隔采样。

然后,代码根据频率、振幅和时间向量生成音符的波形数据a,采用正弦函数的形式。

接下来把生成的音符数据a存储在rec_song中的对应位置,以便生成完整的重新创建的音乐。通过sound函数播放当前音符的波形数据a,并通过pause函数暂停0.5秒。

在循环结束后,代码输出存储音符名称的letter数组。

将重新创建的rec_song以采样率fs保存为"Recreated_Music1.wav"。

6.显示合成音乐频域波形图,展示频率分布。

% plot frequency domain waveform of synthesized music

[y, fs] = audioread('Recreated_Music1.wav');

duration = length(y) / fs;

n = length(y);

f = linspace(0, fs/2, n/2+1);

Y = fft(y);

Y = abs(Y(1:n/2+1));

figure;

plot(f, Y);

xlabel('Frequency (Hz)');

ylabel('Magnitude');

title('Frequency Domain Waveform of Synthesized Music');

xlim([0, fs/2]); % set x-axis limits to positive frequencies

7.FreqToNote函数,将给定的频率映射到已知的钢琴的音符和频率列表上。

%FreqToNote, freq functions (freq based on pianos)

function [note,frequency]=FreqToNote(f)

index=round(17.31232*log(f)-47.37620);

frequencies = [16.35 17.32 18.35 19.45 20.6 21.83 23.12 24.5 25.96 27.5 29.14 30.87 32.7 34.65 36.71 38.89 41.2 43.65 46.25 49 51.91 55 58.27 61.74 65.41 69.3 73.42 77.78 82.41 87.31 92.5 98 103.83 110 116.54 123.47 130.81 138.59 146.83 155.56 164.81 174.61 185 196 207.65 220 233.08 246.94 261.63 277.18 293.66 311.13 329.63 349.23 369.99 392 415.3 440 466.16 493.88 523.25 554.37 587.33 622.25 659.25 698.46 739.99 783.99 830.61 880 932.33 987.77 1046.5 1108.73 1174.66 1244.51 1318.51 1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32 2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07 4186.01 4434.92 4698.63 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88 7040 7458.62 7902.13];

Notes = ["C0" "Db0" "D0" "Eb0" "E0" "F0" "Gb0" "G0" "Ab0" "A0" "Bb0" "B0" "C1" "Db1" "D1" "Eb1" "E1" "F1" "Gb1" "G1" "Ab1" "A1" "Bb1" "B1" "C2" "Db2" "D2" "Eb2" "E2" "F2" "Gb2" "G2" "Ab2" "A2" "Bb2" "B2" "C3" "Db3" "D3" "Eb3" "E3" "F3" "Gb3" "G3" "Ab3" "A3" "Bb3" "B3" "C4" "Db4" "D4" "Eb4" "E4" "F4" "Gb4" "G4" "Ab4" "A4" "Bb4" "B4" "C5" "Db5" "D5" "Eb5" "E5" "F5" "Gb5" "G5" "Ab5" "A5" "Bb5" "B5" "C6" "Db6" "D6" "Eb6" "E6" "F6" "Gb6" "G6" "Ab6" "A6" "Bb6" "B6" "C7" "Db7" "D7" "Eb7" "E7" "F7" "Gb7" "G7" "Ab7" "A7" "Bb7" "B7" "C8"];

note=Notes(index);

frequency=frequencies(index);

End

代码说明:

函数的输入参数是频率f,表示要映射的频率值。通过将频率值转换为一个索引值index,映射到索引值。

已知的音符和频率列表包括多个音符和对应的频率。音符存储在字符串数组Notes中,频率存储在数值数组frequencies中,这两个数组的音符和频率一一对应。然后返回对应的音符频率作为输出。

3.3 结果分析(图片用你们自己跑出来)

3.3.1程序对“Fur Elise.mp3”(钢琴曲《致爱丽丝》节选)的运行结果

波形和图窗a.真实音乐的时域波形:b.经过20点平均滤波和采样后的时域波形对比图:c.滤波之后的原曲波形和识别到的“音符”的对应波形对比图:d.本程序在这示例中,共识别到17个音符。将每一个音符的频率以傅里叶变换的频域图象表示(一共17幅图,这里以识别到的前3个音符为例):e.显示最终合成音乐的频域波形:输出根据识别到的乐音,进行合成的.wav音乐:(默认生成到程序同目录下)

示例:

结果验证

用音乐软件打开生成的音乐和原曲,比较效果。

4 组内互评

(略)

5 总结与体会

对音频信号进行时域处理、频域分析使我们更深入地了解到matlab以及傅里叶变换的奇妙之处。可以更加深入地理解音乐背后的原理。虽然在一些信号处理的方法上还是略显简略,但是小组成员尽力做到了最优,总体效果也还是不错的,在调试中也了解了许多MATLAB的知识,可谓收获颇多。

参考文献

[1] 康华光.数字电子技术基础(第五版)[M].北京:高等教育出版社,2006

[2] 付家才.电子实验与实践[M].北京:高等教育出版社,2004

附录  MATLAB程序主要代码

%setting up song

clear; clc; clf; close all

mute=false;

[song,Fs]=audioread('Fur Elise_3.mp3');

%sound(song,Fs);    %play the song

Fs=Fs*4;

figure, plot(song(:,1)),title('Fur Elise')

%set parameters

length(song)

t1=10; t2=565104;%start & end length

%analyse a window of the song

y=song(t1:t2);

n=length(y);

t=linspace(t1,t2,n);

audiowrite('Fur Elise.wav',y,Fs)%output .wav file

%downsampled by m

clc;

m=20;

Fsm=round(Fs/m);

p=floor(n/m);

y_avg=zeros(1,p);

for i=1:p

    y_avg(i)=mean(y(m*(i-1)+1:m*i));

end

 figure, subplot(2,1,1), plot(linspace(0,100,n),abs(y))

         title('Discrete notes of song')

         legend('Original')

         subplot(2,1,2), plot(linspace(0,100,p),abs(y_avg))

         legend('20-point averaged and down-sampled')

%threshold to find notes

y_thresh=zeros(1,p);

i=1;

while(ithresh)

        for j=0:500

            if(i+j20)

                i_note=i_note+1;

                fundamentals(i_note)=f(index)*2;

                figure, plot(f,abs(Note(1:length(f))))  %plotting fft of each note

                title(['Fundamental frequency = ',num2str(fundamentals(i_note)),'Hz'])

            end

            i=i+50;

        end

        clear note;

        break

    end

    end

    i=i+1;

end

%play back notes

%(and, of course, closing all windows)

%close all

amp=1;

fs=20500;

duration= .49;

rec_song=zeros(1,duration*fs*length(fundamentals));

for i=1:length(fundamentals)

    [letter(i,1),freq(i)]=FreqToNote(fundamentals(i));

    values=0:1/fs:duration;

    a=amp*sin(2*pi*freq(i)*values*2);

    rec_song((i-1)*fs*duration+1:i*fs*duration+1)=a;

    sound(a,fs)

    pause(.5)

end

letter

audiowrite('Recreated_Music1.wav',rec_song,fs);

% plot frequency domain waveform of synthesized music

[y, fs] = audioread('Recreated_Music1.wav');

duration = length(y) / fs;

n = length(y);

f = linspace(0, fs/2, n/2+1);

Y = fft(y);

Y = abs(Y(1:n/2+1));

figure;

plot(f, Y);

xlabel('Frequency (Hz)');

ylabel('Magnitude');

title('Frequency Domain Waveform of Synthesized Music');

xlim([0, fs/2]); % set x-axis limits to positive frequencies

%FreqToNote, freq functions (freq based on pianos)

function [note,frequency]=FreqToNote(f)

index=round(17.31232*log(f)-47.37620);

frequencies = [16.35 17.32 18.35 19.45 20.6 21.83 23.12 24.5 25.96 27.5 29.14 30.87 32.7 34.65 36.71 38.89 41.2 43.65 46.25 49 51.91 55 58.27 61.74 65.41 69.3 73.42 77.78 82.41 87.31 92.5 98 103.83 110 116.54 123.47 130.81 138.59 146.83 155.56 164.81 174.61 185 196 207.65 220 233.08 246.94 261.63 277.18 293.66 311.13 329.63 349.23 369.99 392 415.3 440 466.16 493.88 523.25 554.37 587.33 622.25 659.25 698.46 739.99 783.99 830.61 880 932.33 987.77 1046.5 1108.73 1174.66 1244.51 1318.51 1396.91 1479.98 1567.98 1661.22 1760 1864.66 1975.53 2093 2217.46 2349.32 2489.02 2637.02 2793.83 2959.96 3135.96 3322.44 3520 3729.31 3951.07 4186.01 4434.92 4698.63 4978.03 5274.04 5587.65 5919.91 6271.93 6644.88 7040 7458.62 7902.13];

Notes = ["C0" "Db0" "D0" "Eb0" "E0" "F0" "Gb0" "G0" "Ab0" "A0" "Bb0" "B0" "C1" "Db1" "D1" "Eb1" "E1" "F1" "Gb1" "G1" "Ab1" "A1" "Bb1" "B1" "C2" "Db2" "D2" "Eb2" "E2" "F2" "Gb2" "G2" "Ab2" "A2" "Bb2" "B2" "C3" "Db3" "D3" "Eb3" "E3" "F3" "Gb3" "G3" "Ab3" "A3" "Bb3" "B3" "C4" "Db4" "D4" "Eb4" "E4" "F4" "Gb4" "G4" "Ab4" "A4" "Bb4" "B4" "C5" "Db5" "D5" "Eb5" "E5" "F5" "Gb5" "G5" "Ab5" "A5" "Bb5" "B5" "C6" "Db6" "D6" "Eb6" "E6" "F6" "Gb6" "G6" "Ab6" "A6" "Bb6" "B6" "C7" "Db7" "D7" "Eb7" "E7" "F7" "Gb7" "G7" "Ab7" "A7" "Bb7" "B7" "C8"];

note=Notes(index);

frequency=frequencies(index);

end



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有