def convert_sample_freq(self, sample_id, target_freq): # Get current data and format info cur_handle = self._get_sample_data_handle(sample_id, convert_to_float=True) channels = cur_handle.get_channels() cur_freq = cur_handle.get_audio_rate() cur_bits, cur_is_float = self.get_sample_format(sample_id) # original format ratio = target_freq / cur_freq # Get converted audio data src = SampleRate(SRC_SINC_BEST_QUALITY, channels) src.set_ratio(ratio) src.add_input_data(*cur_handle.read()) new_data = src.get_output_data() new_length = len(new_data[0]) # Write new sample new_handle = WavPackWMem(target_freq, channels, cur_is_float, cur_bits) if not cur_is_float: to_max = 2**(cur_bits - 1) - 1 to_min = -to_max - 1 mult = to_max for ch in new_data: for i in range(len(ch)): ch[i] = min(max(to_min, int(ch[i] * mult)), to_max) new_handle.write(*new_data) raw_data = new_handle.get_contents() sample_data_key = self._get_full_sample_key(sample_id, 'p_sample.wv') new_header = self._get_sample_header(sample_id) new_header['freq'] = target_freq # Adjust loop bounds if new_length == 0: if 'loop_mode' in new_header: new_header['loop_mode'] = 'off' else: if 'loop_start' in new_header: target_start = int(round(new_header['loop_start'] * ratio)) new_header['loop_start'] = min(max(0, target_start), new_length - 1) if 'loop_end' in new_header: cur_loop_start = new_header.get('loop_start', 0) target_end = int(round(new_header['loop_end'] * ratio)) new_header['loop_end'] = min(max( cur_loop_start + 1, target_end), new_length) sample_header_key = self._get_full_sample_key(sample_id, 'p_sh_sample.json') transaction = {} transaction[sample_header_key] = new_header transaction[sample_data_key] = raw_data self._store.put(transaction)
def get_task_post_loop_cut(self, sample_id, on_complete): # Get sample info header = self._get_sample_header(sample_id) assert header['loop_mode'] != 'off' assert header['loop_end'] > 0 loop_end = header['loop_end'] cur_handle = self._get_sample_data_handle(sample_id, convert_to_float=False) channels = cur_handle.get_channels() sample_length = cur_handle.get_length() use_float = cur_handle.is_float() bits = cur_handle.get_bits() assert loop_end < sample_length msg_fmt = 'Cutting sample data past loop end...' self._session.set_progress_description(msg_fmt) self._session.set_progress_position(0) self._updater.signal_update('signal_progress_start') yield # Copy sample data until loop end new_handle = WavPackWMem(cur_handle.get_audio_rate(), channels, use_float, bits) frames_left = loop_end cur_data = cur_handle.read(min(frames_left, 4096)) while cur_data[0]: self._session.set_progress_position( min(1, (loop_end - frames_left) / loop_end)) self._updater.signal_update('signal_progress_step') yield if (not use_float) and (bits < 32): shift = 32 - bits for ch_num, ch in enumerate(cur_data): for i in range(len(ch)): ch[i] >>= shift new_handle.write(*cur_data) frames_left -= len(cur_data[0]) cur_data = cur_handle.read(min(frames_left, 4096)) self._session.set_progress_position(1) raw_data = new_handle.get_contents() sample_data_key = self._get_full_sample_key(sample_id, 'p_sample.wv') transaction = { sample_data_key: raw_data } def notifier(progress): if progress == 1: self._updater.signal_update('signal_progress_finished') on_complete() self._store.put(transaction, transaction_notifier=notifier)
def _get_transaction_import_sample(self, sample_id, path): freq = 48000 if path.endswith('.wv'): with open(path, 'rb') as f: sample_data = f.read() validator = WavPackValidator(sample_data) if not validator.is_data_valid(): raise SampleImportError('Could not import {}:\n{}'.format( path, validator.get_validation_error())) del validator wp = WavPackRMem(sample_data) freq = wp.get_audio_rate() else: try: sf = SndFileR(path, convert_to_float=False) sdata = list(sf.read()) except SndFileError as e: raise SampleImportError('Could not import {}:\n{}'.format(path, str(e))) freq = sf.get_audio_rate() if sf.get_bits() < 32: rshift = 32 - sf.get_bits() for buf in sdata: for i in range(len(buf)): buf[i] >>= rshift wv = WavPackWMem( sf.get_audio_rate(), sf.get_channels(), sf.is_float(), sf.get_bits()) wv.write(*sdata) sample_data = wv.get_contents() format_exts = ('.wv', '.wav', '.au', '.flac') name = os.path.basename(path) if name.endswith(format_exts): name = name[:name.rfind('.')] sample_data_key = self._get_full_sample_key(sample_id, 'p_sample.wv') sample_header_key = self._get_full_sample_key(sample_id, 'p_sh_sample.json') sample_name_key = self._get_full_sample_key(sample_id, 'm_name.json') header = { 'format': 'WavPack', 'freq': freq, } transaction = {} transaction[sample_data_key] = sample_data transaction[sample_header_key] = header transaction[sample_name_key] = name return transaction
def get_task_create_xfade_loop_region(self, sample_id, xfade_length, on_complete): # Get sample info header = self._get_sample_header(sample_id) assert header['loop_mode'] == 'uni' loop_start = header['loop_start'] loop_end = header['loop_end'] loop_length = loop_end - loop_start assert xfade_length > 0 assert xfade_length <= loop_length assert xfade_length <= loop_start cur_handle = self._get_sample_data_handle(sample_id, convert_to_float=False) channels = cur_handle.get_channels() sample_length = cur_handle.get_length() use_float = cur_handle.is_float() bits = cur_handle.get_bits() msg_fmt = 'Creating looping region...' self._session.set_progress_description(msg_fmt) self._session.set_progress_position(0) self._updater.signal_update('signal_progress_start') yield # Set up progress update helper step_count = 0 total_step_count = 4 if not use_float: total_step_count = 5 def add_step(): nonlocal step_count step_count += 1 self._session.set_progress_position(min(1, step_count / total_step_count)) self._updater.signal_update('signal_progress_step') yield # Get all sample data orig_data = cur_handle.read() yield from add_step() # Make copies of relevant sections init_length = loop_end - xfade_length init_data = [d[:init_length] for d in orig_data] fadeout_data = [d[init_length:loop_end] for d in orig_data] fadein_data = [d[loop_start - xfade_length:loop_start] for d in orig_data] trail_data = [d[loop_start:] for d in orig_data] assert len(fadeout_data[0]) == len(fadein_data[0]) yield from add_step() # Create crossfaded section xfade_data = [[] for _ in orig_data] for ch in range(channels): fadein_ch = fadein_data[ch] fadeout_ch = fadeout_data[ch] for i, (in_item, out_item) in enumerate(zip(fadein_ch, fadeout_ch)): t = i / xfade_length diff = in_item - out_item xfade_item = out_item + t * diff xfade_data[ch].append(xfade_item) yield from add_step() # Scale integer contents if not use_float: shift = 32 - bits if shift > 0: for init_ch in init_data: for i in range(len(init_ch)): init_ch[i] >>= shift for trail_ch in trail_data: for i in range(len(trail_ch)): trail_ch[i] >>= shift val_max = 2**(bits - 1) - 1 val_min = -val_max - 1 for xfade_ch in xfade_data: for i in range(len(xfade_ch)): shifted = int(xfade_ch[i]) >> shift xfade_ch[i] = min(max(val_min, shifted), val_max) yield from add_step() # Write new sections new_handle = WavPackWMem(cur_handle.get_audio_rate(), channels, use_float, bits) new_handle.write(*init_data) new_handle.write(*xfade_data) new_handle.write(*trail_data) yield from add_step() raw_data = new_handle.get_contents() sample_data_key = self._get_full_sample_key(sample_id, 'p_sample.wv') transaction = { sample_data_key: raw_data } def notifier(progress): if progress == 1: self._updater.signal_update('signal_progress_finished') on_complete() self._store.put(transaction, transaction_notifier=notifier)
def get_task_convert_sample_format( self, sample_id, bits, use_float, normalise, on_complete): # Get current format parameters cur_handle = self._get_sample_data_handle(sample_id, convert_to_float=False) channels = cur_handle.get_channels() freq = cur_handle.get_audio_rate() cur_bits = cur_handle.get_bits() cur_is_float = cur_handle.is_float() sample_length = cur_handle.get_length() self._session.set_progress_description('Converting sample format...') self._session.set_progress_position(0) self._updater.signal_update('signal_progress_start') yield # Read sample data data = [[] for _ in range(channels)] chunk = cur_handle.read() while len(chunk[0]) > 0: for d, buf in zip(data, chunk): d.extend(buf) chunk = cur_handle.read() # Get conversion ratio and bounds from_max = 1 if cur_is_float else (2**31 - 1) to_max = 1 if use_float else (2**(bits - 1) - 1) to_min = -1 if use_float else (-to_max - 1) mult = to_max / from_max transaction = {} if normalise: # Normalise max_abs = 0 for ch_num, ch in enumerate(data): for i, item in enumerate(ch): if (i & 0x3fff) == 0: self._session.set_progress_position( ((ch_num + i / sample_length) / channels) * 0.5) self._updater.signal_update('signal_progress_step') yield max_abs = max(max_abs, abs(item)) norm_mult = from_max / max_abs if (norm_mult >= 1.01) or (norm_mult <= 0.99999): mult *= norm_mult # Adjust sample volume levels in note and hit maps shift_dB = -math.log(norm_mult, 2) * 6 sample_num = self._get_sample_num(sample_id) note_map = self._get_note_map() for _, random_list in note_map: for i, item in enumerate(random_list): if item[0] == sample_num: item[2] += shift_dB transaction[self._get_conf_key('p_nm_note_map.json')] = note_map hit_map = self._get_hit_map() for _, random_list in hit_map: for i, item in enumerate(random_list): if item[0] == sample_num: item[2] += shift_dB transaction[self._get_conf_key('p_hm_hit_map.json')] = hit_map prog_phase_count = 2 if normalise else 1 prog_start = prog_phase_count - 1 self._session.set_progress_position(prog_start / prog_phase_count) # Write converted output new_handle = WavPackWMem(freq, channels, use_float, bits) if use_float: for ch_num, ch in enumerate(data): for i in range(len(ch)): if (i & 0x3fff) == 0: self._session.set_progress_position( (prog_start + ((ch_num + i / sample_length) / channels)) / prog_phase_count) self._updater.signal_update('signal_progress_step') yield ch[i] *= mult else: for ch_num, ch in enumerate(data): for i in range(len(ch)): if (i & 0x3fff) == 0: self._session.set_progress_position( (prog_start + ((ch_num + i / sample_length) / channels)) / prog_phase_count) self._updater.signal_update('signal_progress_step') yield ch[i] = min(max(to_min, int(ch[i] * mult)), to_max) new_handle.write(*data) raw_data = new_handle.get_contents() sample_data_key = self._get_full_sample_key(sample_id, 'p_sample.wv') transaction[sample_data_key] = raw_data def notifier(progress): if progress == 1: self._updater.signal_update('signal_progress_finished') on_complete() self._store.put(transaction, transaction_notifier=notifier)
def get_task_convert_sample_freq(self, sample_id, target_freq, on_complete): # Get current data and format info cur_handle = self._get_sample_data_handle(sample_id, convert_to_float=True) channels = cur_handle.get_channels() cur_freq = cur_handle.get_audio_rate() cur_bits, cur_is_float = self.get_sample_format(sample_id) # original format ratio = target_freq / cur_freq # Get converted audio data src = SampleRate(SRC_SINC_BEST_QUALITY, channels) src.set_ratio(ratio) self._session.set_progress_description('Resampling...') self._session.set_progress_position(0) self._updater.signal_update('signal_progress_start') est_length = int(cur_handle.get_length() * ratio) new_data = [[] for _ in range(channels)] cur_data = cur_handle.read(4096) while cur_data[0]: self._session.set_progress_position(min(1, len(new_data[0]) / est_length)) self._updater.signal_update('signal_progress_step') yield next_data = cur_handle.read(4096) src.add_input_data(*cur_data, end_of_input=not bool(next_data[0])) resampled_chunk = src.get_output_data() for ch in range(channels): new_data[ch].extend(resampled_chunk[ch]) cur_data = next_data new_length = len(new_data[0]) self._session.set_progress_position(1) # Write new sample new_handle = WavPackWMem(target_freq, channels, cur_is_float, cur_bits) if not cur_is_float: to_max = 2**(cur_bits - 1) - 1 to_min = -to_max - 1 mult = to_max for ch in new_data: for i in range(len(ch)): ch[i] = min(max(to_min, int(ch[i] * mult)), to_max) new_handle.write(*new_data) raw_data = new_handle.get_contents() sample_data_key = self._get_full_sample_key(sample_id, 'p_sample.wv') new_header = self._get_sample_header(sample_id) new_header['freq'] = target_freq # Adjust loop bounds if new_length == 0: if 'loop_mode' in new_header: new_header['loop_mode'] = 'off' else: if 'loop_start' in new_header: target_start = int(round(new_header['loop_start'] * ratio)) new_header['loop_start'] = min(max(0, target_start), new_length - 1) if 'loop_end' in new_header: cur_loop_start = new_header.get('loop_start', 0) target_end = int(round(new_header['loop_end'] * ratio)) new_header['loop_end'] = min(max( cur_loop_start + 1, target_end), new_length) sample_header_key = self._get_full_sample_key(sample_id, 'p_sh_sample.json') transaction = {} transaction[sample_header_key] = new_header transaction[sample_data_key] = raw_data def notifier(progress): if progress == 1: self._updater.signal_update('signal_progress_finished') on_complete() self._store.put(transaction, transaction_notifier=notifier)
def convert_sample_format(self, sample_id, bits, use_float, normalise): # Get current format parameters cur_handle = self._get_sample_data_handle(sample_id, convert_to_float=False) channels = cur_handle.get_channels() freq = cur_handle.get_audio_rate() cur_bits = cur_handle.get_bits() cur_is_float = cur_handle.is_float() # Read sample data data = [[] for _ in range(channels)] chunk = cur_handle.read() while chunk[0]: for d, buf in zip(data, chunk): d.extend(buf) chunk = cur_handle.read() # Get conversion ratio and bounds from_max = 1 if cur_is_float else (2**31 - 1) to_max = 1 if use_float else (2**(bits - 1) - 1) to_min = -1 if use_float else (-to_max - 1) mult = to_max / from_max transaction = {} if normalise: # Normalise max_abs = 0 for ch in data: for item in ch: max_abs = max(max_abs, abs(item)) norm_mult = from_max / max_abs if norm_mult >= 1.01: mult *= norm_mult # Adjust sample volume levels in note and hit maps shift_dB = -math.log(norm_mult, 2) * 6 sample_num = self._get_sample_num(sample_id) note_map = self._get_note_map() for _, random_list in note_map: for i, item in enumerate(random_list): if item[0] == sample_num: item[2] += shift_dB transaction[self._get_conf_key('p_nm_note_map.json')] = note_map hit_map = self._get_hit_map() for _, random_list in hit_map: for i, item in enumerate(random_list): if item[0] == sample_num: item[2] += shift_dB transaction[self._get_conf_key('p_hm_hit_map.json')] = hit_map # Write converted output new_handle = WavPackWMem(freq, channels, use_float, bits) if use_float: for ch in data: for i in range(len(ch)): ch[i] *= mult else: for ch in data: for i in range(len(ch)): ch[i] = min(max(to_min, int(ch[i] * mult)), to_max) new_handle.write(*data) raw_data = new_handle.get_contents() sample_data_key = self._get_full_sample_key(sample_id, 'p_sample.wv') transaction[sample_data_key] = raw_data self._store.put(transaction)
def get_task_create_xfade_loop_region(self, sample_id, xfade_length, on_complete): free_sample_ids = self.get_free_sample_ids() if not free_sample_ids: raise RuntimeError('No free sample slots left') new_sample_id = free_sample_ids[0] # Get sample info header = self._get_sample_header(sample_id) assert header['loop_mode'] == 'uni' loop_start = header['loop_start'] loop_end = header['loop_end'] loop_length = loop_end - loop_start assert xfade_length > 0 assert xfade_length <= loop_length assert xfade_length <= loop_start cur_handle = self._get_sample_data_handle(sample_id, convert_to_float=False) channels = cur_handle.get_channels() sample_length = cur_handle.get_length() use_float = cur_handle.is_float() bits = cur_handle.get_bits() msg_fmt = 'Creating looping region...' self._session.set_progress_description(msg_fmt) self._session.set_progress_position(0) self._updater.signal_update('signal_progress_start') yield # Set up progress update helper step_count = 0 total_step_count = 4 if not use_float: total_step_count = 5 def add_step(): nonlocal step_count step_count += 1 self._session.set_progress_position(min(1, step_count / total_step_count)) self._updater.signal_update('signal_progress_step') yield # Get all sample data orig_data = cur_handle.read() yield from add_step() # Make copies of relevant sections init_length = loop_end - xfade_length init_data = [d[:init_length] for d in orig_data] fadeout_data = [d[init_length:loop_end] for d in orig_data] fadein_data = [d[loop_start - xfade_length:loop_start] for d in orig_data] trail_data = [d[loop_start:] for d in orig_data] assert len(fadeout_data[0]) == len(fadein_data[0]) yield from add_step() # Create crossfaded section xfade_data = [[] for _ in orig_data] for ch in range(channels): fadein_ch = fadein_data[ch] fadeout_ch = fadeout_data[ch] for i, (in_item, out_item) in enumerate(zip(fadein_ch, fadeout_ch)): t = i / xfade_length diff = in_item - out_item xfade_item = out_item + t * diff xfade_data[ch].append(xfade_item) yield from add_step() # Scale integer contents if not use_float: shift = 32 - bits if shift > 0: for init_ch in init_data: for i in range(len(init_ch)): init_ch[i] >>= shift for trail_ch in trail_data: for i in range(len(trail_ch)): trail_ch[i] >>= shift val_max = 2**(bits - 1) - 1 val_min = -val_max - 1 for xfade_ch in xfade_data: for i in range(len(xfade_ch)): shifted = int(xfade_ch[i]) >> shift xfade_ch[i] = min(max(val_min, shifted), val_max) yield from add_step() # Write new sections new_handle = WavPackWMem(cur_handle.get_audio_rate(), channels, use_float, bits) new_handle.write(*init_data) new_handle.write(*xfade_data) new_handle.write(*trail_data) yield from add_step() new_name_key = self._get_full_sample_key(new_sample_id, 'm_name.json') new_name = self.get_sample_name(sample_id) + ' – xfade' new_header = deepcopy(header) new_header_key = self._get_full_sample_key(new_sample_id, 'p_sh_sample.json') raw_data = new_handle.get_contents() sample_data_key = self._get_full_sample_key(new_sample_id, 'p_sample.wv') transaction = { new_name_key: new_name, new_header_key: new_header, sample_data_key: raw_data, } def notifier(progress): if progress == 1: self._updater.signal_update('signal_progress_finished') on_complete() self._store.put(transaction, transaction_notifier=notifier)