tuner code
This commit is contained in:
parent
824c752c51
commit
839411b1fd
85
code/tuner/main.py
Normal file
85
code/tuner/main.py
Normal file
@ -0,0 +1,85 @@
|
||||
import string
|
||||
from typing import Any
|
||||
from scipy.io import wavfile as wav
|
||||
import numpy as np
|
||||
import sounddevice as sd
|
||||
import math
|
||||
import sys
|
||||
|
||||
print("Tuner exercise")
|
||||
SAMPLE_RATE = 44100
|
||||
CHUNK = 2048
|
||||
QUIET_THRESHOLD = 0.01
|
||||
A4 = 440
|
||||
DEBUG = True
|
||||
NOTES = "A B♭/A♯ B C D♭/C♯ D E♭/D♯ E F F♯/G♭ G A♭/G♯".split()
|
||||
|
||||
|
||||
def calculate_note(frequency):
|
||||
if frequency > 0:
|
||||
note_num = round(math.log2(frequency / 440) * 12)
|
||||
octave = math.floor(4 + note_num / 12)
|
||||
rel_note = note_num % 12
|
||||
note = NOTES[rel_note]
|
||||
return f"{note}{octave}"
|
||||
return 0
|
||||
|
||||
|
||||
def dominant_frequency(data, samplerate):
|
||||
windowed_data = data * np.hanning(len(data))
|
||||
fft_result = np.fft.rfft(windowed_data)
|
||||
fft_magnitude = np.abs(fft_result)
|
||||
freqs = np.fft.rfftfreq(len(windowed_data), 1 / samplerate)
|
||||
peak_idx = np.argmax(fft_magnitude)
|
||||
dominant_freq = freqs[peak_idx]
|
||||
return dominant_freq
|
||||
|
||||
|
||||
def calculate_rms(data):
|
||||
return np.sqrt(np.mean(data**2))
|
||||
|
||||
|
||||
def audio_callback(indata: np.ndarray, frames: int, time: Any, status: Any):
|
||||
if status:
|
||||
print(f"Status: {status}")
|
||||
rms = calculate_rms(indata)
|
||||
|
||||
if rms > QUIET_THRESHOLD:
|
||||
mono_data = np.mean(indata, axis=1)
|
||||
frequency = dominant_frequency(mono_data, SAMPLE_RATE)
|
||||
out = f"\r{calculate_note(frequency)}"
|
||||
|
||||
if DEBUG: out += f" Dominant Frequency: {frequency:.2f} Hz (RMS: {rms:.3f})"
|
||||
sys.stdout.write(out)
|
||||
sys.stdout.flush()
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
if DEBUG:
|
||||
print(sd.query_devices())
|
||||
|
||||
|
||||
try:
|
||||
stream = sd.InputStream(
|
||||
device=15,
|
||||
callback=audio_callback,
|
||||
samplerate=SAMPLE_RATE,
|
||||
channels=1,
|
||||
blocksize=CHUNK,
|
||||
)
|
||||
stream.start()
|
||||
if DEBUG:
|
||||
print("channels? ", stream.channels)
|
||||
print("device? ", stream.device)
|
||||
print("active? ", stream.active)
|
||||
while True:
|
||||
pass
|
||||
except KeyboardInterrupt:
|
||||
print("Audio recording stopped.")
|
||||
|
||||
finally:
|
||||
print("Stream closed.")
|
||||
|
||||
# https://python-sounddevice.readthedocs.io/en/0.5.1/examples.html#plot-microphone-signal-s-in-real-time
|
||||
# https://github.com/mzucker/python-tuner/blob/master/tuner.py
|
Reference in New Issue
Block a user