import sounddevice as sd
class Config:
- def __init__(self, **kwargs):
- for arg in kwargs:
- setattr(self, arg, kwargs[arg])
-
-config = Config(yml_file="config.yml")
+ pass
def path():
if getattr(sys, 'frozen', False):
sys.argv.extend(kivy_args)
- parser = argparse.ArgumentParser(description="A Music Sampler application.")
+ parser = argparse.ArgumentParser(
+ description="A Music Sampler application.",
+ formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser.add_argument("-c", "--config",
default="config.yml",
required=False,
help="Config file to load")
+ parser.add_argument("-l", "--latency",
+ default="high",
+ required=False,
+ help="Latency: low, high or number of seconds")
+ parser.add_argument("-b", "--blocksize",
+ default=0,
+ type=int,
+ required=False,
+ help="Blocksize: If not 0, the numbe of frames to take at each step for the mixer")
+ parser.add_argument("-f", "--frame-rate",
+ default=44100,
+ type=int,
+ required=False,
+ help="Frame rate to play the musics")
+ parser.add_argument("-x", "--channels",
+ default=2,
+ type=int,
+ required=False,
+ help="Number of channels to use")
+ parser.add_argument("-s", "--sample-width",
+ default=2,
+ type=int,
+ required=False,
+ help="Sample width (number of bytes for each frame)")
parser.add_argument("-V", "--version",
action="version",
help="Displays the current version and exits. Only use in bundled package",
help="Kivy arguments. All arguments after this are interpreted by Kivy. Pass \"-- --help\" to get Kivy's usage.")
args = parser.parse_args(argv)
- config.yml_file = args.config
+ Config.yml_file = args.config
+ Config.latency = args.latency
+ Config.blocksize = args.blocksize
+ Config.frame_rate = args.frame_rate
+ Config.channels = args.channels
+ Config.sample_width = args.sample_width
class SelectDeviceAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
else:
return "option '-v' can only be used in bundled package"
-def yml_file():
- return config.yml_file
-
def duration_to_min_sec(duration):
minutes = int(duration / 60)
seconds = int(duration) % 60
from .music_file import *
from .mixer import Mixer
-from . import yml_file,gain
+from . import Config, gain
class Mapping(RelativeLayout):
expected_keys = NumericProperty(0)
ready_color = ListProperty([1, 165/255, 0, 1])
def __init__(self, **kwargs):
+ self.mixer = Mixer()
self.key_config, self.open_files = self.parse_config()
super(Mapping, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
self.running = []
Clock.schedule_interval(self.not_all_keys_ready, 1)
- self.mixer = Mixer()
-
@property
def master_gain(self):
return gain(self.master_volume)
self.running.remove((key, start_time))
def parse_config(self):
- stream = open(yml_file(), "r")
+ stream = open(Config.yml_file, "r")
config = yaml.load(stream)
stream.close()
import audioop
import time
-frame_rate = 44100
-channels = 2
-sample_width = 2
+from . import Config
+
+sample_width = Config.sample_width
+def sample_width_to_dtype(sample_width):
+ if sample_width == 1 or sample_width == 2 or sample_width == 4:
+ return 'int' + str(8*sample_width)
+ else:
+ raise "Unknown sample width"
+
+def _latency(latency):
+ if latency == "high" or latency == "low":
+ return latency
+ else:
+ return float(latency)
class Mixer:
def __init__(self):
- self.stream = sd.RawOutputStream(samplerate=frame_rate,
- channels=channels,
- dtype='int' + str(8*sample_width), # FIXME: ?
- latency="high",
- blocksize=5000,
+ self.stream = sd.RawOutputStream(samplerate=Config.frame_rate,
+ channels=Config.channels,
+ dtype=sample_width_to_dtype(Config.sample_width),
+ latency=_latency(Config.latency),
+ blocksize=Config.blocksize,
callback=self.play_callback,
)
self.open_files = []
import os.path
from .lock import Lock
-from . import gain
+from . import Config, gain
file_lock = Lock("file")
try:
print("Loading « {} »".format(self.name))
db_gain = gain(self.volume_factor * 100)
- self.audio_segment = pydub.AudioSegment.from_file(self.filename).set_frame_rate(44100).set_channels(2).set_sample_width(2).apply_gain(db_gain)
+ 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)
self.audio_segment_frame_width = self.audio_segment.frame_width
self.sound_duration = self.audio_segment.duration_seconds
except Exception as e:
data += new_data
nb_frames += new_nb_frames
elif nb_frames == 0:
+ # FIXME: too slow
threading.Thread(name = "MSFinishedCallback", target=self.finished_callback).start()
return data.ljust(out_data_length, b'\0')