Forgotten music or a little about Nokia 3310, PC-Seaker and MIDI file generation (part 1)
Here we’ll talk a little about the melody format (RTTL) in older phone models, about playing such melodies using a regular PC-Speaker computer, and about creating (generating) MIDI files. I will reinforce all my thoughts with Pascal code.
I must make a reservation right away that this article most likely does not represent any practical interest for the majority and was created by the author rather for himself, as a keepsake, so to speak ... But enough of the lyrics, let's begin.
I think that many people still remember how, sitting in a gallery at a school or institute, they retyped melodies of the form “8e, 16d, 16b4,16a4,16b4,8a4,16a4,16a # 4” from the phone of their comrades. This so-called RTTL format for recording melodies. It does not make sense to describe it in detail here, since the description is completely available on the Internet , but for further understanding we will consider the simplest example. So, let's take this RTTL tune:
Simpsons: d = 4, o = 5, b = 160: 32p, c.6, e6, f # 6.8a6, g.6, e6, c6,8a, 8f #, 8f # , 8f #, 2g
As you can see, the format is
[name : duration , octave , speed per minute (BPM) : the melody itself].
We will need the following parameters:
“d = 4”Note duration is the default. This means that in the recording of the melody itself, when we want to play the note a “la” with a duration of 4, we will not necessarily record it as “ 4a ”. It will be enough to write it simply as “ a ”. Here I note that if we compare the duration of RTTL and the duration of a note in musical terms, then there is a simple correspondence - 1 / duration of RTTL. Thus, “d = 4” in the RTTL record means that we play notes by default, with a duration of “one fourth”. If d = 6, then “one sixth” and so on.
“O = 5”Octave by default. From the theory of music, recall that an octave is a doubled frequency between identical notes. So, if the note “a” of the fourth octave has a frequency of 440 Hz, then the same note “a” of the fifth octave will have a frequency of 880 Hz. Exactly the same as with the duration, in the further recording we do not need to write the note a “for” the fifth octave as “ a5 ”. Just write it as “ a ” and we will play the note “a” for the fifth octave with a duration of one fourth. Thus, it turns out that in our case the record “ a ” will be equivalent to the record “ 4a5 ”.
“B = 160”. Pace, or speed per minute (BPM). To calculate the milliseconds that a note should sound, I used the following formula: ((60000 / b) / d) * 8, where b is our tempo and d is the duration of the note. Why so, I already confess and forgot myself. But it works :)
Then the melody itself begins. From the description it follows that the format for recording notes in the general case is as follows:
[duration note octave add. sign].
Commas act as a separator between notes. Notes are used in the English (?) Recording system 'c', 'c #', 'd', 'd #', 'e', 'f', 'f #', 'g', 'g #', 'a', ' a # ',' b ', which corresponds to the Italian' before ',' before sharp ',' re ',' re sharp ',' mi ',' fa ',' f sharp ',' salt ',' salt sharp ', 'la', 'la sharp', 'si'. And also a pause - 'p'.
Additional characters may be: " ."(dot) - an increase in the duration of a note by one and a half times
" ; "(semicolon) - twice
" & "(ampersand) - 2.5 times
There should be no problem with this - when we find one of such signs at the end of a note, we will simply multiply the calculated milliseconds by ½, two and two and a half times.
With the theory on this, if there are any questions, I recommend again reading the description of the RTTL format.
To begin with, we will output our melody for simplicity to a regular PC-Speaker. In most programming languages, to output sound to the speaker, we need to know only two parameters - frequency and delay in milliseconds. So, in Virtual Pascal there is a procedure
which I will use.
Now let's think and start with a simple one. Let's say that our melody consists of only one note and looks like this: “test: d = 4, o = 5, b = 125: a”. Thus, we need to play the note “for” the fifth octave with a duration of one fourth with a tempo of 125. The first thing that comes to mind is that we need to know all note frequencies for all octaves, for this we naturally build a frequency table:
Excellent. Further, the whole business rests on the analysis of the recording of notes for duration, octave, and actually the note itself. I think it’s inappropriate to bring parsing here if someone is interested in the full source code of the program at the end of the article. Let us examine only the calculation in the table of the note itself. I implemented it like this:
So, now in the variable “i” is the offset in the frequency array of the note we need. Now you can process the “#” sign (sharp) at the end, and if it is present in the note, simply increase the “i” value by one. Now we can play a note while with a duration of 1000 ms with a simple command:
With a note and frequency sorted out. It remains only to figure out the duration of the note. Above, I already gave a formula by which I calculated the duration of the sound in milliseconds, depending on the tempo and duration of the note itself. Below is just the code:
The main thing here is not to forget about the additional values “dot”, “semicolon” or “ampersand”, which may be present in musical notation, and, depending on their availability, multiply the value of PrecalcMS by ½, 2 or 2.5. This is in the main program, I am not presenting it here. That's it, now we can play a note with the frequency defined above and the duration we need:
And in the main program we play a note:
In such a simple way, we implemented the RTTL melody player on PC-Speaker. The full source code of the program, as well as the compiled version, are available here: rghost.ru/2230394 I used Virtual Pascal to compile, but I think that I should get together in Free Pascal without any problems.
In the next article, we will talk about creating an RTTL 2 MIDI converter in general and creating and working with MIDI files in particular. Have a good day!
When writing the article, the materials used were:
personal.telefonica.terra.es/web/japus/rtplayer.html
www.music4sale.ru/articles/knowledge_base/586
members.home.nl/bas.de.reuver/files/convert_rtttl.html
I must make a reservation right away that this article most likely does not represent any practical interest for the majority and was created by the author rather for himself, as a keepsake, so to speak ... But enough of the lyrics, let's begin.
Theory.
I think that many people still remember how, sitting in a gallery at a school or institute, they retyped melodies of the form “8e, 16d, 16b4,16a4,16b4,8a4,16a4,16a # 4” from the phone of their comrades. This so-called RTTL format for recording melodies. It does not make sense to describe it in detail here, since the description is completely available on the Internet , but for further understanding we will consider the simplest example. So, let's take this RTTL tune:
Simpsons: d = 4, o = 5, b = 160: 32p, c.6, e6, f # 6.8a6, g.6, e6, c6,8a, 8f #, 8f # , 8f #, 2g
As you can see, the format is
[name : duration , octave , speed per minute (BPM) : the melody itself].
We will need the following parameters:
“d = 4”Note duration is the default. This means that in the recording of the melody itself, when we want to play the note a “la” with a duration of 4, we will not necessarily record it as “ 4a ”. It will be enough to write it simply as “ a ”. Here I note that if we compare the duration of RTTL and the duration of a note in musical terms, then there is a simple correspondence - 1 / duration of RTTL. Thus, “d = 4” in the RTTL record means that we play notes by default, with a duration of “one fourth”. If d = 6, then “one sixth” and so on.
“O = 5”Octave by default. From the theory of music, recall that an octave is a doubled frequency between identical notes. So, if the note “a” of the fourth octave has a frequency of 440 Hz, then the same note “a” of the fifth octave will have a frequency of 880 Hz. Exactly the same as with the duration, in the further recording we do not need to write the note a “for” the fifth octave as “ a5 ”. Just write it as “ a ” and we will play the note “a” for the fifth octave with a duration of one fourth. Thus, it turns out that in our case the record “ a ” will be equivalent to the record “ 4a5 ”.
“B = 160”. Pace, or speed per minute (BPM). To calculate the milliseconds that a note should sound, I used the following formula: ((60000 / b) / d) * 8, where b is our tempo and d is the duration of the note. Why so, I already confess and forgot myself. But it works :)
Then the melody itself begins. From the description it follows that the format for recording notes in the general case is as follows:
[duration note octave add. sign].
Commas act as a separator between notes. Notes are used in the English (?) Recording system 'c', 'c #', 'd', 'd #', 'e', 'f', 'f #', 'g', 'g #', 'a', ' a # ',' b ', which corresponds to the Italian' before ',' before sharp ',' re ',' re sharp ',' mi ',' fa ',' f sharp ',' salt ',' salt sharp ', 'la', 'la sharp', 'si'. And also a pause - 'p'.
Additional characters may be: " ."(dot) - an increase in the duration of a note by one and a half times
" ; "(semicolon) - twice
" & "(ampersand) - 2.5 times
There should be no problem with this - when we find one of such signs at the end of a note, we will simply multiply the calculated milliseconds by ½, two and two and a half times.
With the theory on this, if there are any questions, I recommend again reading the description of the RTTL format.
Pc speaker
To begin with, we will output our melody for simplicity to a regular PC-Speaker. In most programming languages, to output sound to the speaker, we need to know only two parameters - frequency and delay in milliseconds. So, in Virtual Pascal there is a procedure
PlaySound (Freq, Duration: Longint);
which I will use.
Now let's think and start with a simple one. Let's say that our melody consists of only one note and looks like this: “test: d = 4, o = 5, b = 125: a”. Thus, we need to play the note “for” the fifth octave with a duration of one fourth with a tempo of 125. The first thing that comes to mind is that we need to know all note frequencies for all octaves, for this we naturally build a frequency table:
Var
Frequency: Array [1..8 * 12] of word; {frequency table}
{....... some code .......}
Procedure InitFreqTable; {Procedure for initializing the frequency table}
Const
HerzOfFirst = 32.703195258; {note C of the first octave}
Var
tmpReal1, tmpReal2: real;
i: word;
Begin
tmpReal1: = HerzOfFirst; {start with the first note C of the first octave}
tmpReal2: = exp (ln (2.0) /12.0); {constant with which the frequency changes from note to note}
for i: = 1 to 8 * 12 do {12 notes per octave, 8 octaves}
begin
Frequency [i]: = round (tmpReal1);
tmpReal1: = tmpReal1 * tmpReal2;
end;
End
Excellent. Further, the whole business rests on the analysis of the recording of notes for duration, octave, and actually the note itself. I think it’s inappropriate to bring parsing here if someone is interested in the full source code of the program at the end of the article. Let us examine only the calculation in the table of the note itself. I implemented it like this:
{previously we parsed the duration and the octave}
// parse note
{i - will indicate the offset in the frequency table}
i: = (octave-1) * 12; {first move to the desired octave}
Case S [1] of {In s [1] is the note symbol}
'c': inc (i, 1); {and add a note to the offset}
'd': inc (i, 3); {here we do not take into account sharps, I process them after}
'e': inc (i, 5);
'f': inc (i, 6);
'g': inc (i, 8);
'a': inc (i, 10);
'b', 'h': inc (i, 12);
'p': i: = 0;
PlayRTTTLNote: = 1;
WriteLn ('DEBUG: Error [1]: Wrong note - "', S [1], '"');
exit
end;
So, now in the variable “i” is the offset in the frequency array of the note we need. Now you can process the “#” sign (sharp) at the end, and if it is present in the note, simply increase the “i” value by one. Now we can play a note while with a duration of 1000 ms with a simple command:
PlaySound (Frequency [i], 1000);
With a note and frequency sorted out. It remains only to figure out the duration of the note. Above, I already gave a formula by which I calculated the duration of the sound in milliseconds, depending on the tempo and duration of the note itself. Below is just the code:
// calculate microseconds
PrecalcMS: = (60000 / BPMspeed); {BMPspeed is the pace, that is, the parameter “b =”}
PrecalcMS: = (PrecalcMS / Duration) * 8; {duration - the parsed frequency of the note}
MicroSecs: = round (PrecalcMS); {round to integer}
The main thing here is not to forget about the additional values “dot”, “semicolon” or “ampersand”, which may be present in musical notation, and, depending on their availability, multiply the value of PrecalcMS by ½, 2 or 2.5. This is in the main program, I am not presenting it here. That's it, now we can play a note with the frequency defined above and the duration we need:
Procedure PlayNote (Note: byte; MicroSecs: Word);
Begin
If Note = 0 then {Remember, if we met “p”, then set I = 0}
Delay (MicroSecs) {means this is a pause}
Else
playsound (Frequency [Note], microsecs);
End;
And in the main program we play a note:
PlayNote (I, MicroSecs);
In such a simple way, we implemented the RTTL melody player on PC-Speaker. The full source code of the program, as well as the compiled version, are available here: rghost.ru/2230394 I used Virtual Pascal to compile, but I think that I should get together in Free Pascal without any problems.
In the next article, we will talk about creating an RTTL 2 MIDI converter in general and creating and working with MIDI files in particular. Have a good day!
When writing the article, the materials used were:
personal.telefonica.terra.es/web/japus/rtplayer.html
www.music4sale.ru/articles/knowledge_base/586
members.home.nl/bas.de.reuver/files/convert_rtttl.html