- gain function moved to helpers/__init__
- cleanup some unused functions
- stop can now wait for fade_out to finish before returning
- volume can be incremented
- master volume
import argparse
import sys
import os
import argparse
import sys
import os
class Config:
def __init__(self, **kwargs):
class Config:
def __init__(self, **kwargs):
return "{:2}:{:0>2}".format(minutes, seconds)
else:
return "{}:{:0>2}".format(minutes, seconds)
return "{:2}:{:0>2}".format(minutes, seconds)
else:
return "{}:{:0>2}".format(minutes, seconds)
+
+def gain(volume, old_volume = None):
+ if old_volume is None:
+ return 20 * math.log10(volume / 100)
+ else:
+ return [20 * math.log10(max(volume, 0.1) / max(old_volume, 0.1)), max(volume, 0)]
+
raise Exception("Unknown action {}".format(action))
self.key = key
raise Exception("Unknown action {}".format(action))
self.key = key
+ self.mapping = key.parent
self.arguments = kwargs
self.sleep_event = None
self.arguments = kwargs
self.sleep_event = None
if music is not None:
return [music]
else:
if music is not None:
return [music]
else:
- return self.key.parent.open_files.values()
+ return self.mapping.open_files.values()
def pause(self, music = None, **kwargs):
for music in self.music_list(music):
def pause(self, music = None, **kwargs):
for music in self.music_list(music):
if not music.is_not_stopped():
music.play(volume = volume, fade_in = fade_in, start_at = start_at)
if not music.is_not_stopped():
music.play(volume = volume, fade_in = fade_in, start_at = start_at)
- def stop(self, music = None, fade_out = 0, **kwargs):
+ def stop(self, music = None, fade_out = 0, wait = False, **kwargs):
+ previous = None
for music in self.music_list(music):
if music.is_loaded_paused() or music.is_loaded_playing():
for music in self.music_list(music):
if music.is_loaded_paused() or music.is_loaded_playing():
- music.stop(fade_out = fade_out)
+ if previous is not None:
+ previous.stop(fade_out = fade_out)
+ previous = music
+
+ if previous is not None:
+ previous.stop(fade_out = fade_out, wait = wait)
def stop_all_actions(self, **kwargs):
def stop_all_actions(self, **kwargs):
- self.key.parent.stop_all_running()
+ self.mapping.stop_all_running()
- def volume(self, music = None, value = 100, **kwargs):
+ def volume(self, music = None, value = 100, add = False, **kwargs):
- music.set_volume(value)
+ music.set_volume(value, add = add)
+ self.mapping.set_master_volume(value, add = add)
def wait(self, duration = 0, music = None, **kwargs):
self.sleep_event = threading.Event()
def wait(self, duration = 0, music = None, **kwargs):
self.sleep_event = threading.Event()
- def stop_print(self, music = None, fade_out = 0, **kwargs):
+ def stop_print(self, music = None, fade_out = 0, wait = False, **kwargs):
+ message = "stopping "
- if fade_out == 0:
- return "stopping music « {} »".format(music.name)
- else:
- return "stopping music « {} » with {}s fadeout".format(music.name, fade_out)
+ message += "music « {} »".format(music.name)
- if fade_out == 0:
- return "stopping all musics"
- else:
- return "stopping all musics with {}s fadeout".format(fade_out)
+ message += "all musics"
+
+ if fade_out > 0:
+ message += " with {}s fadeout".format(fade_out)
+ if wait:
+ message += " (waiting the end of fadeout)"
+
+ return message
def stop_all_actions_print(self, **kwargs):
return "stopping all actions"
def stop_all_actions_print(self, **kwargs):
return "stopping all actions"
- def volume_print(self, music = None, value = 100, **kwargs):
- if music is not None:
- return "setting volume of « {} » to {}%".format(music.name, value)
+ def volume_print(self, music = None, value = 100, add = False, **kwargs):
+ if add:
+ if music is not None:
+ return "{:+d}% to volume of « {} »".format(value, music.name)
+ else:
+ return "{:+d}% to volume".format(value)
- return "setting volume to {}%".format(value)
+ if music is not None:
+ return "setting volume of « {} » to {}%".format(music.name, value)
+ else:
+ return "setting volume to {}%".format(value)
def wait_print(self, duration = 0, music = None, **kwargs):
if music is None:
def wait_print(self, duration = 0, music = None, **kwargs):
if music is None:
import sys
from .music_file import *
import sys
from .music_file import *
+from . import yml_file,gain
class Mapping(RelativeLayout):
expected_keys = NumericProperty(0)
class Mapping(RelativeLayout):
expected_keys = NumericProperty(0)
+ master_volume = NumericProperty(100)
ready_color = ListProperty([1, 165/255, 0, 1])
def __init__(self, **kwargs):
ready_color = ListProperty([1, 165/255, 0, 1])
def __init__(self, **kwargs):
Clock.schedule_interval(self.not_all_keys_ready, 1)
Clock.schedule_interval(self.not_all_keys_ready, 1)
+ @property
+ def master_gain(self):
+ return gain(self.master_volume)
+
+ def set_master_volume(self, value, add = False):
+ [db_gain, self.master_volume] = gain(value + int(add) * self.master_volume, self.master_volume)
+ for music in self.open_files.values():
+ music.set_gain(db_gain)
+
def _keyboard_closed(self):
self._keyboard.unbind(on_key_down=self._on_keyboard_down)
self._keyboard = None
def _keyboard_closed(self):
self._keyboard.unbind(on_key_down=self._on_keyboard_down)
self._keyboard = None
return self.ids["Key_" + str(key_code[0])]
return None
return self.ids["Key_" + str(key_code[0])]
return None
- def find_by_unicode(self, key_sym):
- for key in self.children:
- if not type(key).__name__ == "Key":
- continue
- print(key.key_sym, key_sym)
- if key.key_sym == key_sym:
- print("found")
- return key
- return None
-
def not_all_keys_ready(self, dt):
for key in self.children:
if not type(key).__name__ == "Key":
def not_all_keys_ready(self, dt):
for key in self.children:
if not type(key).__name__ == "Key":
if filename in config['music_properties']:
seen_files[filename] = MusicFile(
filename,
if filename in config['music_properties']:
seen_files[filename] = MusicFile(
filename,
**config['music_properties'][filename])
else:
seen_files[filename] = MusicFile(
**config['music_properties'][filename])
else:
seen_files[filename] = MusicFile(
filename)
if filename not in key_properties[mapped_key]['files']:
filename)
if filename not in key_properties[mapped_key]['files']:
import threading
import pydub
import threading
import pydub
import time
from transitions.extensions import HierarchicalMachine as Machine
import time
from transitions.extensions import HierarchicalMachine as Machine
import os.path
from .lock import Lock
import os.path
from .lock import Lock
file_lock = Lock("file")
pyaudio = pa.PyAudio()
class MusicFile(Machine):
file_lock = Lock("file")
pyaudio = pa.PyAudio()
class MusicFile(Machine):
- def __init__(self, filename, name = None, gain = 1):
+ def __init__(self, filename, mapping, name = None, gain = 1):
states = [
'initial',
'loading',
states = [
'initial',
'loading',
Machine.__init__(self, states=states, transitions=transitions, initial='initial')
Machine.__init__(self, states=states, transitions=transitions, initial='initial')
+ self.volume = 100
+ self.mapping = mapping
self.filename = filename
self.stream = None
self.name = name or filename
self.audio_segment = None
self.filename = filename
self.stream = None
self.name = name or filename
self.audio_segment = None
+ self.volume_factor = gain
self.music_lock = Lock("music__" + filename)
self.wait_event = threading.Event()
self.music_lock = Lock("music__" + filename)
self.wait_event = threading.Event()
with file_lock:
try:
print("Loading « {} »".format(self.name))
with file_lock:
try:
print("Loading « {} »".format(self.name))
- volume_factor = 20 * math.log10(self.gain)
- self.audio_segment = pydub.AudioSegment.from_file(self.filename).set_frame_rate(44100).apply_gain(volume_factor)
+ db_gain = gain(self.volume_factor * 100)
+ self.audio_segment = pydub.AudioSegment.from_file(self.filename).set_frame_rate(44100).apply_gain(db_gain)
self.sound_duration = self.audio_segment.duration_seconds
except Exception as e:
print("failed to load « {} »: {}".format(self.name, e))
self.sound_duration = self.audio_segment.duration_seconds
except Exception as e:
print("failed to load « {} »: {}".format(self.name, e))
return 0
def play(self, fade_in = 0, volume = 100, start_at = 0):
return 0
def play(self, fade_in = 0, volume = 100, start_at = 0):
- self.db_gain = self.volume_to_gain(volume)
+ db_gain = gain(volume) + self.mapping.master_gain
+ self.volume = volume
+
ms = int(start_at * 1000)
ms_fi = max(1, int(fade_in * 1000))
with self.music_lock:
ms = int(start_at * 1000)
ms_fi = max(1, int(fade_in * 1000))
with self.music_lock:
- self.current_audio_segment = (self.audio_segment + self.db_gain).fade(from_gain=-120, duration=ms_fi, start=ms)
+ self.current_audio_segment = (self.audio_segment + db_gain).fade(from_gain=-120, duration=ms_fi, start=ms)
self.before_loaded_playing(initial_frame = int(start_at * self.audio_segment.frame_rate))
self.start_playing()
self.before_loaded_playing(initial_frame = int(start_at * self.audio_segment.frame_rate))
self.start_playing()
out_data[:] = audio_segment.ljust(len(out_data), b'\0')
out_data[:] = audio_segment.ljust(len(out_data), b'\0')
- def stop(self, fade_out = 0):
+ def stop(self, fade_out = 0, wait = False):
if self.is_loaded_playing():
ms = int(self.sound_position * 1000)
ms_fo = max(1, int(fade_out * 1000))
if self.is_loaded_playing():
ms = int(self.sound_position * 1000)
ms_fo = max(1, int(fade_out * 1000))
with self.music_lock:
self.current_audio_segment = self.current_audio_segment[:ms + ms_fo].fade_out(ms_fo)
self.stop_playing()
with self.music_lock:
self.current_audio_segment = self.current_audio_segment[:ms + ms_fo].fade_out(ms_fo)
self.stop_playing()
+ if wait:
+ self.wait_end()
else:
self.stop_playing()
self.stopped()
else:
self.stop_playing()
self.stopped()
- def set_volume(self, value):
- if self.is_loaded_stopped():
+ def set_gain(self, db_gain):
+ if not self.is_not_stopped():
- db_gain = self.volume_to_gain(value)
- new_audio_segment = self.current_audio_segment + (db_gain - self.db_gain)
- self.db_gain = db_gain
+ new_audio_segment = self.current_audio_segment + db_gain
+
with self.music_lock:
self.current_audio_segment = new_audio_segment
with self.music_lock:
self.current_audio_segment = new_audio_segment
- def volume_to_gain(self, volume):
- return 20 * math.log10(max(volume, 0.0001) / 100)
+ def set_volume(self, value, add = False):
+ [db_gain, self.volume] = gain(value + int(add) * self.volume, self.volume)
+
+ self.set_gain(db_gain)
def wait_end(self):
self.wait_event.clear()
def wait_end(self):
self.wait_event.clear()
Ellipse:
pos: self.width - self.key_size / 2, self.height - self.key_size /2
size: self.key_size / 3, self.key_size / 3
Ellipse:
pos: self.width - self.key_size / 2, self.height - self.key_size /2
size: self.key_size / 3, self.key_size / 3
+ Label:
+ font_name: h.path() + "fonts/Ubuntu-Regular.ttf"
+ font_size: math.ceil(2 * math.sqrt(self.parent.key_size or 10))
+ color: 0, 0, 0, 1
+ text: "volume: {}%".format(self.parent.master_volume)
+ valign: "top"
+ size_hint: None, None
+ size: self.texture_size[0], self.texture_size[1]
+ x: self.parent.width - self.width - 2 * self.parent.key_size / 3
+ center_y: self.parent.height - self.height
Key:
id: Key_27
key_code: 27
Key:
id: Key_27
key_code: 27