setup flask app and test with socketIO

master
km0 3 years ago
parent 33924f28d7
commit 5126b5d5af

3
.gitignore vendored

@ -0,0 +1,3 @@
venv/
__pycache__
.env

@ -0,0 +1,3 @@
{
"python.formatting.provider": "black"
}

@ -0,0 +1,6 @@
import os
class Config(object):
DEBUG = False
FLASK_APP = os.environ.get('FLASK_APP')
FLASK_ENV = os.environ.get('FLASK_ENV')

Before

Width:  |  Height:  |  Size: 288 KiB

After

Width:  |  Height:  |  Size: 288 KiB

Before

Width:  |  Height:  |  Size: 346 KiB

After

Width:  |  Height:  |  Size: 346 KiB

Before

Width:  |  Height:  |  Size: 33 KiB

After

Width:  |  Height:  |  Size: 33 KiB

Before

Width:  |  Height:  |  Size: 385 KiB

After

Width:  |  Height:  |  Size: 385 KiB

@ -1,17 +1,17 @@
# Skimmer: multi-channel & displaced muzik # Skimmer: multi-channel & displaced muzik
![cover with the skimmer](cover.jpg) ![cover with the skimmer](img/cover.jpg)
The Skimmer is a container for experiments on multi-channel and displaced sound works, developed in the context of SI18. The main concept is a system that streams to various connected clients, using them as speakers. Unlike classical broadcast transmissions where everyone receive the same signal, here each client is an individual channel. In doing so, the Skimmer can have as many channels as many clients are connected. This opens interesting spatial and expressive possibilities that I would like to explore. The Skimmer is a container for experiments on multi-channel and displaced sound works, developed in the context of SI18. The main concept is a system that streams to various connected clients, using them as speakers. Unlike classical broadcast transmissions where everyone receive the same signal, here each client is an individual channel. In doing so, the Skimmer can have as many channels as many clients are connected. This opens interesting spatial and expressive possibilities that I would like to explore.
To rely on connected clients and the public as a founding part of the instrument raises questions about instability and contingency in both composition and design. What does it mean for the public to host the instrument, and what does it mean for the performer to be hosted by the public? Which kind of politics and relations are generated? To rely on connected clients and the public as a founding part of the instrument raises questions about instability and contingency in both composition and design. What does it mean for the public to host the instrument, and what does it mean for the performer to be hosted by the public? Which kind of politics and relations are generated?
The Skimmer works with a lightweight setup: a server application links together a source and the connected clients. Instead of streaming the audio directly from the source to the server, what is shared is a model to generate the sounds. With this approach the stream consists in just messages for modulating the instrument on each client, and the traffic it is super light. This require a sound design oriented to the specs of the clients. The Skimmer works with a lightweight setup: a server application links together a source and the connected clients. Instead of streaming the audio directly from the source to the server, what is shared is a model to generate the sounds. With this approach the stream consists in just messages for modulating the instrument on each client, and the traffic it is super light. This require a sound design oriented to the specs of the clients.
![skimming the notes](clients.jpg) ![skimming the notes](img/clients.jpg)
## Structure ## Structure
![structure with a pot](structure.jpg) ![structure with a pot](img/structure.jpg)
This setup is made by three main parts: This setup is made by three main parts:
@ -30,7 +30,7 @@ The source is the instrument that the server and clients share. The recipe of th
- The handle will be maybe something similar to the [modular spaghetti interface](https://git.xpub.nl/kamo/spaghetti)? (not sure yet, but i like the idea of drawing connections between the source and the clients) - The handle will be maybe something similar to the [modular spaghetti interface](https://git.xpub.nl/kamo/spaghetti)? (not sure yet, but i like the idea of drawing connections between the source and the clients)
- The sift will be a little server in the Soupboat, not sure yet if with node.js and express (pro: all JS pipeline) or flask (pro: mixed pipeline and familiar pattern) - The sift will be a little server in the Soupboat, not sure yet if with node.js and express (pro: all JS pipeline) or flask (pro: mixed pipeline and familiar pattern)
![spaghetti setup](spaghetti.jpg) ![spaghetti setup](img/spaghetti.jpg)
Prototype of the spaghetti cables interface Prototype of the spaghetti cables interface
### Process ### Process

@ -0,0 +1,22 @@
bidict==0.22.0
black==22.3.0
click==8.1.2
colorama==0.4.4
dnspython==2.2.1
eventlet==0.33.0
Flask==2.1.1
Flask-SocketIO==5.1.1
greenlet==1.1.2
itsdangerous==2.1.2
Jinja2==3.1.1
Mako==1.2.0
MarkupSafe==2.1.1
mypy-extensions==0.4.3
pathspec==0.9.0
platformdirs==2.5.1
python-dotenv==0.20.0
python-engineio==4.3.1
python-socketio==5.5.2
six==1.16.0
tomli==2.0.1
Werkzeug==2.1.1

@ -0,0 +1,47 @@
import os
from flask import Flask, send_from_directory
from flask_socketio import SocketIO
from . import prefix
socketio = SocketIO()
def create_app(test_config=None):
# Create and configure the Flask App
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(
SECRET_KEY="dev",
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile("config.py", silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
@app.route("/favicon.ico")
def favicon():
return send_from_directory(
os.path.join(app.root_path, "static"),
"favicon.ico",
mimetype="image/vnd.microsoft.icon",
)
from . import bowl
app.register_blueprint(bowl.bp)
app.wsgi_app = prefix.PrefixMiddleware(
app.wsgi_app, prefix=os.environ.get("URL_PREFIX", "")
)
socketio.init_app(app)
return app

@ -0,0 +1,11 @@
from flask import Blueprint
from mako.template import Template
from . import events
bp = Blueprint("bowl", __name__)
@bp.route("/")
def bowl():
return Template(filename="skimmer/templates/bowl.html").render()

@ -0,0 +1,10 @@
from flask import session
from flask_socketio import emit
from . import socketio
@socketio.on("my event")
def test(message):
print(message)
emit("message", {"msg": "eheh"})

@ -0,0 +1,14 @@
class PrefixMiddleware(object):
def __init__(self, app, prefix=""):
self.app = app
self.prefix = prefix
def __call__(self, environ, start_response):
if environ["PATH_INFO"].startswith(self.prefix):
environ["PATH_INFO"] = environ["PATH_INFO"][len(self.prefix) :]
environ["SCRIPT_NAME"] = self.prefix
return self.app(environ, start_response)
else:
start_response("404", [("Content-Type", "text/plain")])
return ["This url does not belong to the app.".encode()]

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"
integrity="sha512-q/dWJ3kcmjBLU4Qc47E4A9kTB4m3wuTY7vkFJDTZKjTs8jhyGQnaUrxa0Ytd0ssMZhbNua9hE+E7Qv1j+DyZwA=="
crossorigin="anonymous"
></script>
<script type="text/javascript" charset="utf-8">
var socket = io();
socket.on("connect", function () {
socket.emit("my event", { data: "I'm connected!" });
});
</script>
</head>
<body>
Hello Bonjur
</body>
</html>

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>🍲 Skimmer - Pot</title>
<link rel="stylesheet" href="style.css" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.38/Tone.js"></script>
<script src="index.js" defer></script>
</head>
<body>
<button id="start">Start</button>
<label for="bpm">BPM</label>
<input type="number" name="bpm" id="bpm" min="1" max="200" value="120" />
<div class="new-channel hidden" id="new-channel">
<input type="text" class="notation" />
<div class="insert">
<button id="insert">Add</button>
</div>
</div>
<div id="ui"></div>
</body>
</html>
Loading…
Cancel
Save