updates
This commit is contained in:
parent
9a68619293
commit
823552ce7f
|
@ -0,0 +1,129 @@
|
|||
from typing import overload
|
||||
import librosa
|
||||
from numba import jit
|
||||
import numpy as np
|
||||
|
||||
|
||||
@jit(nopython=True)
|
||||
def normalize_feature_sequence(X, norm='2', threshold=0.0001, v=None):
|
||||
"""Normalizes the columns of a feature sequence
|
||||
Notebook: C3/C3S1_FeatureNormalization.ipynb
|
||||
Args:
|
||||
X (np.ndarray): Feature sequence
|
||||
norm (str): The norm to be applied. '1', '2', 'max' or 'z' (Default value = '2')
|
||||
threshold (float): An threshold below which the vector ``v`` used instead of normalization
|
||||
(Default value = 0.0001)
|
||||
v (float): Used instead of normalization below ``threshold``. If None, uses unit vector for given norm
|
||||
(Default value = None)
|
||||
Returns:
|
||||
X_norm (np.ndarray): Normalized feature sequence
|
||||
"""
|
||||
assert norm in ['1', '2', 'max', 'z']
|
||||
|
||||
K, N = X.shape
|
||||
X_norm = np.zeros((K, N))
|
||||
|
||||
if norm == '1':
|
||||
if v is None:
|
||||
v = np.ones(K, dtype=np.float64) / K
|
||||
for n in range(N):
|
||||
s = np.sum(np.abs(X[:, n]))
|
||||
if s > threshold:
|
||||
X_norm[:, n] = X[:, n] / s
|
||||
else:
|
||||
X_norm[:, n] = v
|
||||
|
||||
if norm == '2':
|
||||
if v is None:
|
||||
v = np.ones(K, dtype=np.float64) / np.sqrt(K)
|
||||
for n in range(N):
|
||||
s = np.sqrt(np.sum(X[:, n]**2))
|
||||
if s > threshold:
|
||||
X_norm[:, n] = X[:, n] / s
|
||||
else:
|
||||
X_norm[:, n] = v
|
||||
|
||||
if norm == 'max':
|
||||
if v is None:
|
||||
v = np.ones(K, dtype=np.float64)
|
||||
for n in range(N):
|
||||
s = np.max(np.abs(X[:, n]))
|
||||
if s > threshold:
|
||||
X_norm[:, n] = X[:, n] / s
|
||||
else:
|
||||
X_norm[:, n] = v
|
||||
|
||||
if norm == 'z':
|
||||
if v is None:
|
||||
v = np.zeros(K, dtype=np.float64)
|
||||
for n in range(N):
|
||||
mu = np.sum(X[:, n]) / K
|
||||
sigma = np.sqrt(np.sum((X[:, n] - mu)**2) / (K - 1))
|
||||
if sigma > threshold:
|
||||
X_norm[:, n] = (X[:, n] - mu) / sigma
|
||||
else:
|
||||
X_norm[:, n] = v
|
||||
|
||||
return X_norm
|
||||
|
||||
|
||||
def compute_chromagram_from_filename(fn_wav,
|
||||
Fs=22050,
|
||||
N=4096,
|
||||
H=2048,
|
||||
gamma=None,
|
||||
version='STFT',
|
||||
norm='2'):
|
||||
"""Compute chromagram for WAV file specified by filename
|
||||
|
||||
Notebook: C5/C5S2_ChordRec_Templates.ipynb
|
||||
|
||||
Args:
|
||||
fn_wav (str): Filenname of WAV
|
||||
Fs (scalar): Sampling rate (Default value = 22050)
|
||||
N (int): Window size (Default value = 4096)
|
||||
H (int): Hop size (Default value = 2048)
|
||||
gamma (float): Constant for logarithmic compression (Default value = None)
|
||||
version (str): Technique used for front-end decomposition ('STFT', 'IIS', 'CQT') (Default value = 'STFT')
|
||||
norm (str): If not 'None', chroma vectors are normalized by norm as specified ('1', '2', 'max')
|
||||
(Default value = '2')
|
||||
|
||||
Returns:
|
||||
X (np.ndarray): Chromagram
|
||||
Fs_X (scalar): Feature reate of chromagram
|
||||
x (np.ndarray): Audio signal
|
||||
Fs (scalar): Sampling rate of audio signal
|
||||
x_dur (float): Duration (seconds) of audio signal
|
||||
"""
|
||||
x, Fs = librosa.load(fn_wav, sr=Fs)
|
||||
x_dur = x.shape[0] / Fs
|
||||
if version == 'STFT':
|
||||
# Compute chroma features with STFT
|
||||
X = librosa.stft(x, n_fft=N, hop_length=H, pad_mode='constant', center=True)
|
||||
if gamma is not None:
|
||||
X = np.log(1 + gamma * np.abs(X)**2)
|
||||
else:
|
||||
X = np.abs(X)**2
|
||||
X = librosa.feature.chroma_stft(S=X, sr=Fs, tuning=0, norm=None, hop_length=H, n_fft=N)
|
||||
if version == 'CQT':
|
||||
# Compute chroma features with CQT decomposition
|
||||
X = librosa.feature.chroma_cqt(y=x, sr=Fs, hop_length=H, norm=None)
|
||||
if version == 'IIR':
|
||||
# Compute chroma features with filter bank (using IIR elliptic filter)
|
||||
X = librosa.iirt(y=x, sr=Fs, win_length=N, hop_length=H, center=True, tuning=0.0)
|
||||
if gamma is not None:
|
||||
X = np.log(1.0 + gamma * X)
|
||||
X = librosa.feature.chroma_cqt(C=X,
|
||||
bins_per_octave=12,
|
||||
n_octaves=7,
|
||||
fmin=librosa.midi_to_hz(24),
|
||||
norm=None)
|
||||
if norm is not None:
|
||||
X = normalize_feature_sequence(X, norm='2')
|
||||
Fs_X = Fs / H
|
||||
return X, Fs_X, x, Fs, x_dur
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_file = "/home/martin/Music/deemix Music/Simone Sommerland - Ki-Ka-Kinderturnen.mp3"
|
||||
chroma = compute_chromagram_from_filename(test_file)
|
|
@ -8,7 +8,10 @@ from player import AudioPlayer
|
|||
from glob import glob
|
||||
from copy import deepcopy
|
||||
import os
|
||||
from hass_client import HomeAssistantClient
|
||||
|
||||
HASS_URL = "https://ha.bauer.tech"
|
||||
HASS_TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI3YmY1OTc3NWJhZGI0MzFkOTBiNDBkZDA3OGQ1MTMxNSIsImlhdCI6MTY0MDAzNzI3MSwiZXhwIjoxOTU1Mzk3MjcxfQ.c7RPRP_hxzIwd3xcFTNLz94rOjLQDR0elH8RE-jCDgc"
|
||||
MUSIC_FOLDER = "/home/martin/code/musicmouse/espmusicmouse/host_driver/music"
|
||||
|
||||
audio_player = AudioPlayer()
|
||||
|
@ -96,6 +99,7 @@ def on_rfid(protocol, tagid):
|
|||
ring_eff = EffectSwipeAndChange()
|
||||
ring_eff.swipe.primary_color = ccfg.primary
|
||||
ring_eff.swipe.secondary_color = ccfg.secondary
|
||||
ring_eff.swipe.swipe_speed = 180
|
||||
ring_eff.change.color1 = ccfg.primary
|
||||
ring_eff.change.color2 = ccfg.secondary
|
||||
protocol.led_ring_effect(ring_eff)
|
||||
|
@ -104,6 +108,7 @@ def on_rfid(protocol, tagid):
|
|||
mouse_eff = deepcopy(ring_eff)
|
||||
mouse_eff.swipe.start_position = 6 / 45 * 360
|
||||
mouse_eff.swipe.bell_curve_width_in_leds = 16
|
||||
mouse_eff.swipe.swipe_speed = 180
|
||||
protocol.mouse_led_effect(mouse_eff)
|
||||
|
||||
protocol.button_background_led_prev(0.3)
|
||||
|
@ -132,12 +137,23 @@ def on_firmware_msg(protocol: MusicMouseProtocol, message):
|
|||
audio_player.previous()
|
||||
elif message.button == "right" and message.event == "pressed":
|
||||
audio_player.next()
|
||||
elif isinstance(message, TouchButtonPress):
|
||||
ccfg = color_cfg[current_figure]
|
||||
protocol.mouse_led_effect(EffectStaticConfig(ccfg.accent,
|
||||
*mouse_leds[message.touch_button]))
|
||||
elif isinstance(message, TouchButtonRelease):
|
||||
ccfg = color_cfg[current_figure]
|
||||
elif False and isinstance(message, TouchButtonPress):
|
||||
if current_figure:
|
||||
ccfg = color_cfg[current_figure]
|
||||
protocol.mouse_led_effect(
|
||||
EffectStaticConfig(ccfg.accent, *mouse_leds[message.touch_button]))
|
||||
#if message.touch_button == TouchButton.RIGHT_FOOT:
|
||||
# asyncio.create_task(
|
||||
# hass.call_service("switch", "toggle", {"entity_id": "switch.tasmota06"}))
|
||||
# asyncio.create_task(
|
||||
# hass.call_service("light", "turn_on", {"entity_id": "light.arbeitszimmer_fluter"}))
|
||||
#elif message.touch_button == TouchButton.LEFT_FOOT:
|
||||
# asyncio.create_task(
|
||||
# hass.call_service("light", "turn_off", {"entity_id": "light.arbeitszimmer_fluter"}))
|
||||
|
||||
elif False and isinstance(message, TouchButtonRelease):
|
||||
if current_figure:
|
||||
ccfg = color_cfg[current_figure]
|
||||
eff_change = EffectRandomTwoColorInterpolationConfig()
|
||||
eff_static = EffectStaticConfig(ColorRGBW(0, 0, 0, 0), *mouse_leds[message.touch_button])
|
||||
if audio_player.is_playing():
|
||||
|
@ -152,6 +168,7 @@ def on_firmware_msg(protocol: MusicMouseProtocol, message):
|
|||
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
hass = HomeAssistantClient(HASS_URL, HASS_TOKEN, loop)
|
||||
coro = serial_asyncio.create_serial_connection(loop,
|
||||
MusicMouseProtocol,
|
||||
'/dev/ttyUSB0',
|
||||
|
@ -161,5 +178,6 @@ protocol.register_message_callback(on_firmware_msg)
|
|||
|
||||
audio_player.on_playlist_end_callback = lambda: on_music_end_callback(protocol)
|
||||
|
||||
loop.create_task(hass.connect())
|
||||
loop.run_forever()
|
||||
loop.close()
|
|
@ -12,7 +12,7 @@
|
|||
#include <cstring>
|
||||
|
||||
static constexpr int MAX_EFFECT_CONFIG_SIZE = 128;
|
||||
static constexpr int MAX_EFFECT_CLASS_SIZE = 4 * 1024;
|
||||
static constexpr int MAX_EFFECT_CLASS_SIZE = 8 * 1024;
|
||||
|
||||
template <typename TLedStrip>
|
||||
class LedTask
|
||||
|
|
|
@ -129,7 +129,7 @@ LedTask<decltype(ledStripCircle)> ledTaskCircle;
|
|||
|
||||
void setupLedCircle()
|
||||
{
|
||||
ledDriverCircle.begin(23, 0);
|
||||
ledDriverCircle.begin(22, 0);
|
||||
ledTaskCircle.begin(ledStripCircle, ledDriverCircle);
|
||||
ledTaskCircle.startEffect(EffectStaticConfig(ColorRGBW{0, 0, 0, 0}));
|
||||
}
|
||||
|
@ -147,6 +147,19 @@ void setupMouseLeds()
|
|||
ledTaskMouse.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 0, 0}, 0, 0});
|
||||
}
|
||||
|
||||
// -------------------------------------------------- Shelf Leds -------------------------------------------
|
||||
|
||||
LedStripRGBW<250> ledStripShelf;
|
||||
Esp32DriverRGBW ledDriverShelf;
|
||||
LedTask<decltype(ledStripShelf)> ledTaskShelf;
|
||||
|
||||
void setupShelfLeds()
|
||||
{
|
||||
ledDriverShelf.begin(17, 2);
|
||||
ledTaskShelf.begin(ledStripShelf, ledDriverShelf);
|
||||
ledTaskShelf.startEffect(EffectStaticConfig{ColorRGBW{0, 0, 30}, 0, 0});
|
||||
}
|
||||
|
||||
// -------------------------------------------------- Touch Buttons ----------------------------------------
|
||||
|
||||
constexpr auto TOUCH_PAD_RIGHT_EAR = TOUCH_PAD_NUM0;
|
||||
|
@ -205,6 +218,7 @@ void setup()
|
|||
setupButtons();
|
||||
setupTouchButtons();
|
||||
setupMouseLeds();
|
||||
setupShelfLeds();
|
||||
}
|
||||
|
||||
void loop()
|
||||
|
|
Loading…
Reference in New Issue