I'm a Mathematica novice, so i think there is a lot of space to improve the code.
Here is Youtube Link.Hopefully you like it.
First I use the Bach's manuscript as the music score, but the output sound is chaos around the middle part.This score fit to play with the instrument, obviously not Mathematica.
After posting this awful version to my Weibo, my friend told me there is a Canon played by Matlab, it's so amazing, the most important its score suits for playing with software, so i decided to translate this score from Matlab to Mathematica.
Matlab code
There are 3 parts in Matlab code.
1.First, tell the computer how to make certain sounds.
There is a part of the code in Matlab (I'm a Chinese student, hopefully my poor English didn't confuse you. I will attach some concepts' wikilink, sorry about that)
% 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);
% 1/8 notes
fa0e = mod8.*cos(2*pi*ScaleTable(1)*f0*t8);
so0e = mod8.*cos(2*pi*ScaleTable(2)*f0*t8);
la0e = mod8.*cos(2*pi*ScaleTable(3)*f0*t8);
% 1/16 notes
fa0s = mod16.*cos(2*pi*ScaleTable(1)*f0*t16);
so0s = mod16.*cos(2*pi*ScaleTable(2)*f0*t16);
la0s = mod16.*cos(2*pi*ScaleTable(3)*f0*t16);
For clear to see, I just pick few notes information
i.$\frac{1}{4} $,$\frac{1}{8} $,$\frac{1}{16} $means [the relative duration of a note][4](https://en.wikipedia.org/wiki/Note_value), the duration of Quarter note is twice that of Eighth note, the duration of 8th note is twice that of 16th note. In the Matlab code, the duration depends on $t4,t8, or\space t16$
ii.Obviously, "do0f" means the note's tone. If you plot the the curve of middle A, it will be like that
Middle A's frequency "f" is 440Hz. In the Matlab code, the frequency depends on "$ScaleTable(\space)\times f0$"
iii.mod is a modification function, it makes notes sound more soft. the number behind "mod" means it's duration
So the Matlab code looks more clear! It becomes$$notename=mod4\times cos(2\pi f t)$$ This the way how to make sounds in Matlab.
2.Second, tell the computer musical score
This part is easy to understand, just input the score.
% Base Melody
cello = [do1f do1f so0f so0f la0f la0f mi0f mi0f... fa0f fa0f do0f do0f fa0f fa0f so0f so0f];......
% Long Melody
violin = [mi2f mi2f re2f re2f do2f do2f ti1f ti1f... la1f la1f so1f so1f la1f la1f ti1f ti1f ......
3.Third, arrange the different instruments' sequence
Canon is an very interesting music style, you just need to put the same melody at 3 different time points, and done! (I know I didn't explain it clearly, you can see Canon's wiki link)
It looks beautiful in code
% violin1
v1 = [blkblock violin blkblock blkblock];
% violin2
v2 = [blkblock blkblock violin blkblock];
% violin3
v3 = [blkblock blkblock blkblock violin];
% Combination
s = c1+v1+v2+v3;
sound(s,fs);
Translate to Mathematica
We get all information about all notes and musical score, but it's Matlab code, not Mathematica, we need use Mathematica code translate it.(The Mathematica file at the bottom of the article, it's a little bit long, so I decided not to paste it here)
- First, make the association between the note name and sound respectively in Mathematica. The output should be like this. I named this association "nametosoundass", remember this name.
2.Next, we should get the list of sequence of every instrument should be play.
i.Input the raw sequence in Matlab to Mathematica, as you can see, there are many characters we don't want to get, such as "...", "%%", return and whitespace
cellonoteinfo =
"do1f do1f so0f so0f la0f%% la0f mi0f mi0f...fa0f%% fa0f do0f do0f fa0f \n
fa0f so0f so0f";
ii.Define a function to delete these unexpected characters
infotonote[info_] :=
StringPartition[StringJoin@StringCases[info, _?LetterQ | _?DigitQ],
4];
iii.Get the sequence
In[1]:= cellonote = infotonote[cellonoteinfo]
Out[1]:= {"do1f", "do1f", "so0f", "so0f", "la0f", "la0f", "mi0f", "mi0f", \
"fa0f", "fa0f", "do0f", "do0f", "fa0f", "fa0f", "so0f", "so0f"}
3.Third, replace the note name in sequence by sound, then we will get the sound in sequence. We use the association "notetosoundass"
cello = Sound[Flatten@Table[Replace[cellonote, notetosoundass, 1], 23], {0}];
vio1 = Sound[Replace[violinnote, notetosoundass, 1], {8}];
vio2 = Sound[Replace[violinnote, notetosoundass, 1], {16}];
vio3 = Sound[Replace[violinnote, notetosoundass, 1], {24}];
0,8,16,24 at the end of code means the insert time of different instruments.
4.Finally, combine it
You can enjoy it here
BTW, this code runs 2 minutes to generate final music, i think it can be better, if you have another idea, glad to see your comment.
Both Matlab and Mathematica code are below.
Attachments: