remi
remi copied to clipboard
[Question/Enhancement] Integration with PyGame
Is it possible to show a PyGame window embedded in a Remi window?
I managed to do this with tkinter so that now a PyGame program is capable of running inside of PySimpleGUI. It would be amazing to see it run in a browser using Remi!
Here is my basic integration between PySimpleGUI (tkinter version) and PyGame https://github.com/PySimpleGUI/PySimpleGUI/blob/master/DemoPrograms/Demo_PyGame_Integration.py
There's really only 3 important lines of code and it only works on Windows for me so far.
embed = graph.TKCanvas
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
os.environ['SDL_VIDEODRIVER'] = 'windib'
I'm also trying to integrate the pyxel project into tkinter and Remi.
Hey! I managed to get this Super Mario Brothers game to run in my PySimpleGUI (tkinter) window!
It would be amazing to get it piped out to a Remi window...
Hello @MikeTheWatchGuy ,
here is an example for you:
import remi.gui as gui
from remi import start, App
import os
import io
from PIL import Image
import threading
import random, math, pygame
from pygame.locals import *
#constants
WINSIZE = [640, 480]
WINCENTER = [320, 240]
NUMSTARS = 150
def init_star():
"creates new star values"
dir = random.randrange(100000)
velmult = random.random()*.6+.4
vel = [math.sin(dir) * velmult, math.cos(dir) * velmult]
return vel, WINCENTER[:]
def initialize_stars():
"creates a new starfield"
stars = []
for x in range(NUMSTARS):
star = init_star()
vel, pos = star
steps = random.randint(0, WINCENTER[0])
pos[0] = pos[0] + (vel[0] * steps)
pos[1] = pos[1] + (vel[1] * steps)
vel[0] = vel[0] * (steps * .09)
vel[1] = vel[1] * (steps * .09)
stars.append(star)
move_stars(stars)
return stars
def draw_stars(surface, stars, color):
"used to draw (and clear) the stars"
for vel, pos in stars:
pos = (int(pos[0]), int(pos[1]))
surface.set_at(pos, color)
def move_stars(stars):
"animate the star values"
for vel, pos in stars:
pos[0] = pos[0] + vel[0]
pos[1] = pos[1] + vel[1]
if not 0 <= pos[0] <= WINSIZE[0] or not 0 <= pos[1] <= WINSIZE[1]:
vel[:], pos[:] = init_star()
else:
vel[0] = vel[0] * 1.05
vel[1] = vel[1] * 1.05
class PILImageViewverWidget(gui.Image):
def __init__(self, pil_image=None, **kwargs):
super(PILImageViewverWidget, self).__init__("/res:logo.png", **kwargs)
self._buf = None
self.index = 0
self.render_done = True
def set_image(self, pil_image):
if not self.render_done:
return
self.render_done = False
self._buf = io.BytesIO()
pil_image.save(self._buf, format='png')
self.refresh()
def refresh(self):
self.attributes['src'] = "/%s/get_image_data?update_index=%d" % (id(self), self.index)
self.index = self.index+1
self.style['background-image'] = "url('/%s/get_image_data?update_index=%d')" % (id(self), self.index)
def get_image_data(self, update_index):
if self._buf is None:
return None
self.render_done = True
self._buf.seek(0)
headers = {'Content-type': 'image/png'}
return [self._buf.read(), headers]
class MyApp(App):
def main(self):
main_container = gui.VBox(width="100%", height="100%", style={'margin':'0px auto'})
#the following image widget will be used to show the PYGAME window content
self.pil_image_viewer = PILImageViewverWidget()
main_container.append(self.pil_image_viewer)
#here we start the thread for pygame
self.t = threading.Thread(target=self.pygame_main)
self.t.start()
return main_container
def pygame_main(self):
"This is the starfield code"
#create our starfield
random.seed()
stars = initialize_stars()
clock = pygame.time.Clock()
#initialize and prepare screen
pygame.init()
screen = pygame.display.set_mode(WINSIZE)
pygame.display.set_caption('pygame Stars Example')
white = 255, 240, 200
black = 20, 20, 40
screen.fill(black)
#main game loop
done = 0
while not done:
draw_stars(screen, stars, black)
move_stars(stars)
draw_stars(screen, stars, white)
pygame.display.update()
for e in pygame.event.get():
if e.type == QUIT or (e.type == KEYUP and e.key == K_ESCAPE):
done = 1
break
elif e.type == MOUSEBUTTONDOWN and e.button == 1:
WINCENTER[:] = list(e.pos)
clock.tick(50)
#>>>>>>>>> here the pygame window gets shown in the REMI widget <<<<<<<<<
surf = pygame.display.get_surface()
data = pygame.image.tostring(surf, 'RGBA')
img = Image.frombytes('RGBA', surf.get_size(), data)
with self.update_lock: #thread sync
self.pil_image_viewer.set_image(img)
if __name__ == "__main__":
start(MyApp, address='0.0.0.0', port=0, start_browser=True, update_interval=0.1, enable_file_cache=True)
WOW you're quick!
That's amazing. Is there a way of not showing the PyGame window. I managed to do it using tkinter in a way that embeds the window and doesn't open the PyGame window. I forgot what line of code I took out that stopped the other window from appearing.
Thank you so much for this code!!
I managed to not display the PyGame window!
I added 2 os.environ calls and after that, only the Remi window shows the game!!!
THIS IS EPIC!!
Here is where I inserted those 2 lines
def pygame_main(self):
"This is the starfield code"
#create our starfield
random.seed()
stars = initialize_stars()
clock = pygame.time.Clock()
#initialize and prepare screen
os.environ['SDL_WINDOWID'] = str(1)
os.environ['SDL_VIDEODRIVER'] = 'windib'
Now "all I have to do" is take your Remi code and translate it into PySimpleGUIWeb code, perhaps using the Widgets I've already got designed, or maybe having to add something new. I don't know yet. Need more studying of how you did this!
Hmmmm.... unlike when I integrated with tkinter, key presses are not being returned to the application. With tkinter, I was able to do another level of integration. This statement:
os.environ['SDL_WINDOWID'] = str(1)
looks like this for the tkinter version:
os.environ['SDL_WINDOWID'] = str(embed.winfo_id())
where embed
is a tkinter Canvas
widget.
Well done @MikeTheWatchGuy and thank you for sharing. In the example I provided you there is really few remi code. The most of the code is from a pygame example.
To integrate keyboard events you should put a listener in the remi window. I will show you soon with an example. ;-)
I figured something like that needed to happen. I already have in PySimpleGUIWeb the provision to return all key presses to the application (it's a flag that's set when the window is created). So that part I'm in good shape for, I think. I don't know how to then route the key presses Remi gives me over to PyGame.
If we show the Super Mario Brothers game running in a browser, perhaps even on Android, it'll be HUGE!
It's crazy this is a possibility!
You've REALLY opened up new possibilities.
When I get code from you, my task is to translate your Remi solution into a PySimpleGUIWeb solution.
This one was a little difficult with the new Image class. I think I managed to use my Image Element to get to the SuperImage Widget that implements it.
When I try to run my code, I only see multiple copies of my logo, the initial image I used to create my Image Element. You did something similar with your logo.
Another difference for me is that the window does not turn black.
There is a method, get_image_data, that isn't getting called directly by the code. That makes me think that Remi is calling it. Perhaps I need to add a "get_image_data" to my SuperImage class that I can replace with the method you supplied?
Here's my code at the moment. I also removed the multithreading part since I multithread Remi already.
import os
import io
from PIL import Image
import threading
import random, math, pygame
from pygame.locals import *
import PySimpleGUIWeb as sg
#constants
WINSIZE = [640, 480]
WINCENTER = [320, 240]
NUMSTARS = 150
def init_star():
"creates new star values"
dir = random.randrange(100000)
velmult = random.random()*.6+.4
vel = [math.sin(dir) * velmult, math.cos(dir) * velmult]
return vel, WINCENTER[:]
def initialize_stars():
"creates a new starfield"
stars = []
for x in range(NUMSTARS):
star = init_star()
vel, pos = star
steps = random.randint(0, WINCENTER[0])
pos[0] = pos[0] + (vel[0] * steps)
pos[1] = pos[1] + (vel[1] * steps)
vel[0] = vel[0] * (steps * .09)
vel[1] = vel[1] * (steps * .09)
stars.append(star)
move_stars(stars)
return stars
def draw_stars(surface, stars, color):
"used to draw (and clear) the stars"
for vel, pos in stars:
pos = (int(pos[0]), int(pos[1]))
surface.set_at(pos, color)
def move_stars(stars):
"animate the star values"
for vel, pos in stars:
pos[0] = pos[0] + vel[0]
pos[1] = pos[1] + vel[1]
if not 0 <= pos[0] <= WINSIZE[0] or not 0 <= pos[1] <= WINSIZE[1]:
vel[:], pos[:] = init_star()
else:
vel[0] = vel[0] * 1.05
vel[1] = vel[1] * 1.05
class PILImageViewverWidget():
def __init__(self, image_elem=None, pil_image=None, **kwargs):
self._buf = None
self.index = 0
self.render_done = True
self.image_elem = image_elem # type: sg.Image
self.image_widget = image_elem.Widget # type: sg.SuperImage
def set_image(self, pil_image):
if not self.render_done:
return
self.render_done = False
self._buf = io.BytesIO()
pil_image.save(self._buf, format='png')
self.refresh()
def refresh(self):
self.image_widget.attributes['src'] = "/%s/get_image_data?update_index=%d" % (id(self.image_widget), self.index)
self.index = self.index+1
self.image_widget.style['background-image'] = "url('/%s/get_image_data?update_index=%d')" % (id(self.image_widget), self.index)
def get_image_data(self, update_index):
if self._buf is None:
return None
self.render_done = True
self._buf.seek(0)
headers = {'Content-type': 'image/png'}
return [self._buf.read(), headers]
def pygame_main():
"This is the starfield code"
#create our starfield
random.seed()
stars = initialize_stars()
clock = pygame.time.Clock()
#initialize and prepare screen
# --------------------- PySimpleGUI window layout and creation --------------------
layout = [[sg.T('Test of PySimpleGUI with PyGame')],
[sg.Image(filename=r'C:\Python\PycharmProjects\GooeyGUI\logo200.png', size=(640, 480), background_color='lightblue', key='_IMAGE_')],
[sg.B('Draw'), sg.Exit()]]
window = sg.Window('PySimpleGUI + PyGame', layout).Finalize()
image_elem = window.Element('_IMAGE_')
pil_image_viewer = PILImageViewverWidget(image_elem)
# -------------- Magic code to integrate PyGame with tkinter -------
os.environ['SDL_WINDOWID'] = str(1)
os.environ['SDL_VIDEODRIVER'] = 'windib'
# pygame.init()
screen = pygame.display.set_mode(WINSIZE)
screen.fill(pygame.Color(255, 255, 255))
pygame.display.init()
pygame.display.update()
pygame.display.set_caption('pygame Stars Example')
white = 255, 240, 200
black = 20, 20, 40
# screen.fill(black)
#main game loop
done = 0
count = 0
while not done:
event, values = window.Read(timeout=10)
print(event, values) if event != sg.TIMEOUT_KEY else None
if event in (None, 'Exit'):
break
draw_stars(screen, stars, black)
move_stars(stars)
draw_stars(screen, stars, white)
pygame.display.update()
for e in pygame.event.get():
print(f'Event = {e}')
if e.type == QUIT or (e.type == KEYUP and e.key == K_ESCAPE):
print('**** FOUND A KEY PRESS!')
done = 1
break
elif e.type == MOUSEBUTTONDOWN and e.button == 1:
print('**** FOUND A MOUSE PRESS!')
WINCENTER[:] = list(e.pos)
clock.tick(50)
#>>>>>>>>> here the pygame window gets shown in the REMI widget <<<<<<<<<
surf = pygame.display.get_surface()
data = pygame.image.tostring(surf, 'RGBA')
img = Image.frombytes('RGBA', surf.get_size(), data)
# with update_lock: #thread sync
pil_image_viewer.set_image(img)
# pil_image_viewer.get_image_data(count)
count +=1
window.Close()
if __name__ == "__main__":
pygame_main()
# t = threading.Thread(target=pygame_main)
# t.start()
Here is what's output:
Oh!! I needed to replace my get_image_data with the one supplied by the app:
image_elem.Widget.get_image_data = pil_image_viewer.get_image_data
After that I got this image!
It looks slow because I'm getting all this logging output. I still haven't figured out how to turn it off all...
IT WORKS!
It runs just as fast as your version :-)
And I do not see a second window!
THIS IS AMAZING!
Check this out.... in my web browser!
Now I need help with 2 things....
- Turning off the warnings that are constantly scrolling.
- Get the keyboard routed to PyGame. With my tkinter port, all that was required was clicking on the image, giving it focus. At the moment, no keys are being sent to PyGame.
This is getting to be really really cool!
@MikeTheWatchGuy here is the version with events (Mouse position is correct) and sound redirection:
import remi.gui as gui
from remi import start, App
import os
import io
from PIL import Image
import threading
import random, math, pygame
from pygame.locals import *
from pygame.mixer import *
from time import sleep
import base64
import wave
#constants
WINSIZE = [640, 480]
WINCENTER = [320, 240]
NUMSTARS = 150
def init_star():
"creates new star values"
dir = random.randrange(100000)
velmult = random.random()*.6+.4
vel = [math.sin(dir) * velmult, math.cos(dir) * velmult]
return vel, WINCENTER[:]
def initialize_stars():
"creates a new starfield"
stars = []
for x in range(NUMSTARS):
star = init_star()
vel, pos = star
steps = random.randint(0, WINCENTER[0])
pos[0] = pos[0] + (vel[0] * steps)
pos[1] = pos[1] + (vel[1] * steps)
vel[0] = vel[0] * (steps * .09)
vel[1] = vel[1] * (steps * .09)
stars.append(star)
move_stars(stars)
return stars
def draw_stars(surface, stars, color):
"used to draw (and clear) the stars"
for vel, pos in stars:
pos = (int(pos[0]), int(pos[1]))
surface.set_at(pos, color)
def move_stars(stars):
"animate the star values"
for vel, pos in stars:
pos[0] = pos[0] + vel[0]
pos[1] = pos[1] + vel[1]
if not 0 <= pos[0] <= WINSIZE[0] or not 0 <= pos[1] <= WINSIZE[1]:
vel[:], pos[:] = init_star()
else:
vel[0] = vel[0] * 1.05
vel[1] = vel[1] * 1.05
class PILImageViewverWidget(gui.Image):
def __init__(self, pil_image=None, **kwargs):
super(PILImageViewverWidget, self).__init__("/res:logo.png", **kwargs)
self._buf = None
self.index = 0
self.render_done = True
def set_image(self, pil_image):
if not self.render_done:
return
self.render_done = False
self._buf = io.BytesIO()
pil_image.save(self._buf, format='png')
self.refresh()
def refresh(self):
self.attributes['src'] = "/%s/get_image_data?update_index=%d" % (id(self), self.index)
self.index = self.index+1
self.style['background-image'] = "url('/%s/get_image_data?update_index=%d')" % (id(self), self.index)
def get_image_data(self, update_index):
if self._buf is None:
return None
self.render_done = True
self._buf.seek(0)
headers = {'Content-type': 'image/png'}
return [self._buf.read(), headers]
app_instance = None
class MyApp(App):
def idle(self):
#THIS CODE ALLOWS TO REDIRECT VIDEO TO REMI
try:
surf = pygame.display.get_surface()
data = pygame.image.tostring(surf, 'RGBA')
img = Image.frombytes('RGBA', surf.get_size(), data)
with self.update_lock: #thread sync
self.pil_image_viewer.set_image(img)
except:
pass
def main(self):
global app_instance
app_instance = self
main_container = gui.VBox(width="100%", height="100%", style={'margin':'0px auto'})
#the following image widget will be used to show the PYGAME window content
self.pil_image_viewer = PILImageViewverWidget(style={})
main_container.append(self.pil_image_viewer)
#I connect keyboard events to the body (the entire page) because the main_container can't get focus in this case, and can't receive these events
self.page.children['body'].onkeydown.connect(self.onkeydown)
self.page.children['body'].onkeyup.connect(self.onkeyup)
#I connect mouse events to the main_container in order to get mouse position relative to this widget
self.pil_image_viewer.onmousemove.connect(self.onmousemove)
self.pil_image_viewer.onmousedown.connect(self.onmousedown)
self.pil_image_viewer.onmouseup.connect(self.onmouseup)
return main_container
def onkeydown(self, emitter, key, keycode, ctrl, shift, alt):
#print("keydown: %s"%keycode)
""" PYGAME COMMON EVENTS
QUIT none
ACTIVEEVENT gain, state
KEYDOWN unicode, key, mod
KEYUP key, mod
MOUSEMOTION pos, rel, buttons
MOUSEBUTTONUP pos, button
MOUSEBUTTONDOWN pos, button
JOYAXISMOTION joy, axis, value
JOYBALLMOTION joy, ball, rel
JOYHATMOTION joy, hat, value
JOYBUTTONUP joy, button
JOYBUTTONDOWN joy, button
VIDEORESIZE size, w, h
VIDEOEXPOSE none
USEREVENT code
"""
#sending event to pygame
ee = pygame.event.Event(KEYDOWN, {'key':int(keycode), 'mod':0})
pygame.event.post(ee)
def onkeyup(self, emitter, key, keycode, ctrl, shift, alt):
#sending event to pygame
ee = pygame.event.Event(KEYUP, {'key':int(keycode), 'mod':0})
pygame.event.post(ee)
def onmousemove(self, emitter, x, y):
ee = pygame.event.Event(MOUSEMOTION, {'pos':(int(float(x)),int(float(y))), 'buttons':(False, False, False)})
pygame.event.post(ee)
def onmousedown(self, emitter, x, y):
ee = pygame.event.Event(MOUSEBUTTONDOWN, {'pos':(int(float(x)),int(float(y))), 'button':1})
pygame.event.post(ee)
def onmouseup(self, emitter, x, y):
ee = pygame.event.Event(MOUSEBUTTONUP, {'pos':(int(float(x)),int(float(y))), 'button':1})
pygame.event.post(ee)
def pygame_main():
"This is the starfield code"
#create our starfield
random.seed()
stars = initialize_stars()
clock = pygame.time.Clock()
#initialize and prepare screen
pygame.init()
screen = pygame.display.set_mode(WINSIZE)
pygame.display.set_caption('pygame Stars Example')
white = 255, 240, 200
black = 20, 20, 40
screen.fill(black)
#main game loop
done = 0
while not done:
draw_stars(screen, stars, black)
move_stars(stars)
draw_stars(screen, stars, white)
pygame.display.update()
for e in pygame.event.get():
if e.type == QUIT or (e.type == KEYUP and e.key == K_ESCAPE):
#>>>>>>>>>>sound<<<<<<<<<<<
pre_init(44100, -16, 1, 1024)
pygame.init()
snd = pygame.mixer.Sound("./Alarm01.wav")
snd.play(-1)
sleep(5)
done = 1
break
elif e.type == MOUSEBUTTONDOWN and e.button == 1:
WINCENTER[:] = list(e.pos)
clock.tick(50)
#THIS CODE ALLOWS TO REDIRECT AUDIO TO REMI, place this after the App class
SND = pygame.mixer.Sound
class SoundProxy(pygame.mixer.Sound):
def play(self, *args, **kwargs):
global app_instance
raw = self.get_raw()
sio = io.BytesIO()
sfile = wave.open(sio, 'w')
frequency, _format, channels = pygame.mixer.get_init()
# write raw PyGame sound buffer to wave file
sfile.setframerate(frequency)
sfile.setnchannels(channels)
sfile.setsampwidth(2)
sfile.writeframesraw(raw)
sfile.close()
sio.seek(0)
data = "function beep(data) {var snd = new Audio(data); snd.play();}; beep('%s');"%("data:audio/wav;base64,%s"%base64.b64encode(sio.read()))
with app_instance.update_lock:
app_instance.execute_javascript(data)
return SND.play(self, *args, **kwargs)
pygame.mixer.Sound = SoundProxy
Sound = SoundProxy
if __name__ == "__main__":
#here we start the thread for pygame
t = threading.Thread(target=pygame_main)
t.start()
start(MyApp, address='0.0.0.0', port=8081, start_browser=True, update_interval=0.01, enable_file_cache=True, multiple_instance=True)
have a good development ;-)
Man, I just saw this thread, and I can only say that your support @dddomodossola is amazing and the work you are doing here is super cool!
@awesomebytes Thank you a lot Sam :D
@dddomodossola please format code samples on your comments. like
| ```python
| Your code here...
| ```
import remi.gui as gui
from remi import start, App
import os
import io
from PIL import Image
import threading
import random, math, pygame
from pygame.locals import *
from pygame.mixer import *
from time import sleep
import base64
import wave
#constants
WINSIZE = [640, 480]
WINCENTER = [320, 240]
NUMSTARS = 150
def init_star():
"creates new star values"
dir = random.randrange(100000)
velmult = random.random()*.6+.4
vel = [math.sin(dir) * velmult, math.cos(dir) * velmult]
return vel, WINCENTER[:]
def initialize_stars():
"creates a new starfield"
stars = []
for x in range(NUMSTARS):
star = init_star()
vel, pos = star
steps = random.randint(0, WINCENTER[0])
pos[0] = pos[0] + (vel[0] * steps)
pos[1] = pos[1] + (vel[1] * steps)
vel[0] = vel[0] * (steps * .09)
vel[1] = vel[1] * (steps * .09)
stars.append(star)
move_stars(stars)
return stars
def draw_stars(surface, stars, color):
"used to draw (and clear) the stars"
for vel, pos in stars:
pos = (int(pos[0]), int(pos[1]))
surface.set_at(pos, color)
def move_stars(stars):
"animate the star values"
for vel, pos in stars:
pos[0] = pos[0] + vel[0]
pos[1] = pos[1] + vel[1]
if not 0 <= pos[0] <= WINSIZE[0] or not 0 <= pos[1] <= WINSIZE[1]:
vel[:], pos[:] = init_star()
else:
vel[0] = vel[0] * 1.05
vel[1] = vel[1] * 1.05
class PILImageViewverWidget(gui.Image):
def __init__(self, pil_image=None, **kwargs):
super(PILImageViewverWidget, self).__init__("/res:logo.png", **kwargs)
self._buf = None
self.index = 0
self.render_done = True
def set_image(self, pil_image):
if not self.render_done:
return
self.render_done = False
self._buf = io.BytesIO()
pil_image.save(self._buf, format='png')
self.refresh()
def refresh(self):
self.attributes['src'] = "/%s/get_image_data?update_index=%d" % (id(self), self.index)
self.index = self.index+1
self.style['background-image'] = "url('/%s/get_image_data?update_index=%d')" % (id(self), self.index)
def get_image_data(self, update_index):
if self._buf is None:
return None
self.render_done = True
self._buf.seek(0)
headers = {'Content-type': 'image/png'}
return [self._buf.read(), headers]
app_instance = None
class MyApp(App):
def idle(self):
#THIS CODE ALLOWS TO REDIRECT VIDEO TO REMI
try:
surf = pygame.display.get_surface()
data = pygame.image.tostring(surf, 'RGBA')
img = Image.frombytes('RGBA', surf.get_size(), data)
with self.update_lock: #thread sync
self.pil_image_viewer.set_image(img)
except:
pass
def main(self):
global app_instance
app_instance = self
main_container = gui.VBox(width="100%", height="100%", style={'margin':'0px auto'})
#the following image widget will be used to show the PYGAME window content
self.pil_image_viewer = PILImageViewverWidget(style={})
main_container.append(self.pil_image_viewer)
#I connect keyboard events to the body (the entire page) because the main_container can't get focus in this case, and can't receive these events
self.page.children['body'].onkeydown.connect(self.onkeydown)
self.page.children['body'].onkeyup.connect(self.onkeyup)
#I connect mouse events to the main_container in order to get mouse position relative to this widget
self.pil_image_viewer.onmousemove.connect(self.onmousemove)
self.pil_image_viewer.onmousedown.connect(self.onmousedown)
self.pil_image_viewer.onmouseup.connect(self.onmouseup)
return main_container
def onkeydown(self, emitter, key, keycode, ctrl, shift, alt):
#print("keydown: %s"%keycode)
""" PYGAME COMMON EVENTS
QUIT none
ACTIVEEVENT gain, state
KEYDOWN unicode, key, mod
KEYUP key, mod
MOUSEMOTION pos, rel, buttons
MOUSEBUTTONUP pos, button
MOUSEBUTTONDOWN pos, button
JOYAXISMOTION joy, axis, value
JOYBALLMOTION joy, ball, rel
JOYHATMOTION joy, hat, value
JOYBUTTONUP joy, button
JOYBUTTONDOWN joy, button
VIDEORESIZE size, w, h
VIDEOEXPOSE none
USEREVENT code
"""
#sending event to pygame
ee = pygame.event.Event(KEYDOWN, {'key':int(keycode), 'mod':0})
pygame.event.post(ee)
def onkeyup(self, emitter, key, keycode, ctrl, shift, alt):
#sending event to pygame
ee = pygame.event.Event(KEYUP, {'key':int(keycode), 'mod':0})
pygame.event.post(ee)
def onmousemove(self, emitter, x, y):
ee = pygame.event.Event(MOUSEMOTION, {'pos':(int(float(x)),int(float(y))), 'buttons':(False, False, False)})
pygame.event.post(ee)
def onmousedown(self, emitter, x, y):
ee = pygame.event.Event(MOUSEBUTTONDOWN, {'pos':(int(float(x)),int(float(y))), 'button':1})
pygame.event.post(ee)
def onmouseup(self, emitter, x, y):
ee = pygame.event.Event(MOUSEBUTTONUP, {'pos':(int(float(x)),int(float(y))), 'button':1})
pygame.event.post(ee)
def pygame_main():
"This is the starfield code"
#create our starfield
random.seed()
stars = initialize_stars()
clock = pygame.time.Clock()
#initialize and prepare screen
pygame.init()
screen = pygame.display.set_mode(WINSIZE)
pygame.display.set_caption('pygame Stars Example')
white = 255, 240, 200
black = 20, 20, 40
screen.fill(black)
#main game loop
done = 0
while not done:
draw_stars(screen, stars, black)
move_stars(stars)
draw_stars(screen, stars, white)
pygame.display.update()
for e in pygame.event.get():
if e.type == QUIT or (e.type == KEYUP and e.key == K_ESCAPE):
#>>>>>>>>>>sound<<<<<<<<<<<
pre_init(44100, -16, 1, 1024)
pygame.init()
snd = pygame.mixer.Sound("./Alarm01.wav")
snd.play(-1)
sleep(5)
done = 1
break
elif e.type == MOUSEBUTTONDOWN and e.button == 1:
WINCENTER[:] = list(e.pos)
clock.tick(50)
#THIS CODE ALLOWS TO REDIRECT AUDIO TO REMI, place this after the App class
SND = pygame.mixer.Sound
class SoundProxy(pygame.mixer.Sound):
def play(self, *args, **kwargs):
global app_instance
raw = self.get_raw()
sio = io.BytesIO()
sfile = wave.open(sio, 'w')
frequency, _format, channels = pygame.mixer.get_init()
# write raw PyGame sound buffer to wave file
sfile.setframerate(frequency)
sfile.setnchannels(channels)
sfile.setsampwidth(2)
sfile.writeframesraw(raw)
sfile.close()
sio.seek(0)
data = "function beep(data) {var snd = new Audio(data); snd.play();}; beep('%s');"%("data:audio/wav;base64,%s"%base64.b64encode(sio.read()))
with app_instance.update_lock:
app_instance.execute_javascript(data)
return SND.play(self, *args, **kwargs)
pygame.mixer.Sound = SoundProxy
Sound = SoundProxy
if __name__ == "__main__":
#here we start the thread for pygame
t = threading.Thread(target=pygame_main)
t.start()
start(MyApp, address='0.0.0.0', port=8081, start_browser=True, update_interval=0.01, enable_file_cache=True, multiple_instance=True)