Hi, with the help of GPTs I came up with this code… With this code, you can easily transcribe sheet music into Sonic Pi by using scale degrees instead of absolute note names. This simplifies the process of adapting melodies, harmonies, and basslines to different keys and octaves. By referencing musical scale degrees (e.g., 1 for tonic, 5 for dominant) and adding optional alterations (sharp, flat, or natural), you can efficiently reproduce melodies and harmonies without worrying about recalculating exact notes for every key change.
Additionally, the code allows you to isolate musical layers. For instance, you can mute the melody, bass, or harmony while keeping other parts active. This is especially useful for play-along practice with your instrument. You can play the melody or solo part yourself while the program provides harmonic and rhythmic accompaniment, turning it into a highly customizable backing track.
By combining layers and adjusting the playback settings, this code is a versatile tool for learning, practicing, and performing music.
AS FOLLOWS:
# Noite Feliz / Silent Night
# Referência: https://youtu.be/isBnNxnvBOE?si=fDrPsa4_OhKMBhGM
# Tempo / Tempo
use_bpm 77 # Silent Night é tocada em andamento lento / Silent Night is played at a slow tempo
# Tonalidade / Key
TONALIDADE = :a # Define a tonalidade da música / Defines the song's key
ESCALA = scale(TONALIDADE, :major) # Gera a escala baseada na tonalidade / Generates the scale based on the key
# Função para calcular graus da escala com oitava
# Function to calculate scale degrees with octave
def grau(n, oitava = 4, alteracao = nil)
nota_base = ESCALA[n - 1] # Nota no grau da escala / Note in the scale degree
nota = nota_base + (oitava - 4) * 12 # Ajusta para a oitava desejada / Adjusts to the desired octave
alterar_nota(nota, alteracao) # Aplica alterações (bemol, sustenido, etc.) / Applies alterations (flat, sharp, etc.)
end
# Função para alterar uma nota (sustenido, bemol ou bequadro)
# Function to alter a note (sharp, flat, or natural)
def alterar_nota(nota, alteracao)
caso = {
flat: -1, # Bemol: abaixa meio tom / Flat: lowers half a step
sharp: 1, # Sustenido: sobe meio tom / Sharp: raises half a step
natural: 0 # Bequadro: retorna a nota natural / Natural: resets the note
}
if alteracao == :natural
nota_original = ESCALA.find { |n| n % 12 == nota % 12 } # Nota natural na mesma oitava / Natural note in the same octave
return nota_original + (nota / 12).floor * 12 # Garante a oitava correta / Ensures the correct octave
elsif caso.key?(alteracao)
return nota + caso[alteracao]
else
return nota
end
end
# Mapeamento de durações nomeadas / Mapping of named durations
DURACOES = {
semibreve: 4, # Whole note
minima: 2, # Half note
seminima: 1, # Quarter note
colcheia: 0.5, # Eighth note
semicolcheia: 0.25, # Sixteenth note
fusa: 0.125, # Thirty-second note
semifusa: 0.0625 # Sixty-fourth note
}
# Função para calcular durações com ponto de aumento
# Function to calculate dotted note durations
def ponto(duracao_nomeada)
if DURACOES.key?(duracao_nomeada)
DURACOES[duracao_nomeada] * 1.5
else
puts "Duração '#{duracao_nomeada}' não encontrada. Usando 0." # Duration not found. Using 0.
0
end
end
# Função para tocar notas ou acordes com respeito ao tempo
# Function to play notes or chords respecting their duration
def tocar_camada(camadas, tipo: :nota)
camadas.each do |elemento|
som, duracao_nomeada = elemento
duracao = duracao_nomeada.is_a?(Numeric) ? duracao_nomeada : DURACOES[duracao_nomeada] || 0
if som == :pausa
sleep duracao # Pausa / Rest
else
if tipo == :sample
sample som, amp: 0.8 # Percussão / Percussion
elsif som.is_a?(Array) # Para acordes / For chords
play som, amp: 1, release: duracao
else
play som, amp: 1, release: duracao
end
sleep duracao
end
end
end
# Função para construir acordes baseados nos graus e oitavas
# Function to build chords based on scale degrees and octaves
def acorde(grau, oitava, tipo = :major)
chord(grau(grau, oitava), tipo)
end
# Camadas musicais / Musical layers
# Melodia / Melody
# Harmonia / Harmony
# Baixo / Bass
# Percussão / Percussion
# Noite Feliz: Camadas
melodia = [
# 1 a 5 é pausa
# 6 e 30
[grau(5, 4), ponto(:seminima)], # Noi
[grau(6, 4), :colcheia], # te
[grau(5, 4), :seminima], # fe
# 7 e 31
[grau(3, 4), ponto(:minima)], # liz
#8 e 32
[grau(5, 4), ponto(:seminima)], # noi
[grau(6, 4), :colcheia], [grau(5, 4), :seminima], # te fe
#9 e 33
[grau(3, 4), ponto(:minima)], # liz
# 10 e 34
[grau(2, 5), :minima], [grau(2, 5), :seminima], # Ó se
# 11 e 35
[grau(7, 4), ponto(:minima)], # nhor
#12 e 36
[grau(1, 5), :minima], [grau(1, 5), :seminima], # Deus de a
#13 e 37
[grau(5, 4), ponto(:minima)], # mor
#14 e 38
[grau(6, 4), :minima], [grau(6, 4), :seminima], # Pobre
#15 e 39
[grau(1, 5), ponto(:seminima)], [grau(7, 4), :colcheia], [grau(6, 4), :seminima], # zinho na
#16 e 40
[grau(5, 4), ponto(:seminima)], [grau(6, 4), :colcheia], [grau(5, 4), :seminima], # sceu em Be
#17 e 41
[grau(3, 4), ponto(:minima)], # lém
# 18 e 42
[grau(6, 4), :minima], [grau(6, 4), :seminima], # Eis na
# 19 e 43
[grau(1, 5), ponto(:seminima)], [grau(7, 4), :colcheia], [grau(6, 4), :seminima], # lapa Je
# 20 e 44
[grau(5, 4), ponto(:seminima)], [grau(6, 4), :colcheia], [grau(5, 4), :seminima], # sus nosso
# 21 e 45
[grau(3, 4), ponto(:minima)], # bem
# 22 e 46
[grau(2, 5), :minima], [grau(2, 5), :seminima], #Dorme
#23 e 47
[grau(4, 5), ponto(:seminima)], [grau(2, 5), :colcheia], [grau(7, 4), :seminima], # em paz ó
# 24 e 48
[grau(1, 5), ponto(:minima)], # Je
# 25 e 49
[grau(3, 5), ponto(:minima)], # su
#26 e 50
[grau(1, 5), :seminima], [grau(5, 4), :seminima], [grau(3, 4), :seminima], # us Dorme
#27 e 51
[grau(5, 4), ponto(:seminima)], [grau(4, 4), :colcheia], [grau(2, 4), :seminima], # em paz ó Je
# 28 e 29 (arco de ligação) e 52 a 53
[grau(1, 4), ponto(:semibreve)] #sus
]
harmonia_inicio_fim = [
# Compassos 1 a 5 e 54 a 57
[acorde(1, 3), ponto(:minima)], # D3 (Grau 1, oitava 3)
[acorde(5, 3), ponto(:minima)], # A3
[acorde(4, 3, :minor), ponto(:minima)], # G3
[acorde(5, 3), ponto(:minima)], # A3
[acorde(4, 3), ponto(:minima)], # G3
]
harmonia = [
# 6 e 30
[acorde(1, 3), ponto(:minima)], # D3 (Grau 1, oitava 3)
# 7 e 31
[acorde(5, 3), ponto(:minima)], # A3
# 8 e 32
[acorde(4, 3), ponto(:minima)], # G3
#9 e 33
[acorde(3, 3), ponto(:minima)], # liz
# 10 e 34
[acorde(2, 4), ponto(:minima)], # Ó se
# 11 e 35
[acorde(7, 3), ponto(:minima)], # nhor
#12 e 36
[acorde(1, 4), ponto(:minima)], # Deus de a
#13 e 37
[acorde(5, 3), ponto(:minima)], # mor
#14 e 38
[acorde(6, 3), ponto(:minima)], # Pobre
#15 e 39
[acorde(1, 4), ponto(:minima)], # zinho na
#16 e 40
[acorde(5, 3), ponto(:minima)], # sceu em Be
#17 e 41
[acorde(3, 3), ponto(:minima)],
# 18 e 42
[acorde(6, 3), ponto(:minima)],
# 19 e 43
[acorde(1, 4), ponto(:minima)],
# 20 e 44
[acorde(5, 3), ponto(:minima)],
# 21 e 45
[acorde(3, 3), ponto(:minima)],
# 22 e 46
[acorde(2, 4), ponto(:minima)],
#23 e 47
[acorde(4, 4), ponto(:minima)],
# 24 e 48
[acorde(1, 4), ponto(:minima)],
# 25 e 49
[acorde(3, 4), ponto(:minima)],
#26 e 50
[acorde(1, 4), ponto(:minima)],
#27 e 51
[acorde(5, 3), ponto(:minima)],
# 28 e 29 (arco de ligação) e 52 a 53
[acorde(1, 3), ponto(:semibreve)]
]
baixo = [
# 1 a 5 em silêncio
# 6 e 30
[grau(1, 2), ponto(:minima)], # D2
# 7 e 31
[grau(5, 2), ponto(:minima)], # A2
# 8 e 32
[grau(4, 2), ponto(:minima)], # G2
#9 e 33
[grau(3, 2), ponto(:minima)], # liz
# 10 e 34
[grau(2, 3), ponto(:minima)], # Ó se
# 11 e 35
[grau(7, 2), ponto(:minima)], # nhor
#12 e 36
[grau(1, 3), ponto(:minima)], # Deus de a
#13 e 37
[grau(5, 2), ponto(:minima)], # mor
#14 e 38
[grau(6, 2), ponto(:minima)], # Pobre
#15 e 39
[grau(1, 3), ponto(:minima)], # zinho na
#16 e 40
[grau(5, 2), ponto(:minima)], # sceu em Be
#17 e 41
[grau(3, 2), ponto(:minima)],
# 18 e 42
[grau(6, 2), ponto(:minima)],
# 19 e 43
[grau(1, 3), ponto(:minima)],
# 20 e 44
[grau(5, 2), ponto(:minima)],
# 21 e 45
[grau(3, 2), ponto(:minima)],
# 22 e 46
[grau(2, 3), ponto(:minima)],
#23 e 47
[grau(4, 3), ponto(:minima)],
# 24 e 48
[grau(1, 3), ponto(:minima)],
# 25 e 49
[grau(3, 3), ponto(:minima)],
#26 e 50
[grau(1, 3), ponto(:minima)],
#27 e 51
[grau(5, 2), ponto(:minima)],
# 28 e 29 (arco de ligação) e 52 a 53
[grau(1, 2), ponto(:semibreve)]
]
# Percussão (Padrão 3/4 usando samples)
percussao = [
#1 compasso
[:drum_cymbal_closed, :colcheia], [:pausa, :colcheia], [:drum_bass_hard, :colcheia],
[:pausa, :colcheia], [:drum_snare_hard, :colcheia], [:pausa, :colcheia]
]
# Reproduz a música uma vez
in_thread {tocar_camada(harmonia_inicio_fim, tipo: :nota)
2.times do
tocar_camada(harmonia, tipo: :nota)
end
tocar_camada(harmonia_inicio_fim.drop(2), tipo: :nota)}
in_thread { sleep 15
tocar_camada(baixo, tipo: :nota) }
in_thread {
sleep 15 # Compassos 1 a 5
46.times do
tocar_camada(percussao, tipo: :sample)
end
}
sleep 15 # Compassos 1 a 5
2.times do
tocar_camada(melodia, tipo: :nota)
end
User Manual for the Code
1. Requirements
- Install Sonic Pi on your computer.
- Copy and paste the complete code into a Sonic Pi buffer.
2. Initial Setup
- Change the key: Adjust the
TONALIDADE
variable to set the desired key (e.g.,:a
for A major,:d
for D major). - Change the tempo (BPM): Modify the
use_bpm
value to set the playback speed (e.g.,77
for a slow tempo).
3. Modifying the Music
-
Melody, Harmony, and Bass:
- These are defined in the
melodia
,harmonia
, andbaixo
arrays. - Add or edit notes using the
grau(n, oitava, alteracao)
function:n
: Scale degree (1 for tonic, 5 for dominant, etc.).oitava
: Octave of the note (e.g., 4 for middle range, 5 for higher range).alteracao
(optional): Use:sharp
for sharp,:flat
for flat, or:natural
to remove accidentals.
- These are defined in the
-
Percussion Patterns:
- Modify the
percussao
array to create new rhythms. - Example:
percussao = [ [:drum_bass_hard, :colcheia], [:drum_snare_soft, :colcheia], [:pausa, :colcheia], [:drum_cymbal_closed, :colcheia], [:pausa, :colcheia], [:drum_bass_hard, :colcheia] ]
- Modify the
4. Running the Code
- Press the “Run” button in Sonic Pi to play the song.
- The program will play Silent Night (Noite Feliz) once, including synchronized melody, harmony, bass, and percussion.
5. Customizing Notes
- Use the
grau
function to reference scale degrees instead of absolute note names:- Example:
grau(1, 4)
corresponds to the tonic in the 4th octave (e.g., D4 in D major).
- Example:
- Alterations:
- Add
:sharp
for sharp notes,:flat
for flat notes, or:natural
to return to a natural note.
- Add
6. Advanced Customization
-
Adding New Layers:
- Create new layers, e.g.,
new_layer = [...]
, and play them usingin_thread
:in_thread { tocar_camada(new_layer, tipo: :nota) }
- Create new layers, e.g.,
-
Changing Instruments:
- Adjust the synthesizer or sample used for each layer:
- Replace
:saw
with other options like:piano
,:pluck
, etc., in theplay
method. - For percussion, use Sonic Pi’s built-in drum samples, such as
:drum_snare_soft
or:drum_tom_hi_soft
.
- Replace
- Adjust the synthesizer or sample used for each layer:
7. Example Adjustments
Change Key to G Major:
TONALIDADE = :g
Faster Tempo:
use_bpm 120
Add Variation to Percussion:
percussao = [
[:drum_bass_hard, :colcheia], [:drum_snare_hard, :colcheia], [:drum_cymbal_closed, :colcheia],
[:pausa, :colcheia], [:drum_snare_soft, :colcheia], [:drum_bass_hard, :colcheia]
]
Summary of Functions
-
grau(n, oitava = 4, alteracao = nil)
:- Converts scale degrees to actual notes.
- Example:
grau(5, 4, :sharp)
gives the 5th degree (dominant) with a sharp alteration in the 4th octave.
-
alterar_nota(nota, alteracao)
:- Alters notes with
:sharp
,:flat
, or:natural
.
- Alters notes with
-
ponto(duracao_nomeada)
:- Calculates dotted durations.
- Example:
ponto(:minima)
returns 3 beats for a dotted half note.
-
tocar_camada(camadas, tipo: :nota)
:- Plays the specified layer (
melodia
,harmonia
,baixo
, orpercussao
).
- Plays the specified layer (
-
acorde(grau, oitava, tipo = :major)
:- Constructs chords based on scale degrees.
- Example:
acorde(1, 3, :minor)
gives the tonic chord in minor.