First proper working
This commit is contained in:
commit
356444f2de
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
.venv
|
27
app.py
Normal file
27
app.py
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
from flask import Flask, render_template
|
||||||
|
from flask_socketio import SocketIO, emit
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
socketio = SocketIO(app)
|
||||||
|
|
||||||
|
# Normal app routes
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
return render_template('index.html')
|
||||||
|
|
||||||
|
@app.route('/spe')
|
||||||
|
def spe():
|
||||||
|
return render_template('spe.html')
|
||||||
|
|
||||||
|
# Socket IO stuff
|
||||||
|
@socketio.on('action')
|
||||||
|
def hey():
|
||||||
|
print('action')
|
||||||
|
socketio.emit('all_action')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
socketio.run(
|
||||||
|
app,
|
||||||
|
host='0.0.0.0',
|
||||||
|
allow_unsafe_werkzeug=True
|
||||||
|
)
|
14
requirements.txt
Normal file
14
requirements.txt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
bidict==0.22.1
|
||||||
|
blinker==1.7.0
|
||||||
|
click==8.1.7
|
||||||
|
Flask==3.0.1
|
||||||
|
Flask-SocketIO==5.3.6
|
||||||
|
h11==0.14.0
|
||||||
|
itsdangerous==2.1.2
|
||||||
|
Jinja2==3.1.3
|
||||||
|
MarkupSafe==2.1.4
|
||||||
|
python-engineio==4.8.2
|
||||||
|
python-socketio==5.11.0
|
||||||
|
simple-websocket==1.0.0
|
||||||
|
Werkzeug==3.0.1
|
||||||
|
wsproto==1.2.0
|
9
static/images/play.svg
Normal file
9
static/images/play.svg
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||||
|
<svg width="19.999996mm" height="22.569992mm" viewBox="0 0 19.999996 22.569992" version="1.1" id="svg5" inkscape:version="1.2 (dc2aedaf03, 2022-05-15)" sodipodi:docname="icons.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
|
||||||
|
<sodipodi:namedview id="namedview7" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:showpageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:deskcolor="#d1d1d1" inkscape:document-units="mm" showgrid="false" inkscape:zoom="3.6613294" inkscape:cx="332.80262" inkscape:cy="370.76697" inkscape:window-width="1920" inkscape:window-height="1011" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="1" inkscape:current-layer="layer1"/>
|
||||||
|
<defs id="defs2"/>
|
||||||
|
<g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1" transform="translate(-50.079351,-70.338316)">
|
||||||
|
<path id="rect1069" style="opacity:1;fill:#121212;fill-opacity:1;stroke-width:1.59792;stroke-linejoin:round;stop-color:#000000" d="m 51.57935,70.475601 17,9.525 c 0.724961,0.406191 1.5,0.669 1.5,1.5 v 0.245422 c 0,0.831 -0.775039,1.093809 -1.5,1.5 l -17,9.525 c -0.724961,0.406192 -1.5,-0.139833 -1.5,-0.970833 V 71.446434 c 0,-0.831 0.775039,-1.377025 1.5,-0.970833 z" sodipodi:nodetypes="sssssssss"/>
|
||||||
|
</g>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 1.5 KiB |
85
static/js/app.js
Normal file
85
static/js/app.js
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
import { amsynth } from "./modules/instruments/amsynth.js"
|
||||||
|
import { duosynth } from "./modules/instruments/duosynth.js"
|
||||||
|
import { monosynth } from "./modules/instruments/monosynth.js"
|
||||||
|
import { plucksynth } from "./modules/instruments/plucksynth.js"
|
||||||
|
|
||||||
|
let FILTER_FREQ = 400
|
||||||
|
let REV_RANGE = 12
|
||||||
|
let REV = Math.random() * REV_RANGE
|
||||||
|
|
||||||
|
let NOTES = ["A3", "A2", "C4", "C3", "F3", "F2"]
|
||||||
|
let NOTE = NOTES[ Math.floor(Math.random() * NOTES.length)]
|
||||||
|
|
||||||
|
let SPACING = ["7h", "8h", "9h", "10h"]
|
||||||
|
let SPACE = SPACING[Math.floor(Math.random() * SPACING.length)]
|
||||||
|
|
||||||
|
Tone.Transport.bpm.value = 60;
|
||||||
|
|
||||||
|
let INSTRUMENTS = [amsynth, monosynth, plucksynth]
|
||||||
|
let INSTRUMENT = INSTRUMENTS[Math.floor(Math.random() * INSTRUMENTS.length)]
|
||||||
|
|
||||||
|
const channel = new Tone.Channel();
|
||||||
|
const freeverb = new Tone.Freeverb({ roomSize: 0.98, wet : 0.4 })
|
||||||
|
const filter = new Tone.Filter({type:"lowpass", frequency:800})
|
||||||
|
|
||||||
|
channel.chain(freeverb, filter, Tone.Master)
|
||||||
|
|
||||||
|
for (let inst of INSTRUMENTS) {
|
||||||
|
inst.connect(channel)
|
||||||
|
}
|
||||||
|
|
||||||
|
const play = () => {
|
||||||
|
let r = Math.random()
|
||||||
|
if (r > 0.7) {
|
||||||
|
const a = new Tone.Loop((time) => {
|
||||||
|
INSTRUMENT.triggerAttackRelease(NOTE, "16n")
|
||||||
|
}, SPACE).start(0)
|
||||||
|
} else if (r > 0.3) {
|
||||||
|
const a = new Tone.Loop((time) => {
|
||||||
|
amsynth.triggerAttack(NOTE, "16n")
|
||||||
|
}, SPACE).start(0)
|
||||||
|
|
||||||
|
} else {
|
||||||
|
freeverb.wet.value = 0.0
|
||||||
|
const bassPart = new Tone.Sequence(((time, note) => {
|
||||||
|
plucksynth.triggerAttack(note);
|
||||||
|
}), ["C7", "C8", "C7", "C5", "C#8"], "8n").start(0);
|
||||||
|
|
||||||
|
bassPart.probability = 0.6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let ac_x = document.getElementById("ac_x")
|
||||||
|
let ac_y = document.getElementById("ac_y")
|
||||||
|
let ac_z = document.getElementById("ac_z")
|
||||||
|
|
||||||
|
if (window.DeviceOrientationEvent) {
|
||||||
|
window.addEventListener(
|
||||||
|
"deviceorientation",
|
||||||
|
(event) => {
|
||||||
|
const rotateDegrees = event.alpha; // alpha: rotation around z-axis
|
||||||
|
const leftToRight = event.gamma; // gamma: left to right
|
||||||
|
const frontToBack = event.beta; // beta: front back motion
|
||||||
|
|
||||||
|
// ac_x.innerHTML = rotateDegrees
|
||||||
|
ac_y.innerHTML = leftToRight
|
||||||
|
// ac_z.innerHTML = frontToBack
|
||||||
|
|
||||||
|
filter.frequency.value = (180 + leftToRight) * 6
|
||||||
|
|
||||||
|
ac_x.innerHTML = filter.frequency.value
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
document.getElementById('start').addEventListener('click', function() {
|
||||||
|
Tone.context.resume().then(() => {
|
||||||
|
Tone.start()
|
||||||
|
Tone.Transport.start()
|
||||||
|
|
||||||
|
play()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})()
|
8
static/js/lib/Tone.13.4.9.js
Normal file
8
static/js/lib/Tone.13.4.9.js
Normal file
File diff suppressed because one or more lines are too long
22
static/js/lib/Tone.js
Normal file
22
static/js/lib/Tone.js
Normal file
File diff suppressed because one or more lines are too long
22
static/js/lib/Tone.o.js
Normal file
22
static/js/lib/Tone.o.js
Normal file
File diff suppressed because one or more lines are too long
2
static/js/lib/howler.core.min.js
vendored
Normal file
2
static/js/lib/howler.core.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4
static/js/lib/howler.min.js
vendored
Normal file
4
static/js/lib/howler.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
6046
static/js/lib/socket.io.js
Normal file
6046
static/js/lib/socket.io.js
Normal file
File diff suppressed because it is too large
Load diff
90
static/js/main.js
Normal file
90
static/js/main.js
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
const socket = io();
|
||||||
|
|
||||||
|
import { NOTE, SPACE } from "./settings.js"
|
||||||
|
|
||||||
|
import { pick } from "./modules/utils.js"
|
||||||
|
|
||||||
|
import { amsynth } from "./modules/instruments/amsynth.js"
|
||||||
|
import { duosynth } from "./modules/instruments/duosynth.js"
|
||||||
|
import { monosynth } from "./modules/instruments/monosynth.js"
|
||||||
|
import { membranesynth } from "./modules/instruments/membranesynth.js"
|
||||||
|
import { plucksynth } from "./modules/instruments/plucksynth.js"
|
||||||
|
|
||||||
|
const instrument = pick([amsynth, duosynth, monosynth, membranesynth, plucksynth])
|
||||||
|
|
||||||
|
import { reverb } from "./modules/effects/reverb.js"
|
||||||
|
|
||||||
|
Tone.Transport.bpm.value = 60;
|
||||||
|
|
||||||
|
// A channel to chain instruments and effects
|
||||||
|
const channel = new Tone.Channel();
|
||||||
|
|
||||||
|
// This is a hack to have something running, which makes the reverb work
|
||||||
|
const pingpong = new Tone.PingPongDelay({delayTime : 2, feedback : 0, wet : 0})
|
||||||
|
|
||||||
|
// Chain the channel and effects to the master out
|
||||||
|
channel.connect(pingpong)
|
||||||
|
pingpong.connect(reverb)
|
||||||
|
reverb.connect(Tone.Master)
|
||||||
|
|
||||||
|
// Chain instrument to the channel
|
||||||
|
instrument.connect(channel)
|
||||||
|
|
||||||
|
const voice = new Tone.Player("/static/recordings/tts.mp3").connect(channel)
|
||||||
|
voice.playbackRate = 0.75
|
||||||
|
voice.loop = true
|
||||||
|
voice.autostart = false
|
||||||
|
|
||||||
|
let playloop = undefined
|
||||||
|
|
||||||
|
const pathway = pick([0, 1, 2])
|
||||||
|
const play = () => {
|
||||||
|
// Determine which of our patterns to play
|
||||||
|
switch(pathway) {
|
||||||
|
case 0:
|
||||||
|
playloop = new Tone.Loop((time) => {
|
||||||
|
instrument.triggerAttackRelease(NOTE, "16n")
|
||||||
|
}, SPACE).start(0)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
playloop = new Tone.Loop((time) => {
|
||||||
|
instrument.triggerAttackRelease(NOTE, "8n")
|
||||||
|
}, SPACE).start(0)
|
||||||
|
break
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
playloop = new Tone.Player("/static/recordings/birds.mp3").connect(channel)
|
||||||
|
playloop.loop = true
|
||||||
|
playloop.autostart = true
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Defaulting
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
socket.on('all_action', () => {
|
||||||
|
console.log('ACTION')
|
||||||
|
document.body.style.background = "orange"
|
||||||
|
voice.start()
|
||||||
|
})
|
||||||
|
|
||||||
|
const flowers = ["🌼", "🌸", "💮", "🌺", "🪷", "🏵️"]
|
||||||
|
|
||||||
|
const playbutton = document.getElementById('play')
|
||||||
|
|
||||||
|
playbutton.addEventListener('click', () => {
|
||||||
|
if (playbutton.className == 'paused') {
|
||||||
|
playbutton.className = 'playing';
|
||||||
|
playbutton.innerHTML = pick(flowers);
|
||||||
|
Tone.context.resume().then(() => {
|
||||||
|
Tone.start()
|
||||||
|
Tone.Transport.start("+0.1")
|
||||||
|
}).then(
|
||||||
|
play()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})()
|
4
static/js/modules/effects/reverb.js
Normal file
4
static/js/modules/effects/reverb.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export const reverb = new Tone.Reverb({
|
||||||
|
decay : 30,
|
||||||
|
wet : 0.5
|
||||||
|
})
|
2
static/js/modules/instruments/amsynth.js
Normal file
2
static/js/modules/instruments/amsynth.js
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
export const amsynth = new Tone.AMSynth({
|
||||||
|
})
|
3
static/js/modules/instruments/duosynth.js
Normal file
3
static/js/modules/instruments/duosynth.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export const duosynth = new Tone.DuoSynth({
|
||||||
|
volume : -9
|
||||||
|
})
|
15
static/js/modules/instruments/membranesynth.js
Normal file
15
static/js/modules/instruments/membranesynth.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
export const membranesynth = new Tone.MembraneSynth({
|
||||||
|
volume : -9,
|
||||||
|
pitchDecay : 0.05,
|
||||||
|
octaves : 10,
|
||||||
|
oscillator : {
|
||||||
|
type : "sine"
|
||||||
|
},
|
||||||
|
envelope : {
|
||||||
|
attack : 0.001,
|
||||||
|
decay : 0.4,
|
||||||
|
sustain : 0.01,
|
||||||
|
release : 1.4,
|
||||||
|
attackCurve : "exponential"
|
||||||
|
}
|
||||||
|
})
|
13
static/js/modules/instruments/monosynth.js
Normal file
13
static/js/modules/instruments/monosynth.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
export const monosynth = new Tone.MonoSynth({
|
||||||
|
volume: -9,
|
||||||
|
envelope: {
|
||||||
|
attack: 0.01,
|
||||||
|
},
|
||||||
|
filterEnvelope: {
|
||||||
|
attack: 0.001,
|
||||||
|
decay: 0.01,
|
||||||
|
sustain: 0.9,
|
||||||
|
baseFrequency: 1000,
|
||||||
|
octaves: 1.6
|
||||||
|
}
|
||||||
|
})
|
5
static/js/modules/instruments/plucksynth.js
Normal file
5
static/js/modules/instruments/plucksynth.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export const plucksynth = new Tone.PluckSynth({
|
||||||
|
volume : -3,
|
||||||
|
attackNoise : 1,
|
||||||
|
resonance : 0.9
|
||||||
|
})
|
1
static/js/modules/instruments/synth.js
Normal file
1
static/js/modules/instruments/synth.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
|
1
static/js/modules/synth.js
Normal file
1
static/js/modules/synth.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const name = "burger"
|
3
static/js/modules/utils.js
Normal file
3
static/js/modules/utils.js
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
export const pick = (list) => {
|
||||||
|
return list[Math.floor(Math.random() * list.length)]
|
||||||
|
}
|
4
static/js/play.js
Normal file
4
static/js/play.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
export const play = () => {
|
||||||
|
synth.triggerAttackRelease("C4", "16n");
|
||||||
|
}
|
||||||
|
|
7
static/js/settings.js
Normal file
7
static/js/settings.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import { pick } from "./modules/utils.js"
|
||||||
|
|
||||||
|
export const NOTES = ["A3", "A2", "C4", "C3", "F3", "F2"]
|
||||||
|
export const NOTE = pick(NOTES)
|
||||||
|
|
||||||
|
export const SPACING = ["7h", "8h", "9h", "10h"]
|
||||||
|
export const SPACE = SPACING[Math.floor(Math.random() * SPACING.length)]
|
BIN
static/recordings/birds.mp3
Normal file
BIN
static/recordings/birds.mp3
Normal file
Binary file not shown.
BIN
static/recordings/tts.mp3
Normal file
BIN
static/recordings/tts.mp3
Normal file
Binary file not shown.
84
templates/index.html
Normal file
84
templates/index.html
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf8" />
|
||||||
|
<title>🌟 Valde 30 🌟</title>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
width : 100%;
|
||||||
|
height : 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
body div {
|
||||||
|
font-size : 2.88em;
|
||||||
|
color : #aa2211;
|
||||||
|
}
|
||||||
|
|
||||||
|
#play {
|
||||||
|
height: 180px;
|
||||||
|
width: 180px;
|
||||||
|
border-radius: 100%;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 180px;
|
||||||
|
font-size: 100px;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background-color 0.4s, color 0.4s;
|
||||||
|
box-shadow: 0 0 10px rgba(0,0,0,0.6);
|
||||||
|
background-position: center center;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
#play.paused {
|
||||||
|
background-color: #efefef;
|
||||||
|
color: #121212;
|
||||||
|
background-image: url('/static/images/play.svg');
|
||||||
|
background-position: 58% 54%;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#play.playing {
|
||||||
|
background-color: #121212;
|
||||||
|
color: #efefef;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<h2>🌟 Valde 30 🌟</h2>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div id="play" class="paused"></div>
|
||||||
|
</div>
|
||||||
|
<script src="static/js/lib/socket.io.js"></script>
|
||||||
|
<script src="static/js/lib/Tone.js"></script>
|
||||||
|
<script type="module" src="static/js/main.js"></script>
|
||||||
|
<script>
|
||||||
|
// Random colours
|
||||||
|
let hexString = "0123456789abcdef";
|
||||||
|
let randomColor = () => {
|
||||||
|
let hexCode = "#";
|
||||||
|
for( i=0; i<6; i++){
|
||||||
|
hexCode += hexString[Math.floor(Math.random() * hexString.length)];
|
||||||
|
}
|
||||||
|
return hexCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
let generateGrad = () => {
|
||||||
|
let colorOne = randomColor();
|
||||||
|
let colorTwo = randomColor();
|
||||||
|
let angle = Math.floor(Math.random() * 360);
|
||||||
|
document.body.style.background = `linear-gradient(${angle}deg, ${colorOne}, ${colorTwo})`;
|
||||||
|
// outputCode.value = `background: linear-gradient(${angle}deg, ${colorOne}, ${colorTwo});`;
|
||||||
|
}
|
||||||
|
|
||||||
|
generateGrad()
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
24
templates/spe.html
Normal file
24
templates/spe.html
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf8" />
|
||||||
|
<title>Admin</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
background : #222;
|
||||||
|
color : #aaa;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<button id="action">Action</button>
|
||||||
|
<script src="static/js/lib/socket.io.js"></script>
|
||||||
|
<script>
|
||||||
|
const socket = io();
|
||||||
|
document.getElementById('action').addEventListener('click', () => {
|
||||||
|
socket.emit('action')
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
Loading…
Reference in a new issue