From 109ce3b3fe61041ba8c93a8fa1fedb592612ae11 Mon Sep 17 00:00:00 2001 From: iAmInActions Date: Tue, 2 Jan 2024 15:04:34 +0100 Subject: [PATCH] Initial commit --- README.md | 29 +++++++++++++++- example/mario-levelcleared.csv | 28 +++++++++++++++ example/test2.csv | 3 ++ img/cli.png | Bin 0 -> 12114 bytes img/excel.png | Bin 0 -> 20522 bytes offitracker.py | 60 +++++++++++++++++++++++++++++++++ 6 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 example/mario-levelcleared.csv create mode 100644 example/test2.csv create mode 100644 img/cli.png create mode 100644 img/excel.png create mode 100644 offitracker.py diff --git a/README.md b/README.md index ccbb7ff..804e9da 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,30 @@ # OffiTracker -Ever wanted to make music in Excel? Now you can! \ No newline at end of file +Ever wanted to make music in Excel? Now you can! + +OffiTracker lets you use CSV spreadsheets to create chiptunes. Its as simple as typing in the frequency, pulse width and duration. + +![Screenshot of a spreadsheet program showing tracker data](img/excel.png) +![The softwares CLI](img/cli.png) + +## Usage + +Running OffiTracker requires the following packages to be present on your system: + +`python3, python3-csv, pyhon3-numpy, python3-sounddevice` + +Assuming `python3` is already installed, you can use the following command to install the dependencies: + +```bash +pip3 install csv numpy sounddevice +``` + +After that, simply run `python3 offitracker.py` and enjoy. + + + +____ + +Examples can be found in the `example` folder. + +For usage information, check the contents of the `offitracker.py` file diff --git a/example/mario-levelcleared.csv b/example/mario-levelcleared.csv new file mode 100644 index 0000000..e7bb840 --- /dev/null +++ b/example/mario-levelcleared.csv @@ -0,0 +1,28 @@ +Frequency1,Effect1,Duration +130,50,100 +262,50,100 +330,50,100 +392,50,100 +523,50,100 +660,50,100 +784,50,300 +660,50,300 +146,50,100 +262,50,100 +311,50,100 +415,50,100 +523,50,100 +622,50,100 +831,50,300 +622,50,300 +155,50,100 +294,50,100 +349,50,100 +466,50,100 +588,50,100 +699,50,100 +933,50,300 +933,50,100 +933,50,100 +933,50,100 +1047,50,400 diff --git a/example/test2.csv b/example/test2.csv new file mode 100644 index 0000000..cac034f --- /dev/null +++ b/example/test2.csv @@ -0,0 +1,3 @@ +Frequency1,Effect1,Frequency2,Effect2,Frequency3,Effect3,Noise,Duration +440,50,247,10,311,70,0,500 +440,25,247,10,311,40,5,500 diff --git a/img/cli.png b/img/cli.png new file mode 100644 index 0000000000000000000000000000000000000000..eecd963877a115676d4c3ea78c46bb739b662856 GIT binary patch literal 12114 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 literal 0 HcmV?d00001 diff --git a/img/excel.png b/img/excel.png new file mode 100644 index 0000000000000000000000000000000000000000..c70570b610d7b665251cc1767c1d665603ec2cf4 GIT binary patch literal 20522 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 C@knI= literal 0 HcmV?d00001 diff --git a/offitracker.py b/offitracker.py new file mode 100644 index 0000000..2e7ca87 --- /dev/null +++ b/offitracker.py @@ -0,0 +1,60 @@ +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(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) + + sd.play(combined_wave, sample_rate, blocking=True) + +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 + + 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(frequencies, effects, duration, noise_amplitude=noise_amplitude) + + +if __name__ == "__main__": + print(' ') + print(' Mueller\'s Software Domain proudly presents:') + print('________ _____ _____._____________ __ ') + print('\_____ \_/ ____\/ ____\__\__ ___/___________ ____ | | __ ___________ ') + print(' / | \ __\\\\ __\| | | | \_ __ \__ \ _/ ___\| |/ // __ \_ __ \\') + print('/ | \ | | | | | | | | | \// __ \\\\ \___| <\ ___/| | \/') + print('\_______ /__| |__| |__| |____| |__| (____ /\___ >__|_ \\\\___ >__| ') + print(' \/ \/ \/ \/ \/ ') + csv_file_path = input("Choose a CSV file: ") + play_csv_file(csv_file_path) +