From ba2c5a6e39342809a14528bf1a39e1f11d545094 Mon Sep 17 00:00:00 2001 From: Emanulator Date: Tue, 2 Jan 2024 20:25:31 +0000 Subject: [PATCH] create offiplayergui.py & update offitracker.py Adds a GUI for easy usage --- offiplayergui.py | 45 +++++++++++++++ offitracker.py | 144 +++++++++++++++++++++++++---------------------- 2 files changed, 122 insertions(+), 67 deletions(-) create mode 100644 offiplayergui.py diff --git a/offiplayergui.py b/offiplayergui.py new file mode 100644 index 0000000..2c76f6a --- /dev/null +++ b/offiplayergui.py @@ -0,0 +1,45 @@ +import PySimpleGUI as sg +import glob +import offitracker as offi +import sys +import csv +import numpy as np +import sounddevice as sd +import threading + +names = glob.glob("./**/*.csv", recursive=True) +toplay = "" + +layout = [[sg.Text('Search')], + [sg.Input(size=(200, 1), enable_events=True, key='-INPUT-')], + [sg.Listbox(names, size=(200, 10), enable_events=True, key='-LIST-')], + [sg.Button('Play'), sg.Button('Stop'), sg.Text("",key="file")]] + +window = sg.Window('OffiPlayer', layout,size=(480, 320)) + +def playthread(window): + offi.stop_signal = False + offi.play_csv_file(toplay) + window.write_event_value(('-THREAD-', '** DONE **'), 'Done!') + +while True: + event, values = window.read() + if event in (sg.WIN_CLOSED, 'Exit'): + break + if values['-INPUT-'] != '': + search = values['-INPUT-'] + new_values = [x for x in names if search in x] + window['-LIST-'].update(new_values) + else: + window['-LIST-'].update(names) + if event == '-LIST-' and len(values['-LIST-']): + toplay = values['-LIST-'][0] + window['file'].update(toplay) + if event == 'Play': + window.start_thread(lambda: playthread(window), ('-THREAD-', '-THEAD ENDED-')) + if event == 'Stop': + offi.stop_signal = True +window.close() + + + diff --git a/offitracker.py b/offitracker.py index ecd240f..8d27ff7 100644 --- a/offitracker.py +++ b/offitracker.py @@ -1,67 +1,77 @@ -import sys -import csv -import numpy as np -import sounddevice as sd - -# OffiTracker, the tracker that no one asked for but I made it anyways :3 -# Usage: Make a CSV table in Excel or LibreOffice with the following format: -# Frequency1 Effect1 Frequency2 Effect2 .... Noise Duration -# You can make as many channels as you want. -# Effect = pulse width from 0 to 100 -# Frequency = tone in Hz. -# Noise = noise amplitude from 0 to 10 -# Duration = tone duration in ms -# (c) 2024 mueller_minki, Feel free to modify or share. - -def play_square_waves(output_stream, frequencies, effects, duration, amplitude=1, noise_amplitude=0, sample_rate=44100): - num_waves = len(frequencies) - t = np.linspace(0, duration / 1000, int(sample_rate * duration / 1000), endpoint=False) - - # Generate and sum square waves for each frequency with corresponding effects - waves = [amplitude * (effect / 100) * np.sign(np.sin(2 * np.pi * freq * t)) for freq, effect in zip(frequencies, effects)] - - # Add optional noise channel - if noise_amplitude > 0: - noise = noise_amplitude * np.random.uniform(-1, 1, len(t)) - waves.append(noise) - - combined_wave = np.sum(waves, axis=0) - - combined_wave = combined_wave.astype(np.float32) - - output_stream.write(combined_wave) - -def play_csv_file(file_path): - with open(file_path, 'r') as csv_file: - csv_reader = csv.DictReader(csv_file) - header = csv_reader.fieldnames - num_columns = len(header) - num_pairs = (num_columns - 1) // 2 - - with sd.OutputStream(channels=1) as output_stream: - for row in csv_reader: - frequencies = [float(row[f'Frequency{i}']) for i in range(1, num_pairs + 1)] - effects = [float(row[f'Effect{i}']) for i in range(1, num_pairs + 1)] - duration = float(row['Duration']) - - # Check if 'Noise' column exists in the CSV file - noise_amplitude = float(row.get('Noise', 0)) - - play_square_waves(output_stream, frequencies, effects, duration, noise_amplitude=noise_amplitude) - -if __name__ == "__main__": - print(' ') - print(' Mueller\'s Software Domain proudly presents:') - print('________ _____ _____._____________ __ ') - print('\_____ \_/ ____\/ ____\__\__ ___/___________ ____ | | __ ___________ ') - print(' / | \ __\\\\ __\| | | | \_ __ \__ \ _/ ___\| |/ // __ \_ __ \\') - print('/ | \ | | | | | | | | | \// __ \\\\ \___| <\ ___/| | \/') - print('\_______ /__| |__| |__| |____| |__| (____ /\___ >__|_ \\\\___ >__| ') - print(' \/ \/ \/ \/ \/ ') - print(' Version 1.1') - if len(sys.argv) > 1: - csv_file_path = sys.argv[1] - else: - csv_file_path = input("Choose a CSV file: ") - play_csv_file(csv_file_path) - +import sys +import csv +import numpy as np +import sounddevice as sd +import time +# OffiTracker, the tracker that no one asked for but I made it anyways :3 +# Usage: Make a CSV table in Excel or LibreOffice with the following format: +# Frequency1 Effect1 Frequency2 Effect2 .... Noise Duration +# You can make as many channels as you want. +# Effect = pulse width from 0 to 100 +# Frequency = tone in Hz. +# Noise = noise amplitude from 0 to 10 +# Duration = tone duration in ms +# (c) 2024 mueller_minki, Feel free to modify or share. +stop_signal = False + +def stop_playback(): + stop_signal = True + +def play_square_waves(output_stream, frequencies, effects, duration, amplitude=1, noise_amplitude=0, sample_rate=44100): + if stop_signal == True: + output_stream.stop() + pass + else: + num_waves = len(frequencies) + t = np.linspace(0, duration / 1000, int(sample_rate * duration / 1000), endpoint=False) + + # Generate and sum square waves for each frequency with corresponding effects + waves = [amplitude * (effect / 100) * np.sign(np.sin(2 * np.pi * freq * t)) for freq, effect in zip(frequencies, effects)] + + # Add optional noise channel + if noise_amplitude > 0: + noise = noise_amplitude * np.random.uniform(-1, 1, len(t)) + waves.append(noise) + + combined_wave = np.sum(waves, axis=0) + + combined_wave = combined_wave.astype(np.float32) + + output_stream.write(combined_wave) + +def play_csv_file(file_path): + stop_signal = False + + with open(file_path, 'r') as csv_file: + csv_reader = csv.DictReader(csv_file) + header = csv_reader.fieldnames + num_columns = len(header) + num_pairs = (num_columns - 1) // 2 + + with sd.OutputStream(channels=1) as output_stream: + for row in csv_reader: + frequencies = [float(row[f'Frequency{i}']) for i in range(1, num_pairs + 1)] + effects = [float(row[f'Effect{i}']) for i in range(1, num_pairs + 1)] + duration = float(row['Duration']) + + # Check if 'Noise' column exists in the CSV file + noise_amplitude = float(row.get('Noise', 0)) + if stop_signal == False: + play_square_waves(output_stream, frequencies, effects, duration, noise_amplitude=noise_amplitude) + +if __name__ == "__main__": + print(' ') + print(' Mueller\'s Software Domain proudly presents:') + print('________ _____ _____._____________ __ ') + print('\_____ \_/ ____\/ ____\__\__ ___/___________ ____ | | __ ___________ ') + print(' / | \ __\\\\ __\| | | | \_ __ \__ \ _/ ___\| |/ // __ \_ __ \\') + print('/ | \ | | | | | | | | | \// __ \\\\ \___| <\ ___/| | \/') + print('\_______ /__| |__| |__| |____| |__| (____ /\___ >__|_ \\\\___ >__| ') + print(' \/ \/ \/ \/ \/ ') + print(' Version 1.1') + if len(sys.argv) > 1: + csv_file_path = sys.argv[1] + else: + csv_file_path = input("Choose a CSV file: ") + play_csv_file(csv_file_path) +