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
|
# Calcul du FFT
|
||||||
signal = soundbox.load_signal(source_file)
|
signal = soundbox.load_signal(source_file)
|
||||||
|
freq_scale = soundbox.samp_rate / len(signal)
|
||||||
|
|
||||||
vecs = np.fft.fft(signal)[:soundbox.samp_rate // 2]
|
vecs = np.fft.fft(signal)[:soundbox.samp_rate // 2]
|
||||||
values = np.absolute(vecs) / np.max(np.absolute(vecs))
|
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
|
# Génération du graphe
|
||||||
plt.style.use('ggplot')
|
plt.style.use('ggplot')
|
||||||
|
@ -30,15 +41,9 @@ plt.rcParams.update({
|
||||||
|
|
||||||
fig, ax = plt.subplots()
|
fig, ax = plt.subplots()
|
||||||
ax.tick_params(axis='both', which='major', labelsize=12)
|
ax.tick_params(axis='both', which='major', labelsize=12)
|
||||||
|
ax.plot(freq, values)
|
||||||
freq_filter = values >= 0.01
|
|
||||||
freq = np.arange(len(values))
|
|
||||||
ax.plot(freq[freq_filter], values[freq_filter])
|
|
||||||
|
|
||||||
# Configuration des axes
|
# Configuration des axes
|
||||||
freq_scale = soundbox.samp_rate / len(signal)
|
|
||||||
|
|
||||||
|
|
||||||
def freq_format(value, pos):
|
def freq_format(value, pos):
|
||||||
return f'{value * freq_scale:.0f} Hz'
|
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
|
return signal
|
||||||
|
|
||||||
notes = {
|
notes = {
|
||||||
'do': 0, 'si#': 0,
|
'si#': 0, 'do': 0,
|
||||||
'do#': 1, 'reb': 1,
|
'reb': 1, 'do#': 1,
|
||||||
're': 2,
|
're': 2,
|
||||||
're#': 3, 'mib': 3,
|
'mib': 3, 're#': 3,
|
||||||
'mi': 4, 'fab': 4,
|
'fab': 4, 'mi': 4,
|
||||||
'fa': 5, 'mi#': 5,
|
'mi#': 5, 'fa': 5,
|
||||||
'fa#': 6, 'solb': 6,
|
'solb': 6, 'fa#': 6,
|
||||||
'sol': 7,
|
'sol': 7,
|
||||||
'sol#': 8, 'lab': 8,
|
'lab': 8, 'sol#': 8,
|
||||||
'la': 9,
|
'la': 9,
|
||||||
'la#': 10, 'sib': 10,
|
'sib': 10, 'la#': 10,
|
||||||
'si': 11, 'dob': 11,
|
'dob': 11, 'si': 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rev_notes = dict(zip(*reversed(list(zip(*notes.items())))))
|
||||||
|
|
||||||
def note_freq(note, octave):
|
def note_freq(note, octave):
|
||||||
"""
|
"""
|
||||||
|
@ -144,6 +145,24 @@ def note_freq(note, octave):
|
||||||
* math.pow(2, (notes[note] - 9) / 12))
|
* 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):
|
def note_freqs(notes):
|
||||||
"""Calcule la fréquence correspondant à un ensemble de notes."""
|
"""Calcule la fréquence correspondant à un ensemble de notes."""
|
||||||
return list(map(lambda info: note_freq(*info), 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