forked from Minki/OffiTracker
Initial commit
This commit is contained in:
parent
4806adf9a1
commit
109ce3b3fe
27
README.md
27
README.md
@ -1,3 +1,30 @@
|
||||
# OffiTracker
|
||||
|
||||
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
|
||||
|
28
example/mario-levelcleared.csv
Normal file
28
example/mario-levelcleared.csv
Normal file
@ -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
|
|
3
example/test2.csv
Normal file
3
example/test2.csv
Normal file
@ -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
|
|
BIN
img/cli.png
Normal file
BIN
img/cli.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
img/excel.png
Normal file
BIN
img/excel.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
60
offitracker.py
Normal file
60
offitracker.py
Normal file
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user