0

I'm on python2-7 I want to get a button in tkinter which stop the reading of the notes created with fluidsynth.

I found that the common solution is to use time.after like here: How do you create a Tkinter GUI stop button to break an infinite loop?

But in my case I can't use it because I need an amount of time between noteon and noteoff to give durations for my notes. Moreover I want to play the notes ONLY if I click on start (and no at the beginning like the solution in the link).

So I created this code but it doesn't work because var_start is always initialized as int:

from tkinter import*
import fluidsynth
import time

fs=fluidsynth.Synth()
fs.start(driver='alsa', midi_driver='alsa_seq')
org_charge = fs.sfload("organ.sf2")
fs.program_select(0,org_charge, 0, 0)
time.sleep(1)

var_start=int

def start():
    global var_start
    var_start=1

def stop():
    global var_start
    var_start=0

root=Tk()

if var_start==1:
    fs.noteon(0,67,127)
    time.sleep(1)
    fs.noteoff(0,67)
    fs.noteon(0,71,127)
    time.sleep(1)
    fs.noteoff(0,71)
    fs.noteon(0,74,127)
    time.sleep(1)
    fs.noteoff(0,74)

Button(root, text='start', command= start).pack(padx=10, pady=10)    
Button(root, text='stop', command= stop).pack(padx=10, pady=10)    

root.mainloop()

I don't have other idea to reshape my code... Can someone help me ?

Thanks

1 Answers1

0

You initiated var_start to int in statement var_start=int and so the code block in if var_start==1: will never be executed. And your start() function is just changing the var_start to 1 and never start playing the notes, therefore nothing will happen.

Never call time.sleep() in main thread as it will block the tkinter main loop. You can use .after(...) to simulate the play loop and below is a sample code block:

playing = False

def play_notes(notes, index, noteoff):
    global playing
    if noteoff:
        fs.noteoff(0, notes[index])
        index += 1      # next note
    if playing and index < len(notes):
        fs.noteon(0, notes[index], 127)
        # call noteoff one second later
        root.after(1000, play_notes, notes, index, True)
    else:
        # either stopped or no more note to play
        playing = False
        print('done playing')

def start_playing():
    global playing
    if not playing:
        print('start playing')
        playing = True
        notes = [67, 71, 74, 88, 80, 91]
        play_notes(notes, 0, False)
    else:
        print('already playing')

def stop_playing():
    global playing
    if playing:
        playing = False
        print('stop playing')
    else:
        print('nothing playing')

Button(root, text='Start', command=start_playing).pack(padx=10, pady=10)
Button(root, text='Stop', command=stop_playing).pack(padx=10, pady=10)

It is just an example you can modify to suit your need.

acw1668
  • 40,144
  • 5
  • 22
  • 34