aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIsmaël Bouya <ismael.bouya@normalesup.org>2016-07-17 13:00:29 +0200
committerIsmaël Bouya <ismael.bouya@normalesup.org>2016-07-17 13:56:27 +0200
commit75d6cdbac628b57e206cd37808c1d3c7fecbb9eb (patch)
tree2b3633489452cf0a4528fd552bf19f83943a702a
parent22514f3ae6d4e19537ae5ab6bdb5bc9f99a64f47 (diff)
downloadMusicSampler-75d6cdbac628b57e206cd37808c1d3c7fecbb9eb.tar.gz
MusicSampler-75d6cdbac628b57e206cd37808c1d3c7fecbb9eb.tar.zst
MusicSampler-75d6cdbac628b57e206cd37808c1d3c7fecbb9eb.zip
Add new configurations parameters
-rw-r--r--helpers/__init__.py44
-rw-r--r--helpers/mapping.py7
-rw-r--r--helpers/mixer.py27
-rw-r--r--helpers/music_file.py5
4 files changed, 59 insertions, 24 deletions
diff --git a/helpers/__init__.py b/helpers/__init__.py
index 4b9529d..807aa44 100644
--- a/helpers/__init__.py
+++ b/helpers/__init__.py
@@ -6,11 +6,7 @@ import math
6import sounddevice as sd 6import sounddevice as sd
7 7
8class Config: 8class Config:
9 def __init__(self, **kwargs): 9 pass
10 for arg in kwargs:
11 setattr(self, arg, kwargs[arg])
12
13config = Config(yml_file="config.yml")
14 10
15def path(): 11def path():
16 if getattr(sys, 'frozen', False): 12 if getattr(sys, 'frozen', False):
@@ -29,11 +25,37 @@ def parse_args():
29 25
30 sys.argv.extend(kivy_args) 26 sys.argv.extend(kivy_args)
31 27
32 parser = argparse.ArgumentParser(description="A Music Sampler application.") 28 parser = argparse.ArgumentParser(
29 description="A Music Sampler application.",
30 formatter_class=argparse.ArgumentDefaultsHelpFormatter)
33 parser.add_argument("-c", "--config", 31 parser.add_argument("-c", "--config",
34 default="config.yml", 32 default="config.yml",
35 required=False, 33 required=False,
36 help="Config file to load") 34 help="Config file to load")
35 parser.add_argument("-l", "--latency",
36 default="high",
37 required=False,
38 help="Latency: low, high or number of seconds")
39 parser.add_argument("-b", "--blocksize",
40 default=0,
41 type=int,
42 required=False,
43 help="Blocksize: If not 0, the numbe of frames to take at each step for the mixer")
44 parser.add_argument("-f", "--frame-rate",
45 default=44100,
46 type=int,
47 required=False,
48 help="Frame rate to play the musics")
49 parser.add_argument("-x", "--channels",
50 default=2,
51 type=int,
52 required=False,
53 help="Number of channels to use")
54 parser.add_argument("-s", "--sample-width",
55 default=2,
56 type=int,
57 required=False,
58 help="Sample width (number of bytes for each frame)")
37 parser.add_argument("-V", "--version", 59 parser.add_argument("-V", "--version",
38 action="version", 60 action="version",
39 help="Displays the current version and exits. Only use in bundled package", 61 help="Displays the current version and exits. Only use in bundled package",
@@ -52,7 +74,12 @@ def parse_args():
52 help="Kivy arguments. All arguments after this are interpreted by Kivy. Pass \"-- --help\" to get Kivy's usage.") 74 help="Kivy arguments. All arguments after this are interpreted by Kivy. Pass \"-- --help\" to get Kivy's usage.")
53 args = parser.parse_args(argv) 75 args = parser.parse_args(argv)
54 76
55 config.yml_file = args.config 77 Config.yml_file = args.config
78 Config.latency = args.latency
79 Config.blocksize = args.blocksize
80 Config.frame_rate = args.frame_rate
81 Config.channels = args.channels
82 Config.sample_width = args.sample_width
56 83
57class SelectDeviceAction(argparse.Action): 84class SelectDeviceAction(argparse.Action):
58 def __call__(self, parser, namespace, values, option_string=None): 85 def __call__(self, parser, namespace, values, option_string=None):
@@ -71,9 +98,6 @@ def show_version():
71 else: 98 else:
72 return "option '-v' can only be used in bundled package" 99 return "option '-v' can only be used in bundled package"
73 100
74def yml_file():
75 return config.yml_file
76
77def duration_to_min_sec(duration): 101def duration_to_min_sec(duration):
78 minutes = int(duration / 60) 102 minutes = int(duration / 60)
79 seconds = int(duration) % 60 103 seconds = int(duration) % 60
diff --git a/helpers/mapping.py b/helpers/mapping.py
index 60c7691..8e0265c 100644
--- a/helpers/mapping.py
+++ b/helpers/mapping.py
@@ -9,7 +9,7 @@ import sys
9 9
10from .music_file import * 10from .music_file import *
11from .mixer import Mixer 11from .mixer import Mixer
12from . import yml_file,gain 12from . import Config, gain
13 13
14class Mapping(RelativeLayout): 14class Mapping(RelativeLayout):
15 expected_keys = NumericProperty(0) 15 expected_keys = NumericProperty(0)
@@ -17,6 +17,7 @@ class Mapping(RelativeLayout):
17 ready_color = ListProperty([1, 165/255, 0, 1]) 17 ready_color = ListProperty([1, 165/255, 0, 1])
18 18
19 def __init__(self, **kwargs): 19 def __init__(self, **kwargs):
20 self.mixer = Mixer()
20 self.key_config, self.open_files = self.parse_config() 21 self.key_config, self.open_files = self.parse_config()
21 super(Mapping, self).__init__(**kwargs) 22 super(Mapping, self).__init__(**kwargs)
22 self._keyboard = Window.request_keyboard(self._keyboard_closed, self) 23 self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
@@ -24,8 +25,6 @@ class Mapping(RelativeLayout):
24 self.running = [] 25 self.running = []
25 Clock.schedule_interval(self.not_all_keys_ready, 1) 26 Clock.schedule_interval(self.not_all_keys_ready, 1)
26 27
27 self.mixer = Mixer()
28
29 @property 28 @property
30 def master_gain(self): 29 def master_gain(self):
31 return gain(self.master_volume) 30 return gain(self.master_volume)
@@ -83,7 +82,7 @@ class Mapping(RelativeLayout):
83 self.running.remove((key, start_time)) 82 self.running.remove((key, start_time))
84 83
85 def parse_config(self): 84 def parse_config(self):
86 stream = open(yml_file(), "r") 85 stream = open(Config.yml_file, "r")
87 config = yaml.load(stream) 86 config = yaml.load(stream)
88 stream.close() 87 stream.close()
89 88
diff --git a/helpers/mixer.py b/helpers/mixer.py
index 9e8179a..d08520a 100644
--- a/helpers/mixer.py
+++ b/helpers/mixer.py
@@ -2,17 +2,28 @@ import sounddevice as sd
2import audioop 2import audioop
3import time 3import time
4 4
5frame_rate = 44100 5from . import Config
6channels = 2 6
7sample_width = 2 7sample_width = Config.sample_width
8def sample_width_to_dtype(sample_width):
9 if sample_width == 1 or sample_width == 2 or sample_width == 4:
10 return 'int' + str(8*sample_width)
11 else:
12 raise "Unknown sample width"
13
14def _latency(latency):
15 if latency == "high" or latency == "low":
16 return latency
17 else:
18 return float(latency)
8 19
9class Mixer: 20class Mixer:
10 def __init__(self): 21 def __init__(self):
11 self.stream = sd.RawOutputStream(samplerate=frame_rate, 22 self.stream = sd.RawOutputStream(samplerate=Config.frame_rate,
12 channels=channels, 23 channels=Config.channels,
13 dtype='int' + str(8*sample_width), # FIXME: ? 24 dtype=sample_width_to_dtype(Config.sample_width),
14 latency="high", 25 latency=_latency(Config.latency),
15 blocksize=5000, 26 blocksize=Config.blocksize,
16 callback=self.play_callback, 27 callback=self.play_callback,
17 ) 28 )
18 self.open_files = [] 29 self.open_files = []
diff --git a/helpers/music_file.py b/helpers/music_file.py
index 6da547b..f1aa341 100644
--- a/helpers/music_file.py
+++ b/helpers/music_file.py
@@ -6,7 +6,7 @@ from transitions.extensions import HierarchicalMachine as Machine
6import os.path 6import os.path
7 7
8from .lock import Lock 8from .lock import Lock
9from . import gain 9from . import Config, gain
10 10
11file_lock = Lock("file") 11file_lock = Lock("file")
12 12
@@ -48,7 +48,7 @@ class MusicFile(Machine):
48 try: 48 try:
49 print("Loading « {} »".format(self.name)) 49 print("Loading « {} »".format(self.name))
50 db_gain = gain(self.volume_factor * 100) 50 db_gain = gain(self.volume_factor * 100)
51 self.audio_segment = pydub.AudioSegment.from_file(self.filename).set_frame_rate(44100).set_channels(2).set_sample_width(2).apply_gain(db_gain) 51 self.audio_segment = pydub.AudioSegment.from_file(self.filename).set_frame_rate(Config.frame_rate).set_channels(Config.channels).set_sample_width(Config.sample_width).apply_gain(db_gain)
52 self.audio_segment_frame_width = self.audio_segment.frame_width 52 self.audio_segment_frame_width = self.audio_segment.frame_width
53 self.sound_duration = self.audio_segment.duration_seconds 53 self.sound_duration = self.audio_segment.duration_seconds
54 except Exception as e: 54 except Exception as e:
@@ -121,6 +121,7 @@ class MusicFile(Machine):
121 data += new_data 121 data += new_data
122 nb_frames += new_nb_frames 122 nb_frames += new_nb_frames
123 elif nb_frames == 0: 123 elif nb_frames == 0:
124 # FIXME: too slow
124 threading.Thread(name = "MSFinishedCallback", target=self.finished_callback).start() 125 threading.Thread(name = "MSFinishedCallback", target=self.finished_callback).start()
125 126
126 return data.ljust(out_data_length, b'\0') 127 return data.ljust(out_data_length, b'\0')