Skip to content

Commit

Permalink
adding (not working yet) webrequests.py. bleep is fixed. upping amy. …
Browse files Browse the repository at this point in the history
…tested desktop(mac) and esp.
  • Loading branch information
bwhitman committed Nov 23, 2024
1 parent 72c52ce commit d721921
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 44 deletions.
2 changes: 1 addition & 1 deletion amy
Submodule amy updated 2 files
+2 −2 README.md
+8 −4 src/amy.c
5 changes: 0 additions & 5 deletions tulip/shared/alles.c
Original file line number Diff line number Diff line change
Expand Up @@ -222,8 +222,6 @@ void run_alles() {

esp_amy_init();
amy_reset_oscs();
// Schedule a "turning on" sound
bleep();
//
// Spin this core until the power off button is pressed, parsing events and making sounds
//while(status & RUNNING) {
Expand All @@ -238,9 +236,6 @@ void * alles_start(void *vargs) {
alles_local_ip[0] = 0;
unix_amy_init();
amy_reset_oscs();
// Schedule a "turning on" sound
// We don't do this by default on tulip desktop as all threads start at once and it makes the bleep sound bad
bleep();
// Spin this core until the power off button is pressed, parsing events and making sounds
while(status & RUNNING) {
delay_ms(10);
Expand Down
17 changes: 10 additions & 7 deletions tulip/shared/py/_boot.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import gc
import uos
import tulip, sys, midi, amy, alles
if(tulip.board()!="WEB"):
import world
import tulip, sys, midi, amy, alles, world
from upysh import *
from tulip import edit, run

Expand Down Expand Up @@ -62,9 +60,14 @@
cd(tulip.app_path())

gc.collect()
# Override amy's send to work with tulip
if(tulip.board()!="WEB"):
amy.override_send = lambda x: tulip.alles_send(x, alles.mesh_flag)
midi.setup()

# Set up audio/midi.
if(tulip.board() == "WEB"):
midi.setup()
# Override send & bleep are done from JS on web because of click-to-start audio.
else:
# Override amy's send to work with tulip
amy.override_send = lambda x: tulip.alles_send(x, alles.mesh_flag)
midi.setup()
midi.startup_bleep()

13 changes: 12 additions & 1 deletion tulip/shared/py/midi.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ def add_synth_object(self, channel, synth_object):
def add_synth(self, channel=1, patch_number=0, num_voices=6):
if channel == 10:
synth_object = DrumSynth(num_voices=num_voices)
elif channel == 16:
synth_object = OscSynth(num_voices=1) # the "system bleep" synth
else:
synth_object = Synth(num_voices=num_voices, patch_number=patch_number)
self.add_synth_object(channel, synth_object)
Expand Down Expand Up @@ -485,8 +487,9 @@ def ensure_midi_config():
if not config:
# Tulip defaults, 6 note polyphony on channel 1
# drum machine always on channel 10
# utility sine wave bleeper on channel 16
config = MidiConfig(
voices_per_channel={1: 6, 10: 10},
voices_per_channel={1: 6, 10: 10, 16: 1},
patch_per_channel={1: 0},
show_warnings=True,
)
Expand Down Expand Up @@ -665,6 +668,14 @@ def c_fired_midi_event(x):

m = tulip.midi_in()

# Resets AMY timebase and plays the bleep
def startup_bleep():
amy.send(reset=amy.RESET_TIMEBASE)
if 16 in config.synth_per_channel:
config.synth_per_channel[16].note_on(57, 1, time=0)
config.synth_per_channel[16].note_on(69, 1, time=150)
config.synth_per_channel[16].note_off(69, time=300)


def deferred_midi_config(t):
setup_midi_codes()
Expand Down
142 changes: 142 additions & 0 deletions tulip/shared/py/webrequests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# webrequests.py
# javascript version (as much as we can) of urequests.py


import json
import js

def as_bytearray(buffer):
"""
Given a JavaScript ArrayBuffer, convert it to a Python bytearray in a
MicroPython friendly manner.
"""
ui8a = js.Uint8Array.new(buffer)
size = ui8a.length
ba = bytearray(size)
for i in range(0, size):
ba[i] = ui8a[i]
return ba

### wrap the response to grant Pythonic results
class _Response:
def __init__(self, response):
self._response = response

# grant access to response.ok and other fields
def __getattr__(self, attr):
return getattr(self._response, attr)

# exposed methods with Pythonic results
async def arrayBuffer(self):
buffer = await self._response.arrayBuffer()
# works in Pyodide
if hasattr(buffer, "to_py"):
return buffer.to_py()
# shims in MicroPython
return memoryview(as_bytearray(buffer))

async def blob(self):
return await self._response.blob()

async def bytearray(self):
buffer = await self._response.arrayBuffer()
return as_bytearray(buffer)

async def json(self):
return json.loads(await self.text())

async def text(self):
return await self._response.text()


### allow direct await to _Response methods
class _DirectResponse:
@staticmethod
def setup(promise, response):
promise._response = _Response(response)
return promise._response

def __init__(self, promise):
self._promise = promise
promise._response = None
promise.arrayBuffer = self.arrayBuffer
promise.blob = self.blob
promise.bytearray = self.bytearray
promise.json = self.json
promise.text = self.text

async def _response(self):
if not self._promise._response:
await self._promise
return self._promise._response

async def arrayBuffer(self):
response = await self._response()
return await response.arrayBuffer()

async def blob(self):
response = await self._response()
return await response.blob()

async def bytearray(self):
response = await self._response()
return await response.bytearray()

async def json(self):
response = await self._response()
return await response.json()

async def text(self):
response = await self._response()
return await response.text()


def fetch(url, **kw):
# workaround Pyodide / MicroPython dict <-> js conversion
options = js.JSON.parse(json.dumps(kw))
awaited = lambda response, *args: _DirectResponse.setup(promise, response)
promise = js.fetch(url, options).then(awaited)
_DirectResponse(promise)
return promise


"""
def get(url):
import js
print(f"fetching {url}...")
res = await js.fetch(url)
json = await res.json()
for i in dir(json):
print(f"{i}: {json[i]}")
return json
#def get(url, headers = {}):
# return await js.fetch(url, method='GET', headers=headers)
json = await res.json()
response = requests.get(base_url+"messages?limit=%d" % (chunk_size), headers = headers)
response = requests.get(base_url+"messages?limit=%d&before=%s" % (chunk_size, oldest_id), headers=headers)
api_response = requests.post(
files_base_url+"attachments",
headers=headers,
json={"files": [{"filename": filename, "file_size": filesize, "id": 1}]},
)
put_response = requests.put(
put_url,
headers={
"Authorization": headers['Authorization'],
"User-Agent": headers['User-Agent'],
"Content-Length": str(filesize),
"Content-Type": "application/octet-stream",
},
data=f,
)
r = requests.post(files_base_url+"messages", headers = headers, data = json.dumps(payload))
r = requests.post(text_base_url+"messages", headers = headers, data = json.dumps ( {"content":u + " ### " + message} ))
"""
7 changes: 4 additions & 3 deletions tulip/web/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,11 @@ The tulip "sys" files will load into `/tulip4/sys`. `/tulip4/user` is there for
- ~~sync my AMY changes to main AMY~~
- ~~build in release.sh~~
- ~~speed of LVGL object creation(?) (try `run('drums')`)~~
- startup bleep (and fix the juno bleep on macos desktop!)
- ~~startup bleep (and fix the juno bleep on macos desktop!)~~
- ~~test changes on tulip desktop mac / linux and tulip cc~~
- "sockets"/web requests - tulip world etc
- some solution for `time.sleep` / `sleep_ms` -- see `parallax`, `bunny_bounce`, `xanadu`
- test changes on tulip desktop mac / linux and tulip cc
- test github hosting on tulip.computer/
- resizeable/responsive SDL canvas

- maybe some simple intro HOWTO on the page

2 changes: 1 addition & 1 deletion tulip/web/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class CORSRequestHandler (SimpleHTTPRequestHandler):
def end_headers (self):
self.send_header('Access-Control-Allow-Origin', '*')
self.send_header('Cross-Origin-Embedder-Policy', 'require-corp')
#self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
self.send_header('Cross-Origin-Opener-Policy', 'same-origin')
SimpleHTTPRequestHandler.end_headers(self)

if __name__ == '__main__':
Expand Down
Binary file modified www/run/amy.wasm
Binary file not shown.
Loading

0 comments on commit d721921

Please sign in to comment.