From 9cf932f7021395452c665346116d9db0228d9d5d Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Sat, 12 Oct 2024 21:58:15 +0200 Subject: [PATCH 01/18] Update music.py Changed ADSR Envelope Class removed unused Note Class --- src/music.py | 118 +++++++++++++++++++++++++-------------------------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/src/music.py b/src/music.py index 645d1cc..f2a8cd7 100644 --- a/src/music.py +++ b/src/music.py @@ -314,66 +314,6 @@ def apply_distortion(audio, gain=2.0, threshold=0.5): return distorted_audio -class ADSR(): - def __init__(self, attack_time, decay_time, sustain_level, release_time, sample_rate): - self.attack_samples = int(attack_time * sample_rate) - self.decay_samples = int(decay_time * sample_rate) - self.sustain_level = sustain_level - self.release_samples = int(release_time * sample_rate) - self.sample_rate = sample_rate - - def get_ads_envelope(self, start_frame, num_frames): - envelope = np.zeros(num_frames) - end_frame = start_frame + num_frames - - # Attack phase - if start_frame < self.attack_samples: - attack_end = min(end_frame, self.attack_samples) - envelope[:attack_end - - start_frame] = np.linspace(0, 1, attack_end - start_frame) - start_frame = attack_end - - # Decay phase - if start_frame < self.attack_samples + self.decay_samples: - decay_end = min(end_frame, self.attack_samples + - self.decay_samples) - envelope[start_frame - self.attack_samples:decay_end - - self.attack_samples] = np.linspace(1, self.sustain_level, decay_end - start_frame)[start_frame - self.attack_samples:decay_end - - self.attack_samples] - start_frame = decay_end - - # Sustain phase - if start_frame >= self.attack_samples + self.decay_samples: - sustain_start = max( - start_frame, self.attack_samples + self.decay_samples) - envelope[sustain_start - start_frame:] = self.sustain_level - - return envelope - - def get_r_envelope(self, start_frame, num_frames): - envelope = np.zeros(num_frames) - end_frame = start_frame + num_frames - - # Release phase - if start_frame < self.release_samples: - release_end = min(end_frame, self.release_samples) - envelope[:release_end - start_frame] = np.linspace( - self.sustain_level, 0, release_end - start_frame) - - return envelope - - -class Note: - def __init__(self, amplitude): - self.amplitude = amplitude - self.on = True - self.adsr_state = 'attack' - self.adsr_position = 0 - - def __str__(self): - return f"Note({self.amplitude}, {self.on}, {self.adsr_position}, {self.adsr_state})" - - def get_on_notes(notes): return {note: note_data for note, note_data in notes.items() if note_data.on} @@ -394,6 +334,64 @@ def piano_id(): return device_id +class ADSR: + def __init__(self, attack_time, decay_time, sustain_level, release_time, sample_rate): + self.attack_samples = int(attack_time * sample_rate) + self.decay_samples = int(decay_time * sample_rate) + self.ad_samples = self.attack_samples + self.decay_samples + self.sustain_level = sustain_level + self.release_samples = int(release_time * sample_rate) + + self.ads_envelope = np.concatenate(( + np.linspace(0, 1, self.attack_samples), + np.linspace(1, self.sustain_level, self.decay_samples) + )) + self.r_envelope = np.linspace(self.sustain_level, 0, self.release_samples) + + self._r_counter = [0 for _ in range(128)] + self._ads_counter = [0 for _ in range(128)] + + def reset_note(self, note_num): + self._ads_counter[note_num] = 0 + self._r_counter[note_num] = 0 + + def has_note_ended(self, note_num) -> bool: + return self._r_counter[note_num]>=self.release_samples + + def get_ads_envelope(self, note_num, frame): + start = self._ads_counter[note_num] + end = start + frame + self._ads_counter[note_num] += frame + + if start > self.ad_samples: + return np.ones(frame) * self.sustain_level + + envelope = np.zeros(frame) + if end > self.ad_samples: + envelope[:self.ad_samples - start] = self.ads_envelope[start:self.ad_samples] + envelope[self.ad_samples:] = np.zeros(end - self.ad_samples) + else: + envelope[:] = self.ads_envelope[start:end] + + return envelope + + def get_r_envelope(self, note_num, frame): + start = self._r_counter[note_num] + end = start + frame + self._r_counter[note_num] += frame + + if start > self.release_samples: + return np.zeros(frame) + + envelope = np.zeros(frame) + if end <= self.release_samples: + envelope[:] = self.r_envelope[start:end] + else: + envelope[:self.release_samples - start] = self.r_envelope[start:self.release_samples] + envelope[self.release_samples - start:] = 0 # After release, the envelope is 0 + return envelope + + class Synth2(): def __init__(self, fourier_nn, stdout: Queue = None, port_name=None): self.stdout = stdout From bcdf92a584ba360629f44f046984e350e6a065d9 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Sun, 13 Oct 2024 14:32:59 +0200 Subject: [PATCH 02/18] added ADSR Envelope --- main.py | 6 +- src/music.py | 290 +++++++-------------------------------------------- 2 files changed, 41 insertions(+), 255 deletions(-) diff --git a/main.py b/main.py index 8188263..d5ee213 100644 --- a/main.py +++ b/main.py @@ -519,9 +519,9 @@ def main(): window.protocol("WM_DELETE_WINDOW", window.quit) state = "running" try: - # window.after(1000, lambda: window.graph.plot_function( - # predefined_functions_dict['nice'], overwrite=True)) - # window.after(2000, window.start_training) + window.after(1000, lambda: window.graph.plot_function( + predefined_functions_dict['nice'], overwrite=True)) + window.after(2000, window.start_training) window.mainloop() except KeyboardInterrupt: print("exiting via keybord interupt") diff --git a/src/music.py b/src/music.py index f2a8cd7..9a5c2dd 100644 --- a/src/music.py +++ b/src/music.py @@ -1,18 +1,10 @@ -import copy -import threading -import time -from typing import Callable import mido -import pygame import scipy import torch from src.fourier_neural_network import FourierNN from src import utils -from pygame import mixer, midi, sndarray import atexit -import multiprocessing from multiprocessing import Process, Queue, current_process -import os import sys from tkinter import filedialog import numpy as np @@ -40,7 +32,7 @@ def musik_from_file(fourier_nn: FourierNN): print(note_a) duration = note_a.end - note_a.start synthesized_note = fourier_nn.synthesize( - midi_note=note_a.pitch-12, duration=duration, sample_rate=44100) + midi_note=note_a.pitch-12, duration=duration, sample_rate=44100) print(synthesized_note.shape) note_list.append(synthesized_note) @@ -72,206 +64,6 @@ def rescale_audio(audio): return audio return audio / max_val - -class Synth(): - - MIDI_NOTE_OF_FREQ_ONE = midi.frequency_to_midi(1) - - def __init__(self, fourier_nn, stdout: Queue = None, num_channels: int = 20): - self.stdout = stdout - self.pool = None - self.live_synth: Process = None - self.notes_ready = False - self.fourier_nn: FourierNN = fourier_nn - self.fs = 44100 # Sample rate - self.num_channels = num_channels - self.notes: dict = {} - self.effects: list[Callable] = [ - # apply_reverb, - # apply_echo, - # apply_chorus, - # apply_distortion, - ] - # pygame.init() - mixer.init(frequency=44100, size=-16, - channels=2, buffer=1024) - mixer.set_num_channels(self.num_channels) - - self.running_channels: dict[str, tuple[int, mixer.Channel]] = {} - self.free_channel_ids = list(range( - self.num_channels)) - # self.generate_sounds() - - def generate_sound_wrapper(self, x, offset): - midi_note, data = self.fourier_nn.synthesize_tuple(x) - return midi_note+offset, data - - def generate_sounds(self): - self.notes_ready = False - - timestep = 44100 - - t = np.arange(0, 1, step=1 / timestep) - - data = self.fourier_nn.predict((2 * np.pi*t)-np.pi) - - peak_frequency = utils.calculate_peak_frequency(data) - - print("peak_frequency", peak_frequency) - - midi_offset = midi.frequency_to_midi(peak_frequency) \ - - self.MIDI_NOTE_OF_FREQ_ONE - print("Midi Note offset:", midi_offset) - self.pool = multiprocessing.Pool(processes=os.cpu_count()) - atexit.register(self.pool.terminate) - atexit.register(self.pool.join) - result_async = self.pool.starmap_async(self.generate_sound_wrapper, - ((x-midi_offset, midi_offset) for x in range(128))) - utils.run_after_ms(1000, self.monitor_note_generation, result_async) - - def monitor_note_generation(self, result_async): - try: - self.note_list = result_async.get(0.1) - except multiprocessing.TimeoutError: - utils.run_after_ms( - 1000, self.monitor_note_generation, result_async) - else: - print("sounds Generated") - - self.notes_ready = True - self.play_init_sound() - self.pool.close() - self.pool.join() - atexit.unregister(self.pool.terminate) - atexit.unregister(self.pool.join) - - def play_init_sound(self): - f1 = 440 # Frequency of the "duuu" sound (in Hz) - f2 = 880 # Frequency of the "dib" sound (in Hz) - t1 = 0.8 # Duration of the "duuu" sound (in seconds) - t2 = 0.2 # Duration of the "dib" sound (in seconds) - t = np.arange(int(t1 * self.fs)) / self.fs - sound1 = 0.5 * np.sin(2 * np.pi * f1 * t) - - # Generate the "dib" sound - t = np.arange(int(t2 * self.fs)) / self.fs - sound2 = 0.5 * np.sin(2 * np.pi * f2 * t) - - # Concatenate the two sounds - audio = np.concatenate([sound1, sound2]) - output = np.array( - audio * 32767 / np.max(np.abs(audio)) / 2).astype(np.int16) - stereo_sine_wave = np.repeat(output.reshape(-1, 1), 2, axis=1) - sound = sndarray.make_sound(stereo_sine_wave) - - channel = mixer.Channel(0) - channel.play(sound) - while (channel.get_busy()): - pass - print("Ready") - - def apply_effects(self, sound): - for effect in self.effects: - print(effect.__name__) - sound[:] = effect(sound) - sound = sound-np.mean(sound) - sound[:] = rescale_audio(sound) - return sound - - def live_synth_loop(self): - midi.init() - mixer.init(frequency=44100, size=-16, - channels=2, buffer=1024) - mixer.set_num_channels(self.num_channels) - for note, sound in self.note_list: - # print(sound.shape) - stereo = np.repeat(rescale_audio(sound).reshape(-1, 1), 2, axis=1) - stereo = np.array(stereo, dtype=np.int16) - # np.savetxt(f"tmp/numpy/sound_note_{note}.numpy", stereo) - stereo_sound = pygame.sndarray.make_sound(stereo) - self.notes[note] = stereo_sound - - input_id = midi.get_default_input_id() - if input_id == -1: - print("No MIDI input device found.") - return - - midi_input = midi.Input(input_id) - print("Live Synth is running") - while True: - if midi_input.poll(): - midi_events = midi_input.read(10) - for midi_event, timestamp in midi_events: - if midi_event[0] == 144: - print("Note on", midi_event[1]) - try: - id = self.free_channel_ids.pop() - channel = mixer.Channel(id) - channel.set_volume(1) - channel.play( - self.notes[midi_event[1]], fade_ms=10, loops=-1) - self.running_channels[midi_event[1]] = ( - id, channel,) - except IndexError: - print("to many sounds playing") - elif midi_event[0] == 128: - print("Note off", midi_event[1]) - self.free_channel_ids.append( - self.running_channels[midi_event[1]][0]) - self.running_channels[midi_event[1]][1].stop() - - def pending_for_live_synth(self): - if not self.notes_ready: - # print("pending") - utils.run_after_ms(500, self.pending_for_live_synth) - else: - self.run_live_synth() - - def run_live_synth(self): - if not self.notes_ready: - print("\033[31;1;4mNOT READY YET\033[0m") - self.generate_sounds() - utils.run_after_ms(500, self.pending_for_live_synth) - return - if not self.live_synth: - print("spawning live synth") - self.live_synth = Process(target=self.live_synth_loop) - self.live_synth.start() - else: - print("killing live synth") - self.live_synth.terminate() - self.live_synth.join() - self.live_synth = None - print("live synth killed") - atexit.register(utils.DIE, self.live_synth, 0, 0) - - def play_sound(self, midi_note): - id = self.free_channel_ids.pop() - channel = mixer.Channel(id) - channel.play(self.notes[midi_note], 200) - - def __getstate__(self) -> object: - pool = self.pool - live_synth = self.live_synth - del self.pool - del self.live_synth - Synth_dict = self.__dict__.copy() - self.pool = pool - self.live_synth = live_synth - return Synth_dict - - def __setstate__(self, state): - # Load the model from a file after deserialization - self.__dict__.update(state) - if self.stdout is not None: - if current_process().name != 'MainProcess': - sys.stdout = utils.QueueSTD_OUT(queue=self.stdout) - - -def get_raw_audio(sound): - return pygame.sndarray.array(sound) - - def apply_reverb(audio, decay=0.5, delay=0.02, fs=44100): delay_samples = int(delay * fs) impulse_response = np.zeros((delay_samples, 2)) @@ -280,10 +72,9 @@ def apply_reverb(audio, decay=0.5, delay=0.02, fs=44100): reverb_audio = np.zeros_like(audio) for channel in range(audio.shape[1]): reverb_audio[:, channel] = scipy.signal.fftconvolve( - audio[:, channel], impulse_response[:, channel])[:len(audio)] + audio[:, channel], impulse_response[:, channel])[:len(audio)] return reverb_audio - def apply_echo(audio, delay=0.2, decay=0.5, fs=44100): delay_samples = int(delay * fs) echo_audio = np.zeros((len(audio) + delay_samples)) @@ -292,7 +83,6 @@ def apply_echo(audio, delay=0.2, decay=0.5, fs=44100): echo_audio = echo_audio[:len(audio)] return echo_audio - def apply_chorus(audio, rate=1.5, depth=0.02, fs=44100): t = np.arange(len(audio)) / fs mod = depth * np.sin(2 * np.pi * rate * t) @@ -306,7 +96,6 @@ def apply_chorus(audio, rate=1.5, depth=0.02, fs=44100): chorus_audio[i, channel] = audio[i, channel] return chorus_audio - def apply_distortion(audio, gain=2.0, threshold=0.5): distorted_audio = gain * audio distorted_audio[distorted_audio > threshold] = threshold @@ -314,26 +103,6 @@ def apply_distortion(audio, gain=2.0, threshold=0.5): return distorted_audio -def get_on_notes(notes): - return {note: note_data for note, note_data in notes.items() if note_data.on} - - -def get_off_notes(notes): - return {note: note_data for note, note_data in notes.items() if not note_data.on} - - -def piano_id(): - desired_name = "Digital Piano" - device_id = None - - for i in range(pygame.midi.get_count()): - info = pygame.midi.get_device_info(i) - if info[1].decode() == desired_name: - device_id = i - break - return device_id - - class ADSR: def __init__(self, attack_time, decay_time, sustain_level, release_time, sample_rate): self.attack_samples = int(attack_time * sample_rate) @@ -345,7 +114,7 @@ def __init__(self, attack_time, decay_time, sustain_level, release_time, sample_ self.ads_envelope = np.concatenate(( np.linspace(0, 1, self.attack_samples), np.linspace(1, self.sustain_level, self.decay_samples) - )) + )) self.r_envelope = np.linspace(self.sustain_level, 0, self.release_samples) self._r_counter = [0 for _ in range(128)] @@ -362,24 +131,24 @@ def get_ads_envelope(self, note_num, frame): start = self._ads_counter[note_num] end = start + frame self._ads_counter[note_num] += frame - + if start > self.ad_samples: return np.ones(frame) * self.sustain_level - + envelope = np.zeros(frame) if end > self.ad_samples: envelope[:self.ad_samples - start] = self.ads_envelope[start:self.ad_samples] - envelope[self.ad_samples:] = np.zeros(end - self.ad_samples) + envelope[self.ad_samples-start:] = np.ones(end - self.ad_samples)*self.sustain_level else: envelope[:] = self.ads_envelope[start:end] - + return envelope def get_r_envelope(self, note_num, frame): start = self._r_counter[note_num] end = start + frame self._r_counter[note_num] += frame - + if start > self.release_samples: return np.zeros(frame) @@ -391,7 +160,7 @@ def get_r_envelope(self, note_num, frame): envelope[self.release_samples - start:] = 0 # After release, the envelope is 0 return envelope - + class Synth2(): def __init__(self, fourier_nn, stdout: Queue = None, port_name=None): self.stdout = stdout @@ -402,13 +171,19 @@ def __init__(self, fourier_nn, stdout: Queue = None, port_name=None): self.max_parralel_notes = 3 self.current_frame = 0 t = np.array([ - midi.midi_to_frequency(f) * + utils.midi_to_freq(f) * np.linspace(0, 2*np.pi, self.fs) for f in range(128) - ]) + ]) self.t_buffer = torch.tensor(t, dtype=torch.float32) print(self.t_buffer.shape) self.port_name = port_name + self.adsr_envelope=ADSR( + 0.1, + 0.1, + 0.7, + 0.2, + self.fs) def set_port_name(self, port_name): self.port_name = port_name @@ -442,7 +217,7 @@ def play_init_sound(self): # Concatenate the sounds to form "duuudldiiidub" audio = np.concatenate([sound1, sound2, sound3, sound4]) output = np.array( - audio * 32767 / np.max(np.abs(audio)) / 2).astype(np.int16) + audio * 32767 / np.max(np.abs(audio)) / 2).astype(np.int16) sd.play(output, blocking=True) print("Ready") @@ -480,26 +255,37 @@ def live_synth_loop(self): if midi_event.type == 'note_on': # Note on print("Note on", midi_event.note, - midi.midi_to_frequency(midi_event.note)) + utils.midi_to_freq(midi_event.note)) - notes[midi_event.note] = midi_event.velocity + notes[midi_event.note] = [True, midi_event.velocity] + self.adsr_envelope.reset_note(midi_event.note) elif midi_event.type == 'note_off': # Note off print("Note off", midi_event.note, - midi.midi_to_frequency(midi_event.note)) + utils.midi_to_freq(midi_event.note)) if midi_event.note in notes: - del notes[midi_event.note] + #del notes[midi_event.note] + notes[midi_event.note][0]=False if len(notes) > 0: y = np.zeros((len(notes), available_buffer), dtype=np.float32) - for i, (note, amplitude) in enumerate(notes.items()): + to_delete=[] + for i, (note, data) in enumerate(notes.items()): with torch.no_grad(): x = utils.wrap_concat( - self.t_buffer[note], cycle_frame, cycle_frame + available_buffer).to(self.fourier_nn.device) - + self.t_buffer[note], cycle_frame, cycle_frame + available_buffer).to(self.fourier_nn.device) + if data[0]: + envelope=self.adsr_envelope.get_ads_envelope(note, available_buffer) + else: + envelope=self.adsr_envelope.get_r_envelope(note, available_buffer) + if self.adsr_envelope.has_note_ended(note): + to_delete.append(note) y[i, :] = model( - x.unsqueeze(1)).cpu().numpy().astype(np.float32) # * (amplitude/127) + x.unsqueeze(1)).cpu().numpy().astype(np.float32) * envelope # * (amplitude/127) + + for note in to_delete: + del notes[note] audio_data = sum_signals(y) # print(np.max(np.abs(audio_data))) @@ -597,7 +383,7 @@ def sum_signals_torch(signals): # Normalize each signal normalized_signals = torch.stack( - [sum_signals_torch(signal) for signal in signals]) + [sum_signals_torch(signal) for signal in signals]) # Sum the signals along dimension 0 summed_signal = torch.sum(normalized_signals, dim=0) From d3524a43d959ac864f387221a475a9a7c1e09071 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Sun, 13 Oct 2024 18:39:57 +0200 Subject: [PATCH 03/18] added pre_release workflow for my branch --- pre_release.yml | 64 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 pre_release.yml diff --git a/pre_release.yml b/pre_release.yml new file mode 100644 index 0000000..9f701a3 --- /dev/null +++ b/pre_release.yml @@ -0,0 +1,64 @@ +name: Daily Build + +on: + push: + branches: + - thetechnicker + +jobs: + build-linux: + runs-on: ubuntu-latest + strategy: + max-parallel: 5 + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.11 + uses: actions/setup-python@v3 + with: + python-version: "3.11" + + - name: Add conda to system path + run: | + echo $CONDA/bin >> $GITHUB_PATH + + - name: Install system dependencies + run: | + sudo apt-get update + sudo apt-get install -y portaudio19-dev + + - name: Install dependencies + run: | + conda env update --file environment.yml --name base + + - name: Build wheel + run: | + conda install wheel + python setup.py bdist_wheel + + - name: Get version + id: get_version + run: echo "VERSION=$(python setup.py --version)" >> $GITHUB_ENV + + - name: List contents of dist folder + run: | + ls -la dist/ + + - name: Upload wheel artifact + uses: actions/upload-artifact@v3 + with: + name: my-package + path: dist/*.whl + + - name: Create Release + id: create_release + uses: softprops/action-gh-release@v1 + with: + tag_name: "v${{ env.VERSION }}" + release_name: "Release v${{ env.VERSION }}" + draft: true + files: dist/*.whl + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + From 6ff8115327ed45d1af2047509bda02a1e6b7c151 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Sun, 13 Oct 2024 18:42:01 +0200 Subject: [PATCH 04/18] saved workflow in wrong folder --- pre_release.yml => .github/workflows/pre_release.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pre_release.yml => .github/workflows/pre_release.yml (100%) diff --git a/pre_release.yml b/.github/workflows/pre_release.yml similarity index 100% rename from pre_release.yml rename to .github/workflows/pre_release.yml From 95f19545386c3ecac6f18f01b0e2f494b9e7bda3 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Sun, 13 Oct 2024 18:43:06 +0200 Subject: [PATCH 05/18] renamed workflow --- .github/workflows/pre_release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pre_release.yml b/.github/workflows/pre_release.yml index 9f701a3..0a2dffc 100644 --- a/.github/workflows/pre_release.yml +++ b/.github/workflows/pre_release.yml @@ -1,4 +1,4 @@ -name: Daily Build +name: Pre Release on: push: From f0307a93c75a7fc6f88aff080e65af7e3a920107 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Sun, 13 Oct 2024 18:46:29 +0200 Subject: [PATCH 06/18] fixed workflow --- .github/workflows/pre_release.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pre_release.yml b/.github/workflows/pre_release.yml index 0a2dffc..040684a 100644 --- a/.github/workflows/pre_release.yml +++ b/.github/workflows/pre_release.yml @@ -56,8 +56,9 @@ jobs: uses: softprops/action-gh-release@v1 with: tag_name: "v${{ env.VERSION }}" - release_name: "Release v${{ env.VERSION }}" + name: "Release v${{ env.VERSION }}" draft: true + prerelease: true files: dist/*.whl env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From 6152fc5c2e40347f918d238ea47381c82345953f Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Sun, 13 Oct 2024 18:49:55 +0200 Subject: [PATCH 07/18] some more fixes --- .github/workflows/pre_release.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/pre_release.yml b/.github/workflows/pre_release.yml index 040684a..cb38687 100644 --- a/.github/workflows/pre_release.yml +++ b/.github/workflows/pre_release.yml @@ -46,20 +46,20 @@ jobs: ls -la dist/ - name: Upload wheel artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: my-package path: dist/*.whl - name: Create Release id: create_release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: tag_name: "v${{ env.VERSION }}" name: "Release v${{ env.VERSION }}" draft: true prerelease: true files: dist/*.whl - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + #env: + #GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From f0c24b1edb116ceb52f00cc3de19d27b2ff1b0fd Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Sun, 13 Oct 2024 18:55:36 +0200 Subject: [PATCH 08/18] workflow does not work --- .github/workflows/pre_release.yml | 65 ------------------------------- 1 file changed, 65 deletions(-) delete mode 100644 .github/workflows/pre_release.yml diff --git a/.github/workflows/pre_release.yml b/.github/workflows/pre_release.yml deleted file mode 100644 index cb38687..0000000 --- a/.github/workflows/pre_release.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Pre Release - -on: - push: - branches: - - thetechnicker - -jobs: - build-linux: - runs-on: ubuntu-latest - strategy: - max-parallel: 5 - - steps: - - uses: actions/checkout@v4 - - - name: Set up Python 3.11 - uses: actions/setup-python@v3 - with: - python-version: "3.11" - - - name: Add conda to system path - run: | - echo $CONDA/bin >> $GITHUB_PATH - - - name: Install system dependencies - run: | - sudo apt-get update - sudo apt-get install -y portaudio19-dev - - - name: Install dependencies - run: | - conda env update --file environment.yml --name base - - - name: Build wheel - run: | - conda install wheel - python setup.py bdist_wheel - - - name: Get version - id: get_version - run: echo "VERSION=$(python setup.py --version)" >> $GITHUB_ENV - - - name: List contents of dist folder - run: | - ls -la dist/ - - - name: Upload wheel artifact - uses: actions/upload-artifact@v4 - with: - name: my-package - path: dist/*.whl - - - name: Create Release - id: create_release - uses: softprops/action-gh-release@v2 - with: - tag_name: "v${{ env.VERSION }}" - name: "Release v${{ env.VERSION }}" - draft: true - prerelease: true - files: dist/*.whl - #env: - #GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - From c762576bad52c44953d881a2ad0f0b87a588319c Mon Sep 17 00:00:00 2001 From: Thetecknicker Date: Mon, 14 Oct 2024 09:21:29 +0200 Subject: [PATCH 09/18] removed useless code --- src/music.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/music.py b/src/music.py index 9a5c2dd..929c59b 100644 --- a/src/music.py +++ b/src/music.py @@ -247,11 +247,11 @@ def live_synth_loop(self): if available_buffer == 0: continue midi_event = midi_input.poll() - # print(midi_event) if midi_event: - midi_event.type - midi_event.note - midi_event.velocity + print(midi_event) + #midi_event.type + #midi_event.note + #midi_event.velocity if midi_event.type == 'note_on': # Note on print("Note on", midi_event.note, From 90f332da6b574d2340470a0b53389d4281ff92f2 Mon Sep 17 00:00:00 2001 From: Thetecknicker Date: Mon, 14 Oct 2024 09:41:40 +0200 Subject: [PATCH 10/18] small changes --- src/music.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/music.py b/src/music.py index 929c59b..59ee5fc 100644 --- a/src/music.py +++ b/src/music.py @@ -181,7 +181,7 @@ def __init__(self, fourier_nn, stdout: Queue = None, port_name=None): self.adsr_envelope=ADSR( 0.1, 0.1, - 0.7, + 0.75, 0.2, self.fs) From fb9e22738c6ab15ad051fdbab7e2d8a81a71c4a8 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Tue, 15 Oct 2024 19:19:36 +0200 Subject: [PATCH 11/18] added Echo --- main.py | 2 +- src/music.py | 131 +++++++++++++++++++++++++++++++++----------- src/std_redirect.py | 25 +++++---- src/utils.py | 27 ++++++++- 4 files changed, 139 insertions(+), 46 deletions(-) diff --git a/main.py b/main.py index d5ee213..301d2e2 100644 --- a/main.py +++ b/main.py @@ -520,7 +520,7 @@ def main(): state = "running" try: window.after(1000, lambda: window.graph.plot_function( - predefined_functions_dict['nice'], overwrite=True)) + predefined_functions_dict['funny2'], overwrite=True)) window.after(2000, window.start_training) window.mainloop() except KeyboardInterrupt: diff --git a/src/music.py b/src/music.py index 59ee5fc..cf95025 100644 --- a/src/music.py +++ b/src/music.py @@ -32,7 +32,7 @@ def musik_from_file(fourier_nn: FourierNN): print(note_a) duration = note_a.end - note_a.start synthesized_note = fourier_nn.synthesize( - midi_note=note_a.pitch-12, duration=duration, sample_rate=44100) + midi_note=note_a.pitch-12, duration=duration, sample_rate=44100) print(synthesized_note.shape) note_list.append(synthesized_note) @@ -64,6 +64,7 @@ def rescale_audio(audio): return audio return audio / max_val + def apply_reverb(audio, decay=0.5, delay=0.02, fs=44100): delay_samples = int(delay * fs) impulse_response = np.zeros((delay_samples, 2)) @@ -72,9 +73,10 @@ def apply_reverb(audio, decay=0.5, delay=0.02, fs=44100): reverb_audio = np.zeros_like(audio) for channel in range(audio.shape[1]): reverb_audio[:, channel] = scipy.signal.fftconvolve( - audio[:, channel], impulse_response[:, channel])[:len(audio)] + audio[:, channel], impulse_response[:, channel])[:len(audio)] return reverb_audio + def apply_echo(audio, delay=0.2, decay=0.5, fs=44100): delay_samples = int(delay * fs) echo_audio = np.zeros((len(audio) + delay_samples)) @@ -83,6 +85,7 @@ def apply_echo(audio, delay=0.2, decay=0.5, fs=44100): echo_audio = echo_audio[:len(audio)] return echo_audio + def apply_chorus(audio, rate=1.5, depth=0.02, fs=44100): t = np.arange(len(audio)) / fs mod = depth * np.sin(2 * np.pi * rate * t) @@ -96,6 +99,7 @@ def apply_chorus(audio, rate=1.5, depth=0.02, fs=44100): chorus_audio[i, channel] = audio[i, channel] return chorus_audio + def apply_distortion(audio, gain=2.0, threshold=0.5): distorted_audio = gain * audio distorted_audio[distorted_audio > threshold] = threshold @@ -114,8 +118,9 @@ def __init__(self, attack_time, decay_time, sustain_level, release_time, sample_ self.ads_envelope = np.concatenate(( np.linspace(0, 1, self.attack_samples), np.linspace(1, self.sustain_level, self.decay_samples) - )) - self.r_envelope = np.linspace(self.sustain_level, 0, self.release_samples) + )) + self.r_envelope = np.linspace( + self.sustain_level, 0, self.release_samples) self._r_counter = [0 for _ in range(128)] self._ads_counter = [0 for _ in range(128)] @@ -125,7 +130,7 @@ def reset_note(self, note_num): self._r_counter[note_num] = 0 def has_note_ended(self, note_num) -> bool: - return self._r_counter[note_num]>=self.release_samples + return self._r_counter[note_num] >= self.release_samples def get_ads_envelope(self, note_num, frame): start = self._ads_counter[note_num] @@ -137,8 +142,10 @@ def get_ads_envelope(self, note_num, frame): envelope = np.zeros(frame) if end > self.ad_samples: - envelope[:self.ad_samples - start] = self.ads_envelope[start:self.ad_samples] - envelope[self.ad_samples-start:] = np.ones(end - self.ad_samples)*self.sustain_level + envelope[:self.ad_samples - + start] = self.ads_envelope[start:self.ad_samples] + envelope[self.ad_samples - + start:] = np.ones(end - self.ad_samples)*self.sustain_level else: envelope[:] = self.ads_envelope[start:end] @@ -156,11 +163,57 @@ def get_r_envelope(self, note_num, frame): if end <= self.release_samples: envelope[:] = self.r_envelope[start:end] else: - envelope[:self.release_samples - start] = self.r_envelope[start:self.release_samples] - envelope[self.release_samples - start:] = 0 # After release, the envelope is 0 + envelope[:self.release_samples - + start] = self.r_envelope[start:self.release_samples] + # After release, the envelope is 0 + envelope[self.release_samples - start:] = 0 return envelope +class Echo: + def __init__(self, sample_size, delay_time_ms, feedback, wet_dry_mix, device='cpu'): + self.sample_size = sample_size + # Convert ms to samples (assuming 44.1 kHz sample rate) + self.delay_time = int(delay_time_ms * 44.1) + self.feedback = feedback + self.wet_dry_mix = wet_dry_mix + self.device = device + + # Initialize the past buffer to store delayed samples + self.past = torch.zeros( + (self.delay_time + 1, sample_size), device=device) + + def apply(self, sound): + # Ensure sound is a tensor of shape (num_samples, sample_size) + if sound.dim() != 2 or sound.size(1) != self.sample_size: + raise ValueError( + "Input sound must be a 2D tensor with shape (num_samples, sample_size)") + + # Create an output tensor + output = torch.zeros_like(sound, device=self.device) + + for i in range(sound.size(0)): + # Get the current sample + current_sample = sound[i] + + # Get the delayed sample from the past buffer + delayed_sample = self.past[-self.delay_time] if i >= self.delay_time else torch.zeros( + self.sample_size, device=self.device) + + # Calculate the echo effect + echo_sample = (current_sample + delayed_sample * + self.feedback) * self.wet_dry_mix + + # Store the current sample in the past buffer + self.past = torch.roll(self.past, shifts=-1, dims=0) + self.past[-1] = current_sample + + # Combine the original sound and the echo + output[i] = current_sample * (1 - self.wet_dry_mix) + echo_sample + + return output + + class Synth2(): def __init__(self, fourier_nn, stdout: Queue = None, port_name=None): self.stdout = stdout @@ -174,16 +227,10 @@ def __init__(self, fourier_nn, stdout: Queue = None, port_name=None): utils.midi_to_freq(f) * np.linspace(0, 2*np.pi, self.fs) for f in range(128) - ]) + ]) self.t_buffer = torch.tensor(t, dtype=torch.float32) print(self.t_buffer.shape) self.port_name = port_name - self.adsr_envelope=ADSR( - 0.1, - 0.1, - 0.75, - 0.2, - self.fs) def set_port_name(self, port_name): self.port_name = port_name @@ -217,7 +264,7 @@ def play_init_sound(self): # Concatenate the sounds to form "duuudldiiidub" audio = np.concatenate([sound1, sound2, sound3, sound4]) output = np.array( - audio * 32767 / np.max(np.abs(audio)) / 2).astype(np.int16) + audio * 32767 / np.max(np.abs(audio)) / 2).astype(np.int16) sd.play(output, blocking=True) print("Ready") @@ -231,10 +278,17 @@ def live_synth_loop(self): CHUNK = 2048 # Increased chunk size stream = p.open(format=pyaudio.paFloat32, channels=1, + frames_per_buffer=CHUNK, rate=self.fs, output=True) current_frame = 0 cycle_frame = 0 + self.adsr_envelope = ADSR( + 0.1, + 0.1, + 0.75, + 0.2, + self.fs) notes = {} model = self.fourier_nn.current_model.to(self.fourier_nn.device) @@ -243,15 +297,14 @@ def live_synth_loop(self): while True: # for _ in utils.timed_loop(True): available_buffer = stream.get_write_available() - # print(available_buffer, end=" |\t") if available_buffer == 0: continue midi_event = midi_input.poll() if midi_event: print(midi_event) - #midi_event.type - #midi_event.note - #midi_event.velocity + # midi_event.type + # midi_event.note + # midi_event.velocity if midi_event.type == 'note_on': # Note on print("Note on", midi_event.note, @@ -264,36 +317,49 @@ def live_synth_loop(self): midi_event.note, utils.midi_to_freq(midi_event.note)) if midi_event.note in notes: - #del notes[midi_event.note] - notes[midi_event.note][0]=False + # del notes[midi_event.note] + notes[midi_event.note][0] = False if len(notes) > 0: + # y = torch.zeros(size=(len(notes), available_buffer), + # device=self.fourier_nn.device) y = np.zeros((len(notes), available_buffer), dtype=np.float32) - to_delete=[] + to_delete = [] for i, (note, data) in enumerate(notes.items()): with torch.no_grad(): x = utils.wrap_concat( - self.t_buffer[note], cycle_frame, cycle_frame + available_buffer).to(self.fourier_nn.device) + self.t_buffer[note], cycle_frame, cycle_frame + available_buffer).to(self.fourier_nn.device) if data[0]: - envelope=self.adsr_envelope.get_ads_envelope(note, available_buffer) + envelope = self.adsr_envelope.get_ads_envelope( + note, available_buffer) else: - envelope=self.adsr_envelope.get_r_envelope(note, available_buffer) + envelope = self.adsr_envelope.get_r_envelope( + note, available_buffer) if self.adsr_envelope.has_note_ended(note): to_delete.append(note) - y[i, :] = model( - x.unsqueeze(1)).cpu().numpy().astype(np.float32) * envelope # * (amplitude/127) + + model_output = model(x.unsqueeze(1)) + y[i, :] = model_output.cpu().numpy().astype( + np.float32) * envelope + # y[i, :] = model( + # x.unsqueeze(1)).cpu().numpy().astype(np.float32) # * envelope # * (amplitude/127) + # y[i, :] = np.sin( + # x.numpy().astype(np.float32)) * envelope for note in to_delete: del notes[note] audio_data = sum_signals(y) # print(np.max(np.abs(audio_data))) + audio_data = normalize(audio_data) audio_data = np.clip(audio_data, -1, 1) audio_data *= 0.7 - stream.write(audio_data, + stream.write(audio_data.astype(np.float32), available_buffer, exception_on_underflow=True) + # if cycle_frame <= 100: + # print(f"available_buffer: {available_buffer}") current_frame = (current_frame + available_buffer) cycle_frame = (cycle_frame + available_buffer) % self.fs @@ -326,6 +392,9 @@ def __setstate__(self, state): def normalize(signal): + max_val = np.max(np.abs(signal)) + if np.isnan(max_val) or max_val == 0: + return signal return signal / np.max(np.abs(signal)) @@ -383,7 +452,7 @@ def sum_signals_torch(signals): # Normalize each signal normalized_signals = torch.stack( - [sum_signals_torch(signal) for signal in signals]) + [sum_signals_torch(signal) for signal in signals]) # Sum the signals along dimension 0 summed_signal = torch.sum(normalized_signals, dim=0) diff --git a/src/std_redirect.py b/src/std_redirect.py index 3ba0996..8affcc2 100644 --- a/src/std_redirect.py +++ b/src/std_redirect.py @@ -165,18 +165,21 @@ def on_resize(self, event): def check_queue(self): try: # print("asdfasdf") - while not self.queue.empty(): - try: - msg = self.queue.get_nowait() - self.redirector(msg) - except queue.Empty: - break - try: - tk_after_errorless(self.master, 100, self.check_queue) - except: - print("ERROR") + if not self.queue.empty(): + for i in range(100): + try: + msg = self.queue.get_nowait() + self.redirector(msg) + # self.old_stdout.write(str(self.queue.qsize())+'\n') + except queue.Empty: + break except BrokenPipeError: - pass + return + # delay = 100 + delay = int(500 if self.queue.empty() + else min(5, 100/min(1, self.queue.qsize()/10))) + # self.old_stdout.write(f'Delay: {delay}\n') + tk_after_errorless(self.master, delay, self.check_queue) def __del__(self): sys.stdout = self.old_stdout diff --git a/src/utils.py b/src/utils.py index 42402f9..54dac13 100644 --- a/src/utils.py +++ b/src/utils.py @@ -378,11 +378,32 @@ def timed_generator(iterable): def timed_loop(condition): + """ + A generator that runs a timed loop while the condition is true. + + Args: + condition (bool): A condition that controls the loop. + + Yields: + None: Control is yielded back to the caller. + """ max_val = 0 + total_time = 0 + iteration_count = 0 + while condition: start_time = time.perf_counter_ns() - yield + yield # Yield control back to the caller current_time = time.perf_counter_ns() - start_time + max_val = max(current_time, max_val) - print( - f"Time taken for this iteration: {(current_time/1_000_000_000):10.9f}ms, max_val: {max_val/1_000_000_000:10.3}") + total_time += current_time + iteration_count += 1 + + if total_time >= 100_000_000: # 100 milliseconds + avg_time = (total_time / iteration_count) / \ + 1_000_000 # Convert to milliseconds + max_time = max_val / 1_000_000 # Convert to milliseconds + print( + f"Time taken for this iteration: {avg_time:10.9f} ms, max_val: {max_time:10.3f} ms") + total_time, iteration_count = 0, 0 # Reset for the next period From f4438b0aa199b31267f31fa25e84b62e67252fd3 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Tue, 15 Oct 2024 19:23:31 +0200 Subject: [PATCH 12/18] Update music.py made 2 echo version 1 for numpy and one for torch --- src/music.py | 47 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/src/music.py b/src/music.py index cf95025..e013861 100644 --- a/src/music.py +++ b/src/music.py @@ -170,7 +170,7 @@ def get_r_envelope(self, note_num, frame): return envelope -class Echo: +class Echo_torch: def __init__(self, sample_size, delay_time_ms, feedback, wet_dry_mix, device='cpu'): self.sample_size = sample_size # Convert ms to samples (assuming 44.1 kHz sample rate) @@ -214,6 +214,51 @@ def apply(self, sound): return output +class Echo: + def __init__(self, sample_size, delay_time_ms, feedback, wet_dry_mix): + self.sample_size = sample_size + # Convert ms to samples (assuming 44.1 kHz sample rate) + # Convert ms to seconds + self.delay_time = int(delay_time_ms * 44.1 / 1000) + self.feedback = feedback + self.wet_dry_mix = wet_dry_mix + + # Initialize the past buffer to store delayed samples + self.past = np.zeros((self.delay_time + 1, sample_size)) + + def apply(self, sound): + # Ensure sound is a 2D array with shape (num_samples, sample_size) + if sound.ndim != 2 or sound.shape[1] != self.sample_size: + raise ValueError( + "Input sound must be a 2D array with shape (num_samples, sample_size)") + + # Create an output array + output = np.zeros_like(sound) + + for i in range(sound.shape[0]): + # Get the current sample + current_sample = sound[i] + + # Get the delayed sample from the past buffer + if i >= self.delay_time: + delayed_sample = self.past[-self.delay_time] + else: + delayed_sample = np.zeros(self.sample_size) + + # Calculate the echo effect + echo_sample = (current_sample + delayed_sample * + self.feedback) * self.wet_dry_mix + + # Store the current sample in the past buffer + self.past = np.roll(self.past, shift=-1, axis=0) + self.past[-1] = current_sample + + # Combine the original sound and the echo + output[i] = current_sample * (1 - self.wet_dry_mix) + echo_sample + + return output + + class Synth2(): def __init__(self, fourier_nn, stdout: Queue = None, port_name=None): self.stdout = stdout From b06c86f34fb29dd324560c0cdc2072b952fc165a Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Thu, 17 Oct 2024 07:07:45 +0200 Subject: [PATCH 13/18] Update music.py --- src/music.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/music.py b/src/music.py index e013861..7053db7 100644 --- a/src/music.py +++ b/src/music.py @@ -366,6 +366,7 @@ def live_synth_loop(self): notes[midi_event.note][0] = False if len(notes) > 0: + print(f"available_buffer: {available_buffer}") # y = torch.zeros(size=(len(notes), available_buffer), # device=self.fourier_nn.device) y = np.zeros((len(notes), available_buffer), From b90c73bdb217e90d71bf75a71106bd89314cd9e9 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Sun, 20 Oct 2024 14:14:29 +0200 Subject: [PATCH 14/18] renames fs to samplerate for better understanding --- audio_stuff/midi/fuer_elise.py | 13 +++++++------ src/music.py | 24 +++++++++++++----------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/audio_stuff/midi/fuer_elise.py b/audio_stuff/midi/fuer_elise.py index 6ec1ceb..4c80687 100644 --- a/audio_stuff/midi/fuer_elise.py +++ b/audio_stuff/midi/fuer_elise.py @@ -6,12 +6,13 @@ # Define the notes for "Für Elise" fur_elise = [ - ('E5', 0.5), ('D#5', 0.5), ('E5', 0.5), ('D#5', 0.5), ('E5', - 0.5), ('B4', 0.5), ('D5', 0.5), ('C5', 0.5), ('A4', 1.5), - ('C4', 0.5), ('E4', 0.5), ('A4', 0.5), ('B4', 1.5), ('E4', - 0.5), ('G#4', 0.5), ('B4', 0.5), ('C5', 1.5), - ('E4', 0.5), ('C4', 0.5), ('E4', 0.5), ('A4', 0.5), ('B4', - 1.5), ('E4', 0.5), ('G#4', 0.5), ('B4', 0.5), ('C5', 1.5) + ('E5', 0.5), ('D#5', 0.5), ('E5', 0.5), ('D#5', 0.5), + ('E5', 0.5), ('B4', 0.5), ('D5', 0.5), ('C5', 0.5), + ('A4', 1.5), ('C4', 0.5), ('E4', 0.5), ('A4', 0.5), + ('B4', 1.5), ('E4', 0.5), ('G#4', 0.5), ('B4', 0.5), + ('C5', 1.5), ('E4', 0.5), ('C4', 0.5), ('E4', 0.5), + ('A4', 0.5), ('B4', 1.5), ('E4', 0.5), ('G#4', 0.5), + ('B4', 0.5), ('C5', 1.5) ] # Define a function to convert note names to MIDI note numbers diff --git a/src/music.py b/src/music.py index 7053db7..0808efa 100644 --- a/src/music.py +++ b/src/music.py @@ -265,12 +265,12 @@ def __init__(self, fourier_nn, stdout: Queue = None, port_name=None): self.live_synth: Process = None self.notes_ready = False self.fourier_nn: FourierNN = fourier_nn - self.fs = 44100 # Sample rate + self.sample_rate = 44100 # Sample rate self.max_parralel_notes = 3 self.current_frame = 0 t = np.array([ utils.midi_to_freq(f) * - np.linspace(0, 2*np.pi, self.fs) + np.linspace(0, 2*np.pi, self.sample_rate) for f in range(128) ]) self.t_buffer = torch.tensor(t, dtype=torch.float32) @@ -291,19 +291,19 @@ def play_init_sound(self): t4 = 0.4 # Duration of the "dii" sound (in seconds) # Generate the "duuu" sound - t = np.arange(int(t1 * self.fs)) / self.fs + t = np.arange(int(t1 * self.sample_rate)) / self.sample_rate sound1 = 0.5 * np.sin(2 * np.pi * f1 * t) # Generate the "dl" sound - t = np.arange(int(t2 * self.fs)) / self.fs + t = np.arange(int(t2 * self.sample_rate)) / self.sample_rate sound2 = 0.5 * np.sin(2 * np.pi * f2 * t) # Generate the "diii" sound - t = np.arange(int(t3 * self.fs)) / self.fs + t = np.arange(int(t3 * self.sample_rate)) / self.sample_rate sound3 = 0.5 * np.sin(2 * np.pi * f3 * t) # Generate the "dub" sound - t = np.arange(int(t4 * self.fs)) / self.fs + t = np.arange(int(t4 * self.sample_rate)) / self.sample_rate sound4 = 0.5 * np.sin(2 * np.pi * f4 * t) # Concatenate the sounds to form "duuudldiiidub" @@ -323,8 +323,8 @@ def live_synth_loop(self): CHUNK = 2048 # Increased chunk size stream = p.open(format=pyaudio.paFloat32, channels=1, - frames_per_buffer=CHUNK, - rate=self.fs, + # frames_per_buffer=CHUNK, + rate=self.sample_rate, output=True) current_frame = 0 cycle_frame = 0 @@ -333,11 +333,12 @@ def live_synth_loop(self): 0.1, 0.75, 0.2, - self.fs) + self.sample_rate) notes = {} model = self.fourier_nn.current_model.to(self.fourier_nn.device) self.play_init_sound() + with mido.open_input(self.port_name) as midi_input: while True: # for _ in utils.timed_loop(True): @@ -399,15 +400,16 @@ def live_synth_loop(self): audio_data = sum_signals(y) # print(np.max(np.abs(audio_data))) audio_data = normalize(audio_data) + audio_data *= 1 # oscilating_amplitude audio_data = np.clip(audio_data, -1, 1) - audio_data *= 0.7 stream.write(audio_data.astype(np.float32), available_buffer, exception_on_underflow=True) # if cycle_frame <= 100: # print(f"available_buffer: {available_buffer}") current_frame = (current_frame + available_buffer) - cycle_frame = (cycle_frame + available_buffer) % self.fs + cycle_frame = (cycle_frame + available_buffer) %\ + self.sample_rate def run_live_synth(self): if not self.live_synth: From c23cd6d79676e5641aad410c4e4e641771a27c52 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Tue, 10 Dec 2024 15:45:16 +0100 Subject: [PATCH 15/18] stuff --- main.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index 301d2e2..91a5641 100644 --- a/main.py +++ b/main.py @@ -519,9 +519,9 @@ def main(): window.protocol("WM_DELETE_WINDOW", window.quit) state = "running" try: - window.after(1000, lambda: window.graph.plot_function( - predefined_functions_dict['funny2'], overwrite=True)) - window.after(2000, window.start_training) + # window.after(1000, lambda: window.graph.plot_function( + # predefined_functions_dict['funny2'], overwrite=True)) + # window.after(2000, window.start_training) window.mainloop() except KeyboardInterrupt: print("exiting via keybord interupt") From 273358103d221c83561d35e4f67676123e9db955 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Tue, 28 Jan 2025 12:36:37 +0100 Subject: [PATCH 16/18] dependabot --- .github/dependabot.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..c2fabe1 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,17 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + # Maintain dependencies for Cargo + - package-ecosystem: "cargo" + directory: "/" # Location of package manifests + schedule: + interval: "weekly" + # Maintain dependencies for GitHub Actions + - package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly From a21cf2bb5ebf572532c9c19554b8ec08de35b569 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Tue, 28 Jan 2025 12:38:14 +0100 Subject: [PATCH 17/18] workflow update --- .github/workflows/dayly_build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/dayly_build.yml b/.github/workflows/dayly_build.yml index 4486596..14f6d5a 100644 --- a/.github/workflows/dayly_build.yml +++ b/.github/workflows/dayly_build.yml @@ -1,9 +1,11 @@ name: Dayly Build on: + pull_request: push: branches: - dev + - main jobs: build-linux: From 42544abe64f0742e11a75512600af708588bff03 Mon Sep 17 00:00:00 2001 From: thetechnicker Date: Tue, 28 Jan 2025 13:10:05 +0100 Subject: [PATCH 18/18] dependencies update --- environment.yml | 118 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 100 insertions(+), 18 deletions(-) diff --git a/environment.yml b/environment.yml index c2a3197..963169d 100644 --- a/environment.yml +++ b/environment.yml @@ -1,22 +1,104 @@ channels: - defaults dependencies: - - python==3.11 - - pip + - bzip2=1.0.8 + - ca-certificates=2024.9.24 + - flake8=7.1.1 + - libffi=3.4.4 + - mccabe=0.7.0 + - openssl=1.1.1w + - pip=24.2 + - pycodestyle=2.12.1 + - pyflakes=3.2.0 + - python=3.11.0 + - setuptools=75.1.0 + - sqlite=3.45.3 + - tk=8.6.14 + - tzdata=2024a + - wheel=0.44.0 + - xz=5.4.6 + - zlib=1.2.13 - pip: - - numpy - - pygame - - scipy - - torch - - psutil - - numba - - pretty_midi - - sounddevice - - pyaudio - - matplotlib - - nuitka - - mkdocs - - mkdocs-material - - mkdocs-git-revision-date-localized-plugin - - mkdocs-git-authors-plugin - - mkdocstrings + - argparse==1.4.0 + - attrs==24.2.0 + - automat==24.8.1 + - babel==2.16.0 + - buildtools==1.0.6 + - certifi==2024.8.30 + - cffi==1.17.1 + - charset-normalizer==3.3.2 + - click==8.1.7 + - colorama==0.4.6 + - constantly==23.10.4 + - contourpy==1.3.0 + - cycler==0.12.1 + - cython==3.0.11 + - docopt==0.6.2 + - filelock==3.16.1 + - fonttools==4.54.0 + - fsspec==2024.9.0 + - furl==2.1.3 + - ghp-import==2.1.0 + - gitdb==4.0.11 + - gitpython==3.1.43 + - greenlet==3.1.1 + - hyperlink==21.0.0 + - idna==3.10 + - incremental==24.7.2 + - jinja2==3.1.4 + - keras==3.5.0 + - kiwisolver==1.4.7 + - llvmlite==0.43.0 + - markupsafe==2.1.5 + - matplotlib==3.9.2 + - mergedeep==1.3.4 + - mido==1.3.2 + - mkdocs==1.6.1 + - mkdocs-autorefs==1.2.0 + - mkdocs-get-deps==0.2.0 + - mkdocs-git-authors-plugin==0.9.0 + - mkdocs-git-revision-date-localized-plugin==1.2.9 + - mkdocs-material==9.5.39 + - mkdocs-material-extensions==1.3.1 + - mkdocstrings==0.26.1 + - mpmath==1.3.0 + - networkx==3.3 + - nuitka==2.4.8 + - numba==0.60.0 + - numpy==2.0.2 + - ordered-set==4.1.0 + - orderedmultidict==1.0.1 + - packaging==23.2 + - paginate==0.5.7 + - pathspec==0.12.1 + - pillow==10.4.0 + - platformdirs==4.3.6 + - psutil==6.0.0 + - pyaudio==0.2.14 + - pycparser==2.22 + - pygame==2.6.0 + - pygments==2.18.0 + - pymdown-extensions==10.11.2 + - pyparsing==3.1.4 + - python-dateutil==2.9.0.post0 + - python-rtmidi==1.5.8 + - pytz==2024.2 + - pyyaml==6.0.2 + - pyyaml-env-tag==0.1 + - redo==3.0.0 + - regex==2024.9.11 + - requests==2.32.3 + - scipy==1.14.1 + - simplejson==3.19.3 + - six==1.16.0 + - smmap==5.0.1 + - sounddevice==0.5.0 + - sqlalchemy==2.0.35 + - sympy==1.13.3 + - torch==2.4.1 + - torchvision==0.19.1 + - twisted==24.7.0 + - typing-extensions==4.12.2 + - urllib3==2.2.3 + - zope-interface==7.0.3 + - zstandard==0.23.0