diff --git a/packages/app/studio/src/ui/dashboard/Dashboard.tsx b/packages/app/studio/src/ui/dashboard/Dashboard.tsx index 74f64870..17344235 100644 --- a/packages/app/studio/src/ui/dashboard/Dashboard.tsx +++ b/packages/app/studio/src/ui/dashboard/Dashboard.tsx @@ -1,6 +1,6 @@ import css from "./Dashboard.sass?inline" import {Lifecycle} from "@opendaw/lib-std" -import {createElement, LocalLink} from "@opendaw/lib-jsx" +import {createElement} from "@opendaw/lib-jsx" import {StudioService} from "@/service/StudioService.ts" import {Html} from "@opendaw/lib-dom" import {Resources} from "@/ui/dashboard/Resources" @@ -8,36 +8,62 @@ import {DemoProjects} from "@/ui/dashboard/DemoProjects" const className = Html.adoptStyleSheet(css, "Dashboard") +const QUOTES = [ + '"Le bruit est le son que les autres font." \u2014 Pierre Schaeffer, probablement', + '"Tout son est de la musique. Sauf la musique de mon voisin." \u2014 John Cage (adapt\u00e9)', + '"Si tu peux pas l\'expliquer \u00e0 un clown, c\'est que t\'as pas compris." \u2014 electron rare', + '"Le silence est un instrument qu\'on oublie d\'accorder." \u2014 Eliane Radigue, entre deux drones', + '"Un bug est une feature qui n\'a pas encore trouv\u00e9 son public." \u2014 Pharmacius', + '"La musique, c\'est du bruit organis\u00e9. Le bruit, c\'est de la musique d\u00e9sorganis\u00e9e. Les deux sont n\u00e9cessaires." \u2014 Sun Ra', + '"404 : harmonie non trouv\u00e9e." \u2014 le serveur', + '"Fork un repo, c\'est comme voler un orgue de barbarie. L\u00e9gal, mais bruyant." \u2014 electron rare', + '"Les fr\u00e9quences en dessous de 20Hz ne sont pas du silence, c\'est de la patience." \u2014 Merzbow', + '"Un clown sans klaxon est un philosophe. Un philosophe avec un klaxon est un clown." \u2014 les Fratellini', +] + type Construct = { lifecycle: Lifecycle service: StudioService } export const Dashboard = ({lifecycle, service}: Construct) => { + const quote = QUOTES[Math.floor(Math.random() * QUOTES.length)] return (
-

Welcome to openDAW

-

A new holistic exploration of music creation inside your browser

+

openDIAW.be

+

Digital Instrument Audio Workstation \u2014 Fork performance KXKM

+

+ {quote} +

- openDAW is an open source web based music studio with a clear focus on education and data privacy, - open to everyone with no login required so you can start creating music right away. The studio is still - evolving and not production ready yet. + openDIAW.be est un fork de openDAW cr\u00e9\u00e9 + pour le spectacle 3615 J'ai p\u00e9t\u00e9 de la compagnie KXKM. + Il ajoute 9 instruments AI (Drone, Grain, Glitch, Circus, Honk, Magenta, + AceStep, KokoroTTS, Piper) et un AI Bridge avec 19 backends audio. +

+

+ \uD83C\uDFAA Instruments de clown \u2022 \uD83E\uDD16 G\u00e9n\u00e9ration IA \u2022 + \uD83C\uDFA4 TTS 12 voix \u2022 \uD83C\uDFB9 MIDI Magenta.js \u2022 + \uD83D\uDD0A 19 backends audio

-

- Visit Discord and GitHub for more information. - Built with ❤️ +

+ Fork: github.com/electron-rare/openDIAW.be + {" \u2022 "} + Upstream: openDAW par Andr\u00e9 Michelle + {" \u2022 "} + License: AGPL v3 +

+

+ "Saboteurs of big daddy mainframe" \u2014 VNS Matrix, 1991

) -} \ No newline at end of file +} diff --git a/packages/app/studio/src/ui/devices/instruments/AceStepDeviceEditor.sass b/packages/app/studio/src/ui/devices/instruments/AceStepDeviceEditor.sass index 275cd1be..83db29a0 100644 --- a/packages/app/studio/src/ui/devices/instruments/AceStepDeviceEditor.sass +++ b/packages/app/studio/src/ui/devices/instruments/AceStepDeviceEditor.sass @@ -39,30 +39,87 @@ component color: var(--color-black) background-color: var(--color-blue) - > div.gen-panel + > div.ai-panel display: flex flex-direction: column - align-items: center - gap: 0.2em + gap: 0.25em margin: 0.375em + padding: 0.25em pointer-events: all + min-width: 10em + border-left: 1px solid rgba(white, 0.08) - > button - font-size: 0.55em - padding: 0.2em 0.5em - border-radius: 0.3em + > textarea, > input[type="text"] + font-size: 0.5em + font-family: inherit + width: 100% + min-height: 2.5em + padding: 0.3em 0.4em + background: rgba(0, 0, 0, 0.3) + border: 1px solid rgba(white, 0.15) + border-radius: 0.25em + color: var(--color-text) + resize: vertical + + &:focus + border-color: var(--color-blue) + outline: none + + &::placeholder + color: rgba(white, 0.3) + + > select + font-size: 0.5em + font-family: inherit + padding: 0.2em 0.3em + background: rgba(0, 0, 0, 0.3) + border: 1px solid rgba(white, 0.15) + border-radius: 0.25em + color: var(--color-text) + cursor: pointer + + > div.ai-controls + display: flex + gap: 0.25em + align-items: center + + > button, > div.ai-controls > button + font-size: 0.5em + padding: 0.25em 0.6em + border-radius: 0.25em border: 1px solid rgba(white, 0.2) background: rgba(white, 0.05) color: var(--color-text) cursor: pointer white-space: nowrap + transition: background 0.15s, border-color 0.15s &:hover - background: rgba(white, 0.15) + background: rgba(white, 0.12) + border-color: rgba(white, 0.3) + + &.generating + background: var(--color-blue) + color: var(--color-black) + border-color: var(--color-blue) &:disabled - opacity: 0.4 + opacity: 0.35 + cursor: default > span.status font-size: 0.4em - color: rgba(white, 0.5) + color: rgba(white, 0.4) + min-height: 1em + + > div.progress-bar + height: 2px + background: rgba(white, 0.08) + border-radius: 1px + overflow: hidden + + > div.progress-fill + height: 100% + background: var(--color-blue) + transition: width 0.3s + width: 0% diff --git a/packages/app/studio/src/ui/devices/instruments/AceStepDeviceEditor.tsx b/packages/app/studio/src/ui/devices/instruments/AceStepDeviceEditor.tsx index 464bf6bb..45ddeb69 100644 --- a/packages/app/studio/src/ui/devices/instruments/AceStepDeviceEditor.tsx +++ b/packages/app/studio/src/ui/devices/instruments/AceStepDeviceEditor.tsx @@ -15,47 +15,17 @@ import {StudioService} from "@/service/StudioService" const className = Html.adoptStyleSheet(css, "AceStepDeviceEditor") const AI_BRIDGE = (location.protocol === "https:" ? "https:" : "http:") + "//" + location.hostname + ":8301" +const STYLES = ["ambient","electronic","experimental","classical","jazz","industrial","drone","glitch","techno","house","drum-n-bass","lo-fi","cinematic","world"] as const -type Construct = { - lifecycle: Lifecycle - service: StudioService - adapter: AceStepDeviceBoxAdapter - deviceHost: DeviceHost -} +type Construct = { lifecycle: Lifecycle; service: StudioService; adapter: AceStepDeviceBoxAdapter; deviceHost: DeviceHost } export const AceStepDeviceEditor = ({lifecycle, service, adapter, deviceHost}: Construct) => { const {volume, release, tempo, duration} = adapter.namedParameter const {project} = service const {editing, midiLearning} = project - const sampleDropZone: HTMLElement = ( -
- -
- ) + const knob = (parameter: typeof volume) => ControlBuilder.createKnob({lifecycle, editing, midiLearning, adapter, parameter}) + const sampleDropZone: HTMLElement = (
) const sampleSelector = new SampleSelector(service, SampleSelectStrategy.forPointerField(adapter.box.file)) - const statusLabel: HTMLElement = - const promptInput: HTMLInputElement = as HTMLInputElement - const generateButton: HTMLButtonElement = as HTMLButtonElement - generateButton.addEventListener("click", async () => { - generateButton.disabled = true - statusLabel.textContent = "Generating..." - try { - const bpm = Math.round(tempo.getValue()) - const dur = Math.round(duration.getValue()) - const prompt = promptInput.value || "ambient electronic" - const response = await fetch(`${AI_BRIDGE}/generate/music-ai`, { - method: "POST", - headers: {"Content-Type": "application/json"}, - body: JSON.stringify({prompt, duration: dur, bpm}) - }) - if (!response.ok) {throw new Error(`HTTP ${response.status}`)} - statusLabel.textContent = "Done" - } catch (error) { - statusLabel.textContent = "Error" - } finally { - generateButton.disabled = false - } - }) lifecycle.ownAll( adapter.box.file.catchupAndSubscribe(pointer => pointer.targetVertex.match({ none: () => sampleDropZone.removeAttribute("sample"), @@ -65,54 +35,56 @@ export const AceStepDeviceEditor = ({lifecycle, service, adapter, deviceHost}: C sampleSelector.configureContextMenu(sampleDropZone), sampleSelector.configureDrop(sampleDropZone) ) + const promptArea: HTMLTextAreaElement =