0

Ok, maybe I'm missing something about the way PyGame registers input.

My problem is when the snooze() method leaves it's audio loop and calls alarm(getup_file) or alarm(alarm_file), it enters the alarm() audio loop and then immediately calls snooze() again without any keys being pressed. This only occurs if I have already hit the space bar during the initial audio loop calling snooze() at some point but not if I start with a call to snooze() initially never having the space bar pressed.

Here is my simple alarm script.

#!/usr/bin/env python3

import schedule, subprocess, time, os, sys
import pygame as pg


if len(sys.argv) > 1:
    x = int(sys.argv[1]) - 140
    y = int(sys.argv[2]) - 190
    os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (x,y)
else:
    x=50
    y=50
    
pg.init()
pg.display.set_mode((100,100))

alarm_file = "/home/pi/Alarm/keelhauled.mp3"
getup_file = "/home/pi/Alarm/witness.mp3"
dream_track = "/home/pi/Alarm/dreamtrack.mp3"
snoozed = 0
volume = 0.08

def get_up():
    currentTime = (int(time.strftime("%H", time.localtime())) * 100) + (int(time.strftime("%M", time.localtime())))

    if currentTime > 650:
        return True

def snooze():
    global snoozed
    snoozed += 1
    #time.sleep(270)
    #Replaced time.sleep(270) with audio loop starting here
    snoozeTime = (int(time.strftime("%H", time.localtime())) * 100) + (int(time.strftime("%M", time.localtime())))
    pg.mixer.music.set_volume(1.0)
    clock = pg.time.Clock()
    try:
        pg.mixer.music.load(dream_track)
        print("Music file %s loaded!" % dream_track)
    except pg.error:
        print("File %s not found! (%s)" % (dream_track, pg.get_error()))
        return
    pg.mixer.music.play()
    while pg.mixer.music.get_busy():
        elapsedTime = (int(time.strftime("%H", time.localtime())) * 100) + (int(time.strftime("%M", time.localtime())))
        if abs(snoozeTime - elapsedTime) > 0:
            pg.mixer.music.stop()
            break  
        clock.tick(30)
    time.sleep(1) #Added to see if the delay would change anything... it did not
    """for event in pg.event.get():
        if event.type == pg.KEYDOWN or event.type == pg.KEYUP:
            if event.key == pg.K_SPACE:
                print("I hit space again for you")
                return"""
    #And ending here
    if get_up():
        alarm(getup_file) #3. After snooze loop exits, alarm() is called again(no input)
        return
    elif snoozed > 1:
        pg.mixer.music.set_volume(0.75)
    else:
        pg.mixer.music.set_volume(0.5)
    alarm(alarm_file) #3. Same issue when called here, not that I'm surprised

def alarm(music_file):
    print("Starting Alarm Procedure")
    clock = pg.time.Clock()
    try:
        pg.mixer.music.load(music_file)
        print("Music file %s loaded!" % music_file)
    except pg.error:
        print("File %s not found! (%s)" % (music_file, pg.get_error()))
        return
    pg.mixer.music.play()
    while pg.mixer.music.get_busy():
        for event in pg.event.get():
            if event.type == pg.KEYDOWN or event.type == pg.KEYUP:
                if event.key == pg.K_SPACE: #2. Space Bar is pressed and snooze() is called on initial loop
                    pg.mixer.music.stop()
                    snooze() #4. Called immediately when entering loop? Where is the input coming from??
                    return
                if event.key == pg.K_ESCAPE:
                    raise SystemExit
                if event.key == pg.K_RETURN:
                    pg.mixer.music.stop()
                    return
        # check if playback has finished
        clock.tick(30)
    alarm(music_file)

def InitMixer():
    # set up the mixer
    freq = 44100     # audio CD quality
    bitsize = -16    # unsigned 16 bit
    channels = 2     # 1 is mono, 2 is stereo
    buffer = 2048    # number of samples (experiment to get right sound)
    pg.mixer.init(freq, bitsize, channels, buffer)

def job():
    InitMixer()
    # optional volume 0 to 1.0
    pg.mixer.music.set_volume(0.5)
    alarm(alarm_file) #1. Initial call for alarm() started by schedule
    #snooze() #If I comment out the call to alarm() before this and uncomment this it works fine

schedule.every().friday.at('13:40').do(job)

while True:
    schedule.run_pending()
    for event in pg.event.get():
            if event.type == pg.KEYDOWN or event.type == pg.KEYUP:
                if event.key == pg.K_ESCAPE:
                    raise SystemExit
    time.sleep(1)
print("Oops!  End of Script reached.")

Until now this was working fine, I added the audio loop to snooze() and it started. Any help would be greatly appreciated because I'm lost at this point. As far as I can see there is no reason snooze() should be being called.

Edit:

For testing purposes I added:

for event in pg.event.get():
        if event.type == pg.KEYDOWN or event.type == pg.KEYUP:
            if event.key == pg.K_SPACE:
                print("I hit space again for you")
                return

to snooze() directly following time.sleep(1) and it shows it is definitely seeing the space bar. Why? Is event not on a frame by frame basis? Does it register keydown on the frame space is pressed and then keyup on a later frame?

ClaudiaR
  • 3,108
  • 2
  • 13
  • 27
  • first you could use `print()` to see what you have in variables. Maybe there is some space in variable. Maybe system send some event with delay. Or maybe your keyboard is broken and it sends spaces. `pygame` uses queue to keep all keys pressed in other moments and later `event.get()` may get it. You may try to clear `event.clear()` this queue. – furas Feb 18 '22 at 21:04
  • BTW: it is not good idea to run `event.get()` in two palces because it can make conflict which `event.get()` gets event from system. You may expect that it will get event in one function but it may get it in another function which will check different keys. You may try to `event.clear()` before every `for event` loop. – furas Feb 18 '22 at 21:09
  • Is event not on a frame by frame basis? - NO Does it register keydown on the frame space is pressed and then keyup on a later frame? - YES – KingInYellow Feb 18 '22 at 21:30
  • How do you suppose I would run event.get() in 1 place? If I were to put it into a variable it would only contain what events transpired to the point of initializing the variable, so how do you only call event.get() once? – KingInYellow Feb 18 '22 at 21:37
  • On a side note, for everyone more or less. Answer direct questions asked in posts. If a direct question has been asked, it is usually a key piece of information required. I've said this before, I personally do not post to have someone solve a problem for me, I post to seek further information. – KingInYellow Feb 18 '22 at 21:56
  • system (Windows, Linux, MacOS) catchs key/mouse events and puts on queue - and later PyGame gets then from this queue. They don't depend on frames. You may press keys before `event.get()` and they will wait until you get them using `event.get()`. If you use two `event.get()` and first doesn't get all events then second `event.get()` will get them. This way if you press button after it finish first event loop but before second second event loop then second loop can get it but it may looks like you pressed it when previous loop was still working. As for me `event.clear()` may helps in this. – furas Feb 18 '22 at 23:42
  • I didn't analize all your code but I saw two `event.get()` and in many questions before I saw similar problems because someone used two `event.get()`. He expect that first `event.get()` will get all keys for one scene and second `event.get()` will get different keys for different scene but some keys was pressed when first scene was still displayed but `event.get()` wasn't running so keys was catched by `event.get()` in next scene. – furas Feb 18 '22 at 23:48
  • On a side note, it is place for comments which don't have to answer direct question. They may suggest some idea related with question - or even not related with question. – furas Feb 18 '22 at 23:49

0 Answers0