Recently I started reading a book called: "Pro C# 10 with .NET 6. Foundational Principles and Practices in Programming". In it I found an interesting method that I didn't know about. It is not a method of any super unknown or fancy class; it belongs to the first class we all see when writing our first line of code in C#: the Console class. I hadn't even taken a close look at the members that contained it, and that's why I missed it. I don't consider it a very useful method, but something interesting, because of what I discovered I could do with it.
If we take a look at its definition we can appreciate that it has 2 overloads, but we are only going to work with the second one: Console.Beep(Int32, Int32). The first parameter refers to the frequency of the sound emitted by the console, while the second refers to the duration of that sound. I immediately remembered that each musical note has a specific frequency and wondered if I could use this method to play a song. Obviously I am neither the first nor the last to come up with this, so I started searching the internet for articles related to the subject. The most laborious part of all this is the musical part, not the programmatic part, but the internet is wonderful and I found several code repositories that you can try on your own computers. Of course, my idea with this article is not to give you the repository and make copy-paste, but to give you a brief explanation from my humble understanding of the subject. Probably from this article you will learn more about music than about programming. I hope you enjoy it.
Hace poco empecé a leer un libro llamado: "Pro C# 10 with .NET 6. Foundational Principles and Practices in Programming". En él encontré un método interesante que no conocía. No es un método de ninguna clase súper desconocida o rebuscada; pertenece a la primera clase que vemos todos a la hora de escribir nuestra primera línea de código en C#: la clase Console. Yo ni siquiera me había puesto a revisar con atención los miembros que la contenían, y es por eso que se me pasó por alto. No considero que sea un método demasiado útil, pero si algo interesante, por lo que descubrí que podía hacer con él.
Si le echamos un vistazo a su definición podemos apreciar que tiene 2 sobrecargas, pero sólo vamos a trabajar con la segunda: Console.Beep(Int32, Int32). El primer parámetro se refiere a la frecuencia del sonido emitido por la consola, mientras que el segundo se refiere a la duración de ese sonido. Inmediatamente recordé que cada nota musical tiene una frecuencia específica y me pregunté si podría utilizar este método para tocar una canción. Obviamente no soy el primero ni el último al que se le ocurre esto, por lo que comencé a buscar en internet artículos relacionados con el tema. Lo más trabajoso de todo esto es la parte musical, no la parte de programar, pero el internet es maravilloso y encontré varios repositorios de código que ustedes mismos podrán probar en sus computadoras. Por supuesto, mi idea con este artículo no es darles el repositorio y que hagan copy-paste, sino darles una breve explicación desde mi humilde comprensión acerca del tema. Probablemente de este artículo aprendan más de música que de programación 😅. Espero lo disfruten.
But first a few basic concepts - [Pero primero unos conceptos básicos]
Sound in combination with silence is the raw material of music. A sound has 4 basic qualities: pitch, duration, intensity and timbre. Of these only 2 are of interest to us, as they are the only ones that we can modify directly through our Beep() method: pitch and duration. The pitch indicates whether the sound is low, high or medium, and is determined by the frequency of the sound wave, measured in Hertz (Hz). Recall that the first parameter of our method collects the frequency of the sound we want to emit through the console. The duration is the time during which the sound is sustained. We can listen to long, short, very short sounds, etc., and we can express it in milliseconds through the second parameter.
In western music certain tones were established, which we call notes, whose sequence of 12 is repeated, forming octaves (C, C#, D, D#, D#, E, F, F#, G, G#, A, A#, B). Each octave doubles the frequency of that note in the previous octave. Musical notes are used in musical notation to represent pitch, and for duration a musical figure is usually used, which is nothing more than a symbol that graphically represents precisely that, the duration of a sound or silence in a piece of music (whole note, half note, quarter note, eighth note, sixteenth note, thirty-second note and sixty-fourth note). This is the way musicians read music and these are the fundamental pieces that will help us when putting together our program.
El sonido en combinación con el silencio son la materia prima de la música. Un sonido tiene 4 cualidades básicas: altura, duración, intensidad y timbre. De ellas sólo nos interesan 2, pues son las únicas que podemos modificar directamente a través de nuestro método Beep(): la altura y la duración. La altura indica si el sonido es grave, agudo o medio, y se determina a través de la frecuencia de la onda sonora, medida en hercios (Hz). Recordemos que el primer parámetro de nuestro método recoge la frecuencia del sonido que queremos emitir por la consola. La duración es el tiempo durante el cual se mantiene el sonido. Podemos escuchar sonidos largos, cortos, muy cortos, etc., y podemos expresarla en milisegundos a través del segundo parámetro.
En la música occidental se fueron estableciendo tonos determinados a los que llamamos notas, cuya secuencia de 12 se va repitiendo, formando octavas (Do, Do#, Re, Re#, Mi, Fa, Fa#, Sol, Sol#, La, La#, Si). En cada octava se duplica la frecuencia de dicha nota en la octava anterior. Las notas musicales se utilizan en la notación musical para representar la altura y para la duración se suele emplear una figura musical, que no es más que un símbolo que representa gráficamente precisamente eso, la duración de un sonido o de un silencio en una pieza musical (redonda, blanca, negra, corchea, semicorchea, fusa y semifusa). Esta es la forma que tienen los músicos de leer la música y son las piezas fundamentales que nos servirán a la hora de armar nuestro programa.
Musical figures. Note that each one represents half of the previous one
Figuras musicales. Nota que cada una representa la mitad de la anterior
To play a song using our method, we first need to know the frequencies of the musical notes. It is not necessary to look up each one of them, there is a simple formula that allows us to calculate them:
Para tocar una canción usando nuestro método, primero necesitamos conocer las frecuencias de las notas musicales. No es necesario buscar cada una de ellas, existe una sencilla fórmula que nos permite calcularlas:
In this formula f represents the frequency to be calculated, 440Hz is the value of a reference point we will use, A4, and n is the distance at which a certain note is separated from A4, expressed in semitones. If the note is above A4, then n is positive, and if it is below A4, then n is negative. If we look at the keys of a piano, a semitone is nothing more than the interval between 2 adjacent keys. Thus, we can create a simple method to calculate the frequencies of all the musical notes.
En esta fórmula f representa la frecuencia a calcular, 440Hz es el valor de un punto de referencia que utilizaremos, el La4, y n es la distancia a la cual se encuentra cierta nota separada de La4, expresada en semitonos. Si la nota está por encima de La4, entonces n es positivo, y si está por debajo de La4, entonces n es negativo. Si miramos las teclas de un piano, un semitono no es más que el intervalo entre 2 teclas adyacentes. Así, podemos crear un método sencillo para calcular las frecuencias de todas las notas musicales.
Finally, we need to know some concepts related to the duration of notes: pulse, tempo and time signature. The pulse is the basic unit used to measure time. It is a constant succession of repeated beats, dividing the time into equal parts.
The tempo refers to the speed at which a piece of music should be played. In the scores of a piece of music it is usually represented at the beginning, at the top of the staff, and can be done in 2 ways. Before the invention of the metronome, words were used to indicate whether the rhythm of the piece was slow (andante) or fast (allegro). In Western music it is usually indicated by a number, which expresses the number of beats per minute (bpm).
Time signature is simply a subdivision of the beats of the song. It is expressed by a fraction in the score. The numerator of the fraction indicates the number of beats and the denominator indicates the musical figure to be used. For example, suppose the time signature of the song is 4/4. If we express the fraction as 4 * 1/4 we can visualize it better. This means that the number of beats per measure is going to be 4, and the musical figure we are going to use is the quarter note, this is, 4 quarter notes per measure. Look at the image of the musical figures and you will notice it right away (by the way, a quarter note represents a beat in the piece of music).
Por último, necesitamos conocer unos conceptos relacionados con la duración de las notas: pulso, tempo y compás. El pulso es la unidad básica que se usa para medir el tiempo. Se trata de una sucesión constante de pulsaciones que se repiten, dividiendo el tiempo en partes iguales.
El tempo hace referencia a la velocidad con la que debe ejecutarse una pieza musical. En las partituras de una obra se suele representar al inicio, encima del pentagrama, y puede hacerse de 2 maneras. Antes de la invención del metrónomo se empleaban palabras que indicaban si el ritmo de la pieza era lento (andante), o si por el contrario era rápido (allegro), etc. En la música occidental se suele indicar con un número, que expresa la cantidad de pulsaciones por minuto (ppm).
El compás es simplemente una subdivisión que se hace de los pulsos de la canción. Se expresa a través de una fracción en la partitura. El numerador de la fracción indica la cantidad de pulsaciones y el denominador indica la figura musical que se va a utilizar. Por ejemplo, supongamos que el compás de la canción es 4/4. Si expresamos la fracción como 4 * 1/4 podemos visualizarlo mejor. Esto significa que la cantidad de pulsaciones por compás va a ser de 4, y la figura musical que vamos a usar es la negra, o sea, 4 negras por compás. Checa la imagen de las figuras musicales y te darás cuenta enseguida (por cierto, una negra representa una pulsación en la pieza musical).
To know the duration of each note we only need to know the tempo and the musical figure that indicates the time signature of the song. From the beats per minute we calculate the beats every second and combining this with the musical figure gives us the duration of that note. Then we only have to express it in milliseconds, since the parameter of our method is expressed in this unit.
As I said before, music is not only composed of sounds but also of rests. Rests are also expressed through the musical figures, which receive the same name as the previous ones in terms of their value, but different graphical representation. To simulate a rest in our program, we execute the line of code: Thread.Sleep(Int32), with the duration also expressed in milliseconds.
Para conocer la duración de cada nota sólo necesitamos conocer el tempo y la figura musical que nos indica el compás de la canción. De las pulsaciones por minuto calculamos las pulsaciones cada segundo y combinando esto con la figura musical nos da la duración de dicha nota. Luego sólo nos queda expresarla en milisegundos, ya que el parámetro de nuestro método está expresado en esta unidad.
Cómo dije antes la música no sólo se compone de sonidos sino también de silencios. Los silencios también se expresan a través de las figuras musicales, las cuales reciben el mismo nombre que las anteriores en cuanto a su valor, pero diferente representación gráfica. Para simular un silencio en nuestro programa, ejecutamos la línea de código Thread.Sleep(Int32), con la duración expresada también en milisegundos.
Musical figures to express silences in music
Figuras musicales para expresar los silencios en la música
Putting all the pieces together - [Uniendo todas las piezas]
Now let's put it all in code. First we need to define the frequencies of each note. To do this we will use the method we made up earlier and write the value of each note (as well as the value of the rest) in an enum. For this small example we will only need to work with the third and fourth octave.
Ahora pongámoslo todo en código. Primero necesitamos definir las frecuencias de cada nota. Para ello utilizaremos el método que confeccionamos anteriormente y escribiremos el valor de cada nota (así como el valor del silencio) en un enum. Para este pequeño ejemplo sólo necesitaremos trabajar con la tercera y la cuarta octava.
Then we are going to declare the values of the musical figures. Let's remember that a quarter note is equal to one beat and that each figure is equal to half of the previous one.
Luego vamos a declarar los valores de las figuras musicales. Recordemos que una negra equivale a una pulsación y que cada figura es igual a la mitad de la anterior.
In addition we will represent a note through a structure, taking as parameters in the constructor the frequency of the note, the musical figure and the tempo. We use a structure instead of a class, because we will have to create many object instances to represent the notes of our song and structures are more efficient for this purpose.
Además representaremos una nota a través de una estructura, tomando como parámetros en el constructor la frecuencia de la nota, la figura musical y el tempo. Utilizamos una estructura en lugar de una clase, porque tendremos que crear muchas instancias de objeto para representar las notas de nuestra canción y las estructuras son más eficiente para este propósito.
We will also need a method that plays all the notes of the song, as well as the rests.
También necesitaremos un método que reproduzca todas las notas de la canción, así como los silencios.
Now we only have to declare in the Main() method our set of notes, which we will do by means of an array, and call the Play() method to finally play our song.
Ahora sólo nos queda declarar en el método Main() nuestro conjunto de notas, lo cual haremos mediante una matriz, y llamar al método Play() para que por fin toque nuestra canción.
Websites and articles - [Páginas web y artículos]
And that is all. I hope you enjoyed this long post as much as I enjoyed doing it. Here I am going to leave you some of the pages I used to guide me when writing the post, as well as my Git-Hub repository with the program code.
Y eso es todo. Espero que hayan disfrutado de este largo post tanto como yo disfruté hacerlo. Aquí les voy a dejar algunas de las páginas que utilicé para guiarme a la hora de elaborar el post, así como mi repositorio de Git-Hub con el código del programa.
This is my repository: music-with-console
https://github.com/Kirito0922/music-with-console/blob/e01e0ed9b92641e7fdf94fc8c5945a7ed94bbc51/Program.cs
Console.Beep Method
https://learn.microsoft.com/en-us/dotnet/api/system.console.beep?view=net-8.0
Take On Me by a-ha converted to C# console beeps · GitHub
https://gist.github.com/Shensd/01342e2f399de4dca2ca87b36059ba0a
Super Mario Song using Console.Beep()
https://hashtagakash.wordpress.com/2014/01/22/182/
C# modo console: Músicas com o Console.Beep - dfilitto
https://dfilitto.blog.br/desenvolvimento/c-sharp/c-modo-console-musicas-com-o-console-beep/
Music in console c# - vbCity - The .NET Developer Community
http://vbcity.com/forums/t/133752.aspx
Just play some Console Music ... · GitHub
https://gist.github.com/Twelve0fNine/9141812
Figura musical
https://es.wikipedia.org/wiki/Figura_musical
Nota (sonido)
https://es.wikipedia.org/wiki/Nota_(sonido)
Tempo
https://es.wikipedia.org/wiki/Tempo
Notación musical
https://es.wikipedia.org/wiki/Notaci%C3%B3n_musical
Compás (música)
https://es.wikipedia.org/wiki/Comp%C3%A1s_(m%C3%BAsica)
Ahora a tocar algo de Snoop Dog 😎
Sus deseos son órdenes 😎