Skip to content
Merged

Dev #20

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
74 commits
Select commit Hold shift + click to select a range
656a238
bugfix + synth optimization
thetechnicker Oct 3, 2024
0f1e19f
suff
thetechnicker Oct 3, 2024
bd77c6f
Update music.py
thetechnicker Oct 3, 2024
60c2f44
Update _version.py
thetechnicker Oct 3, 2024
2d8e62a
Delete main.yml
thetechnicker Oct 3, 2024
7590e3b
Create dayly_build.yml
thetechnicker Oct 3, 2024
027c3fd
Update dayly_build.yml
thetechnicker Oct 3, 2024
7b5c3bd
Update music.py
thetechnicker Oct 4, 2024
ab4493c
adsr and für eliese
thetechnicker Oct 4, 2024
4e0abb9
Update _version.py
thetechnicker Oct 4, 2024
80c6bee
adapt for real piano
thetechnicker Oct 4, 2024
123bcda
changed midi library
thetechnicker Oct 5, 2024
d1d8919
added GUI ellement for selecting midi port
thetechnicker Oct 5, 2024
b1a37be
Allow GPU
thetechnicker Oct 5, 2024
10f241c
synth now runs on gpu
thetechnicker Oct 5, 2024
1f9c85d
documentation and contributing
thetechnicker Oct 5, 2024
e62575c
Create CODE_OF_CONDUCT.md
thetechnicker Oct 5, 2024
2ec42fe
Update index.md
thetechnicker Oct 5, 2024
aca7aa4
Update index.md
thetechnicker Oct 5, 2024
f3f8199
Update index.md
thetechnicker Oct 5, 2024
846bceb
Update idea.md
thetechnicker Oct 5, 2024
6d495f7
Merge pull request #15 from thetechnicker/main
thetechnicker Oct 5, 2024
42aaed4
Merge branch 'dev' into thetechnicker
thetechnicker Oct 5, 2024
c622d15
Update CONTRIBUTING.md
thetechnicker Oct 6, 2024
f024716
Documentation
thetechnicker Oct 6, 2024
5f4f289
setup documentation to include new files
thetechnicker Oct 6, 2024
6d314e6
added overview
thetechnicker Oct 6, 2024
42a8377
more docu
thetechnicker Oct 6, 2024
ea96f97
scr -> src
thetechnicker Oct 6, 2024
22f128b
Update setup.py
thetechnicker Oct 6, 2024
62c94ef
bugfix wrong version
thetechnicker Oct 6, 2024
2e299aa
Merge pull request #16 from thetechnicker/thetechnicker
thetechnicker Oct 6, 2024
2361b30
Update idea.md
thetechnicker Oct 6, 2024
a20f75f
how to use
thetechnicker Oct 6, 2024
50ce0e1
documentation
thetechnicker Oct 6, 2024
68d1c3b
documentation
thetechnicker Oct 6, 2024
07db1a9
added katex
thetechnicker Oct 6, 2024
0115ddc
documentation
thetechnicker Oct 7, 2024
1699c38
Update basics.md
thetechnicker Oct 7, 2024
e675b4c
docu
thetechnicker Oct 7, 2024
fb9786d
Update model_params.md
thetechnicker Oct 7, 2024
abcaf04
Merge branch 'thetechnicker' into dev
thetechnicker Oct 12, 2024
9cf932f
Update music.py
thetechnicker Oct 12, 2024
bcdf92a
added ADSR Envelope
thetechnicker Oct 13, 2024
d3524a4
added pre_release workflow for my branch
thetechnicker Oct 13, 2024
6ff8115
saved workflow in wrong folder
thetechnicker Oct 13, 2024
95f1954
renamed workflow
thetechnicker Oct 13, 2024
f0307a9
fixed workflow
thetechnicker Oct 13, 2024
6152fc5
some more fixes
thetechnicker Oct 13, 2024
f0c24b1
workflow does not work
thetechnicker Oct 13, 2024
c762576
removed useless code
thetechnicker Oct 14, 2024
90f332d
small changes
thetechnicker Oct 14, 2024
cb9fa1d
Merge branch 'thetechnicker' of https://github.com/thetechnicker/Pyth…
thetechnicker Oct 14, 2024
fb9e227
added Echo
thetechnicker Oct 15, 2024
f4438b0
Update music.py
thetechnicker Oct 15, 2024
b06c86f
Update music.py
thetechnicker Oct 17, 2024
b90c73b
renames fs to samplerate for better understanding
thetechnicker Oct 20, 2024
c23cd6d
stuff
thetechnicker Dec 10, 2024
2733581
dependabot
thetechnicker Jan 28, 2025
a21cf2b
workflow update
thetechnicker Jan 28, 2025
42544ab
dependencies update
thetechnicker Jan 28, 2025
d3f8fcc
Merge pull request #17 from thetechnicker/thetechnicker
thetechnicker Jan 28, 2025
44169e2
project structure redo
thetechnicker Feb 25, 2025
1c2e46e
update dependabot
thetechnicker Feb 25, 2025
663a3ec
readme update
thetechnicker Feb 25, 2025
955387d
new formatting style + example music
thetechnicker Feb 25, 2025
7aac8e6
test contex fixed
thetechnicker Feb 25, 2025
86e47e3
better piano and fuer_elise
thetechnicker Feb 25, 2025
eacc439
idk
thetechnicker Feb 26, 2025
ff489e4
idk
thetechnicker Mar 24, 2025
fb5deee
working record function
thetechnicker Mar 24, 2025
8a4f88f
vissible button reaction if using keyboard
thetechnicker Mar 24, 2025
e8bf07b
bugfix: all keys triggered same button to show effect
thetechnicker Mar 24, 2025
4a1fa9c
Merge pull request #19 from thetechnicker/18-play-to-file
thetechnicker Mar 24, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: 2
updates:
- package-ecosystem: "conda"
directory: "/"
schedule:
interval: "weekly"
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: weekly
41 changes: 41 additions & 0 deletions .github/workflows/dayly_build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Dayly Build

on:
pull_request:
push:
branches:
- dev
- main

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: |
# $CONDA is an environment variable pointing to the root of the miniconda directory
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: Upload artifact
uses: actions/upload-artifact@v4
with:
name: python-package-distributions
path: dist/
28 changes: 0 additions & 28 deletions .github/workflows/main.yml

This file was deleted.

6 changes: 3 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Please follow these steps to have your contribution considered by the maintainer

1. **Fork** the repository and create your branch from `dev`.
2. **If you've added code** that should be tested, add tests.
3. **If you've changed APIs**, update the documentation.
3. **If youve modified any modules or files**, update the documentation accordingly.
4. **Ensure the test suite passes**.
5. **Make sure your code lints** using `ms-python.autopep8` from VSCode.
6. **Issue that pull request**!
Expand All @@ -60,8 +60,8 @@ Please follow these steps to have your contribution considered by the maintainer

### Python Style Guide

- Use PEP 8 style guide.
- Use `ms-python.autopep8` from VSCode for formatting.
- Use The Black code style.
- Use `ms-python.black-formatter` from VSCode for formatting.

### Clean Code and Documentation

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ conda activate ai_synth
Once the project setup is complete, you can initiate it by executing the `main.py` file in the environment:

```bash
python main.py
python -m pythonaisynth.main
```

![window](docs/img/main_window_v3.png)
Expand Down
1 change: 0 additions & 1 deletion _version.py

This file was deleted.

121 changes: 75 additions & 46 deletions audio_stuff/midi/midi_piano.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,52 +16,55 @@

def changePort(event):
global port
port.panic()
port.close()
port = mido.open_output(selected_port.get())


# Create a dropdown menu to select the MIDI port
port_menu = tk.OptionMenu(window, selected_port, *
mido.get_output_names(), command=changePort)
port_menu = tk.OptionMenu(
window, selected_port, *mido.get_output_names(), command=changePort
)
port_menu.pack()

# Create a variable to store the selected MIDI channel
selected_channel = tk.StringVar(window)
selected_channel.set('1') # default value
selected_channel.set("1") # default value

# Create a dropdown menu to select the MIDI channel
channel_menu = tk.OptionMenu(
window, selected_channel, *[str(i) for i in range(1, 17)])
channel_menu = tk.OptionMenu(window, selected_channel, *[str(i) for i in range(1, 17)])
channel_menu.pack()

# Create a variable to store the selected octave
selected_octave = tk.IntVar(window)
selected_octave.set(4) # default value

# Create a slider to select the octave
octave_slider = tk.Scale(window, from_=0, to=8, orient='horizontal',
variable=selected_octave, label='Octave')
octave_slider = tk.Scale(
window, from_=0, to=8, orient="horizontal", variable=selected_octave, label="Octave"
)
octave_slider.pack()

# Function to send MIDI messages

note_states = {i: False for i in range(octaves_to_display*12)}
note_states = {i: False for i in range(octaves_to_display * 12)}


def send_midi_note(note, velocity=127, type='note_on'):
def send_midi_note(note, velocity=127, type="note_on"):
global note_states

channel = int(selected_channel.get()) - 1
msg = mido.Message(type, note=note + selected_octave.get()
* 12, velocity=velocity, channel=channel)
if type == 'note_on':
msg = mido.Message(
type, note=note + selected_octave.get() * 12, velocity=velocity, channel=channel
)
if type == "note_on":
# If the note is already on, don't send another note_on message
if note_states[note]:
return
else:
note_states[note] = True
port.send(msg)
elif type == 'note_off':
elif type == "note_off":
note_states[note] = False
port.send(msg)
# window.after(1*10**3, lambda msg=msg: port.send(msg))
Expand All @@ -79,60 +82,86 @@ def send_midi_note(note, velocity=127, type='note_on'):
black_key_note = ["C#", "D#", "F#", "G#", "A#"]

white_keys_bindings_per_octaves = [
['a', 's', 'd', 'f', 'g', 'h', 'j'], ['k', 'l', ';', "'", 'z', 'x', 'c']]
black_keys_bindings_per_octaves = [
['w', 'e', 'r', 't', 'y'], ['u', 'i', 'o', 'p', '[']]
["a", "s", "d", "f", "g", "h", "j"],
["k", "l", ";", "'", "z", "x", "c"],
]
black_keys_bindings_per_octaves = [["w", "e", "r", "t", "y"], ["u", "i", "o", "p", "["]]

current_locale = locale.getlocale()
# If the current locale is German, adjust the key bindings
if "de_DE" in current_locale:
white_keys_bindings_per_octaves = [['a', 's', 'd', 'f', 'g', 'h', 'j'], [
'k', 'l', 'odiaeresis', 'adiaeresis', 'y', 'x', 'c']]
white_keys_bindings_per_octaves = [
["a", "s", "d", "f", "g", "h", "j"],
["k", "l", "odiaeresis", "adiaeresis", "y", "x", "c"],
]
black_keys_bindings_per_octaves = [
['w', 'e', 'r', 't', 'z'], ['u', 'i', 'o', 'p', 'udiaeresis']]
["w", "e", "r", "t", "z"],
["u", "i", "o", "p", "udiaeresis"],
]

for a in range(octaves_to_display):
if a < len(white_keys_bindings_per_octaves) or a < len(black_keys_bindings_per_octaves):
if a < len(white_keys_bindings_per_octaves) or a < len(
black_keys_bindings_per_octaves
):
white_keys_bindings = white_keys_bindings_per_octaves[a]
black_keys_bindings = black_keys_bindings_per_octaves[a]
else:
white_keys_bindings = [" "]*len(white_key_note)
black_keys_bindings = [" "]*len(black_key_note)
white_keys_bindings = [" "] * len(white_key_note)
black_keys_bindings = [" "] * len(black_key_note)

for i in range(7):
button = tk.Button(
keys_frame, text=f'{white_key_note[i]}\n|{white_keys_bindings[i].replace("odiaeresis", "ö").replace("adiaeresis", "ä")}|', bg='white', width=2, height=6)
button.grid(row=0, column=white_keys[i]+a*12)

def press(event, i=i, a=a): return send_midi_note(
white_keys[i]+a*12, type='note_on')

def release(event, i=i, a=a): return send_midi_note(
white_keys[i]+a*12, type='note_off')
button.bind('<ButtonPress-1>', press)
button.bind('<ButtonRelease-1>', release)
keys_frame,
text=f'{white_key_note[i]}\n|{white_keys_bindings[i].replace("odiaeresis", "ö").replace("adiaeresis", "ä")}|',
bg="white",
width=2,
height=6,
)
button.grid(row=0, column=white_keys[i] + a * 12)

def press(event, button=button, i=i, a=a):
button.config(relief="sunken")
return send_midi_note(white_keys[i] + a * 12, type="note_on")

def release(event, button=button, i=i, a=a):
button.config(relief="raised")
return send_midi_note(white_keys[i] + a * 12, type="note_off")

button.bind("<ButtonPress-1>", press)
button.bind("<ButtonRelease-1>", release)
# Bind the button to a key press event
if white_keys_bindings[i] != " ":
window.bind('<KeyPress-%s>' % white_keys_bindings[i], press)
window.bind('<KeyRelease-%s>' % white_keys_bindings[i], release)
window.bind("<KeyPress-%s>" % white_keys_bindings[i], press)
window.bind("<KeyRelease-%s>" % white_keys_bindings[i], release)

for i in range(5):
button = tk.Button(
keys_frame, text=f'{black_key_note[i]}\n|{black_keys_bindings[i].replace("udiaeresis", "ü")}|', fg='white', bg='black', width=1, height=4)
button.grid(row=0, column=black_keys[i]+a*12, sticky='n')

def press(event, i=i, a=a): return send_midi_note(
black_keys[i]+a*12, type='note_on')

def release(event, i=i, a=a): return send_midi_note(
black_keys[i]+a*12, type='note_off')
button.bind('<ButtonPress-1>', press)
button.bind('<ButtonRelease-1>', release)
keys_frame,
text=f'{black_key_note[i]}\n|{black_keys_bindings[i].replace("udiaeresis", "ü")}|',
fg="white",
bg="black",
width=1,
height=4,
)
button.grid(row=0, column=black_keys[i] + a * 12, sticky="n")

def press(event, button=button, i=i, a=a):
button.config(relief="sunken")
return send_midi_note(black_keys[i] + a * 12, type="note_on")

def release(event, button=button, i=i, a=a):
button.config(relief="raised")
return send_midi_note(black_keys[i] + a * 12, type="note_off")

button.bind("<ButtonPress-1>", press)
button.bind("<ButtonRelease-1>", release)
# Bind the button to a key press event
if white_keys_bindings[i] != " ":
window.bind('<KeyPress-%s>' % black_keys_bindings[i], press)
window.bind('<KeyRelease-%s>' % black_keys_bindings[i], release)
window.bind("<KeyPress-%s>" % black_keys_bindings[i], press)
window.bind("<KeyRelease-%s>" % black_keys_bindings[i], release)


# Run the Tkinter event loop
window.mainloop()

port.panic()
14 changes: 8 additions & 6 deletions audio_stuff/midi/mido_test_in.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@

def listen_midi():
# Open a virtual port for input
midiin = mido.open_input('TEST', virtual=True)

while True:
# Wait for a message and print it
msg = midiin.receive()
print(msg)
default_name = mido.get_input_names()[0]
with mido.open_input(default_name) as midi_in: # 'Digital Piano 2')
i = 0
while True:
for msg in midi_in.iter_pending():
print()
# print(i)
# i += 1


if __name__ == "__main__":
Expand Down
26 changes: 26 additions & 0 deletions audio_stuff/midi/pygame_find_channel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import pygame.midi

pygame.midi.init()


for i in range(pygame.midi.get_count()):
info = pygame.midi.get_device_info(i)
print(
f"Device ID: {i}, Name: {info[1].decode()}, Input: {info[2]}, Output: {info[3]}")


desired_name = "Your MIDI Device Name"
device_id = None

for i in range(pygame.midi.get_count()):
info = pygame.midi.get_device_info(i)
print(info)
if info[1].decode() == desired_name:
device_id = i
break

if device_id is not None:
midi_output = pygame.midi.Output(device_id)
print(f"Selected device ID: {device_id}")
else:
print("Device not found")
28 changes: 28 additions & 0 deletions audio_stuff/midi/stream_file.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import time
import mido
from mido import MidiFile, MidiTrack, Message


def play_channel(midi_file_path, channel_to_play):
midi_file = MidiFile(midi_file_path)
output = mido.open_output('LoopBe Internal MIDI 1')

start_time = time.time()
for track in midi_file.tracks:
current_time = start_time
for msg in track:
if not msg.is_meta and not msg.type == 'sysex':
if msg.channel == channel_to_play:
# Convert time from milliseconds to seconds
time.sleep(msg.time / 1000.0)
print(msg)
mido.Message(msg.type, note=msg.note,
velocity=msg.velocity, channel=0)
output.send(msg)
current_time += msg.time / 1000.0


if __name__ == "__main__":
midi_file_path = str(input("input filename: ")).strip()
channel_to_play = int(input("Enter the channel number to play (0-15): "))
play_channel(midi_file_path, channel_to_play)
Loading
Loading