Ajout script pour décoder les notes
This commit is contained in:
parent
a9cd4d2207
commit
e751df5f8b
|
@ -0,0 +1,33 @@
|
|||
import soundbox
|
||||
import numpy as np
|
||||
import scipy.signal as sig
|
||||
import sys
|
||||
|
||||
if len(sys.argv) != 2:
|
||||
print(f"""Utilisation: {sys.argv[0]} [source]
|
||||
|
||||
Détermine les notes jouées dans le fichier [source] en utilisant
|
||||
la transformation de Fourier.""")
|
||||
sys.exit(1)
|
||||
|
||||
source_file = sys.argv[1]
|
||||
|
||||
# Calcul du FFT
|
||||
signal = soundbox.load_signal(source_file)
|
||||
freq_scale = soundbox.samp_rate / len(signal)
|
||||
|
||||
vecs = np.fft.fft(signal)[:soundbox.samp_rate // 2]
|
||||
values = np.absolute(vecs) / np.max(np.absolute(vecs))
|
||||
freq = np.arange(len(values))
|
||||
|
||||
# Calcul de la fenêtre des fréquences intéressantes
|
||||
high_enough = np.where(values >= 0.005)
|
||||
left = high_enough[0][0]
|
||||
right = high_enough[0][-1]
|
||||
|
||||
freq = freq[left:right]
|
||||
values = values[left:right]
|
||||
|
||||
# Recherche des pics
|
||||
peaks, _ = sig.find_peaks(values, height=0.1, distance=10 / freq_scale)
|
||||
print(list(map(soundbox.freq_note, freq[peaks] * freq_scale)))
|
19
fft-graph.py
19
fft-graph.py
|
@ -17,8 +17,19 @@ output_file = sys.argv[2]
|
|||
|
||||
# Calcul du FFT
|
||||
signal = soundbox.load_signal(source_file)
|
||||
freq_scale = soundbox.samp_rate / len(signal)
|
||||
|
||||
vecs = np.fft.fft(signal)[:soundbox.samp_rate // 2]
|
||||
values = np.absolute(vecs) / np.max(np.absolute(vecs))
|
||||
freq = np.arange(len(values))
|
||||
|
||||
# Calcul de la fenêtre des fréquences intéressantes
|
||||
high_enough = np.where(values >= 0.005)
|
||||
left = high_enough[0][0]
|
||||
right = high_enough[0][-1]
|
||||
|
||||
freq = freq[left:right]
|
||||
values = values[left:right]
|
||||
|
||||
# Génération du graphe
|
||||
plt.style.use('ggplot')
|
||||
|
@ -30,15 +41,9 @@ plt.rcParams.update({
|
|||
|
||||
fig, ax = plt.subplots()
|
||||
ax.tick_params(axis='both', which='major', labelsize=12)
|
||||
|
||||
freq_filter = values >= 0.01
|
||||
freq = np.arange(len(values))
|
||||
ax.plot(freq[freq_filter], values[freq_filter])
|
||||
ax.plot(freq, values)
|
||||
|
||||
# Configuration des axes
|
||||
freq_scale = soundbox.samp_rate / len(signal)
|
||||
|
||||
|
||||
def freq_format(value, pos):
|
||||
return f'{value * freq_scale:.0f} Hz'
|
||||
|
||||
|
|
37
soundbox.py
37
soundbox.py
|
@ -113,20 +113,21 @@ def chord(instr, dur, freqs, value=1):
|
|||
return signal
|
||||
|
||||
notes = {
|
||||
'do': 0, 'si#': 0,
|
||||
'do#': 1, 'reb': 1,
|
||||
'si#': 0, 'do': 0,
|
||||
'reb': 1, 'do#': 1,
|
||||
're': 2,
|
||||
're#': 3, 'mib': 3,
|
||||
'mi': 4, 'fab': 4,
|
||||
'fa': 5, 'mi#': 5,
|
||||
'fa#': 6, 'solb': 6,
|
||||
'mib': 3, 're#': 3,
|
||||
'fab': 4, 'mi': 4,
|
||||
'mi#': 5, 'fa': 5,
|
||||
'solb': 6, 'fa#': 6,
|
||||
'sol': 7,
|
||||
'sol#': 8, 'lab': 8,
|
||||
'lab': 8, 'sol#': 8,
|
||||
'la': 9,
|
||||
'la#': 10, 'sib': 10,
|
||||
'si': 11, 'dob': 11,
|
||||
'sib': 10, 'la#': 10,
|
||||
'dob': 11, 'si': 11,
|
||||
}
|
||||
|
||||
rev_notes = dict(zip(*reversed(list(zip(*notes.items())))))
|
||||
|
||||
def note_freq(note, octave):
|
||||
"""
|
||||
|
@ -144,6 +145,24 @@ def note_freq(note, octave):
|
|||
* math.pow(2, (notes[note] - 9) / 12))
|
||||
|
||||
|
||||
def freq_note(freq):
|
||||
"""
|
||||
Retrouve la note correspondant au mieux à une fréquence.
|
||||
|
||||
Paramètres:
|
||||
note
|
||||
"""
|
||||
log = math.log2(freq / note_freq('do', 3))
|
||||
octave = math.floor(log) + 3
|
||||
note = round(12 * log - 12 * math.floor(log))
|
||||
|
||||
if note == 12:
|
||||
octave += 1
|
||||
note = 0
|
||||
|
||||
return (rev_notes[note], octave)
|
||||
|
||||
|
||||
def note_freqs(notes):
|
||||
"""Calcule la fréquence correspondant à un ensemble de notes."""
|
||||
return list(map(lambda info: note_freq(*info), notes))
|
||||
|
|
BIN
sounds/synth.wav
BIN
sounds/synth.wav
Binary file not shown.
Loading…
Reference in New Issue