From 5dc9bcee53ed78e156c62c276aef3ff8c071d04a Mon Sep 17 00:00:00 2001 From: b-ma Date: Fri, 24 Nov 2023 16:00:32 +0100 Subject: [PATCH] first commit --- .gitignore | 4 + .npmrc | 1 + LICENSE | 29 +++++ README.md | 19 +++ create.js | 112 ++++++++++++++++++ package.json | 34 ++++++ templates/simple-online/README.md | 10 ++ templates/simple-online/assets/sample.wav | Bin 0 -> 1808 bytes templates/simple-online/index.html | 13 ++ .../simple-online/lib/load-audio-buffer.js | 17 +++ .../simple-online/lib/resume-audio-context.js | 15 +++ templates/simple-online/main.js | 22 ++++ templates/simple-online/styles.css | 27 +++++ 13 files changed, 303 insertions(+) create mode 100644 .gitignore create mode 100644 .npmrc create mode 100644 LICENSE create mode 100644 README.md create mode 100755 create.js create mode 100644 package.json create mode 100644 templates/simple-online/README.md create mode 100755 templates/simple-online/assets/sample.wav create mode 100644 templates/simple-online/index.html create mode 100644 templates/simple-online/lib/load-audio-buffer.js create mode 100644 templates/simple-online/lib/resume-audio-context.js create mode 100644 templates/simple-online/main.js create mode 100644 templates/simple-online/styles.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..45cd33a --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.DS_Store +.Thumb.db + +node_modules diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..43c97e7 --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..fab4916 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2023-present IRCAM – Centre Pompidou (France, Paris) + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + +* Neither the name of the IRCAM nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..859c4f8 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Ircam | create + +[![npm version](https://badge.fury.io/js/@ircam%2Fcreate.svg)](https://badge.fury.io/js/@ircam%2Fcreate) + +Interactive command line tools for scaffolding simple Web Audio test apps and demos. + +## Usage + +```sh +npx @ircam/create@latest [dirname] +``` + +## Credits + +[https://soundworks.dev/credits.html](https://soundworks.dev/credits.html) + +## License + +[BSD-3-Clause](./LICENSE) diff --git a/create.js b/create.js new file mode 100755 index 0000000..a62bb66 --- /dev/null +++ b/create.js @@ -0,0 +1,112 @@ +#!/usr/bin/env node + +import { execSync } from 'node:child_process'; +import fs from 'node:fs'; +import path from 'node:path'; +import * as url from 'node:url'; + +import chalk from 'chalk'; +import { mkdirp } from 'mkdirp'; +import prompts from 'prompts'; +import readdir from 'recursive-readdir'; + +const __dirname = url.fileURLToPath(new URL('.', import.meta.url)); +const { version } = JSON.parse(fs.readFileSync(path.join(__dirname, 'package.json'))); + +export function toValidPackageName(name) { + return name + .trim() + .toLowerCase() + .replace(/\s+/g, '-') + .replace(/^[._]/, '') + .replace(/[^a-z0-9~.-]+/g, '-'); +} + +console.log(`\ +${chalk.gray(`[@ircam/create#v${version}]`)} +`); + +let targetDir; +if (process.argv[2]) { + targetDir = process.argv[2]; +} else { + targetDir = '.'; +} + +if (targetDir === '.') { + const result = await prompts([ + { + type: 'text', + name: 'dir', + message: 'Where should we create your project?\n (leave blank to use current directory)', + }, + ]); + + if (result.dir) { + targetDir = result.dir; + } +} + +const targetWorkingDir = path.normalize(path.join(process.cwd(), targetDir)); + +if (fs.existsSync(targetWorkingDir) && fs.readdirSync(targetWorkingDir).length > 0) { + console.log(chalk.red(`> "${targetDir}" directory exists and is not empty, aborting...`)); + process.exit(1); +} + +const templateDir = path.join(__dirname, 'templates', 'simple-online'); + +const ignoreFiles = ['.DS_Store', 'Thumbs.db']; +const files = await readdir(templateDir, ignoreFiles); + +await mkdirp(targetWorkingDir); + + +console.log(''); +console.log(`> scaffolding app in:`, targetWorkingDir); + +for (let src of files) { + const file = path.relative(templateDir, src); + const dest = path.join(targetWorkingDir, file); + + await mkdirp(path.dirname(dest)); + + switch (file) { + case 'package.json': { + const pkg = JSON.parse(fs.readFileSync(src)); + pkg.name = toValidPackageName(options.name); + + fs.writeFileSync(dest, JSON.stringify(pkg, null, 2)); + break; + } + case 'README.md': + case 'index.html': + case 'main.js': { + let content = fs.readFileSync(src).toString(); + content = content.replace(/\[app_name\]/mg, targetDir); + fs.writeFileSync(dest, content); + break; + } + // just copy the file without modification + default: { + fs.copyFileSync(src, dest); + break; + } + } +} + +console.log(chalk.yellow('> your project is ready!')); + +console.log('') +console.log(chalk.yellow('> next steps:')); +let i = 1; + +const relative = path.relative(process.cwd(), targetWorkingDir); +if (relative !== '') { + console.log(` ${i++}: ${chalk.cyan(`cd ${relative}`)}`); +} + +console.log(` ${i++}: ${chalk.cyan('npx serve')}`); + +console.log('') +console.log(`- to close the dev server, press ${chalk.bold(chalk.cyan('Ctrl-C'))}`); diff --git a/package.json b/package.json new file mode 100644 index 0000000..59da8d9 --- /dev/null +++ b/package.json @@ -0,0 +1,34 @@ +{ + "name": "@ircam/create", + "version": "1.0.0", + "description": "Interactive command line tools for scaffolding simple Web Audio test apps and demos.", + "authors": [ + "Benjamin Matuszewski" + ], + "license": "BSD-3-Clause", + "type": "module", + "bin": { + "create": "create.js" + }, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/ircam-create/ircam-create" + }, + "bugs": { + "url": "https://github.com/ircam-create/ircam-create/issues" + }, + "homepage": "https://github.com/ircam-create/ircam-create", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "chalk": "^5.3.0", + "commander": "^11.1.0", + "mkdirp": "^3.0.1", + "prompts": "^2.4.2", + "recursive-readdir": "^2.2.3" + } +} diff --git a/templates/simple-online/README.md b/templates/simple-online/README.md new file mode 100644 index 0000000..d92901e --- /dev/null +++ b/templates/simple-online/README.md @@ -0,0 +1,10 @@ +# [app_name] + +Simple template for Web Audio demos and tests + +## Usage + +``` +cd path/to/dir +npx serve +``` diff --git a/templates/simple-online/assets/sample.wav b/templates/simple-online/assets/sample.wav new file mode 100755 index 0000000000000000000000000000000000000000..aa10036601fd6f3f3eb6442366f7ee7c947006df GIT binary patch literal 1808 zcmWO7c~DeW76;&a-+R5Vbps7eLkj|9SVSOzi6|h8z$j56t}K=WC5@&cM#YWD#AxCI zIMK*N)KT1mfPi2ag}6in6a*EFEDf?RA_xdgFR$Nw_fFTTQ|G_0PMtbczcni&BZUG0 zHimA9Q0z!^GzS1cLxmRua3U500+@s3q_m_VJ^&KT$67Rsl&A)kqq8U-#UT%5j_z?+ zI3735mNB;(7ib}f5iPe~W$Pv1Xh+#j$cp4Aof6%5`%Iw?w{_Xa?7z_CoVyj zlXiUz+GVZUj*Px1BMBonx;8v>xqaZ`(CG)K!hZSjx9Z=+?yrBHG~%M(ij8^e1Sk0! zm-Pn(yC<0bJ$kH` z%HQ?t+04$9!pw|J?=$DGbyT@DEpLgapL?$>zyFfS<;8{clS5-Y(vrYG*Eesunj%d} z*kT@^9i0*(3SJU?A@bFl$i%xT+rIfy5gR)exLcY&`T48a2Z!(0R31dq=;D?EMMSlchS_D*Fg61&zi)EtV|yhD`%$OPCPBHXe!9Q{@D#l(fSJi>d#)@ z>6q8+)?d~8ueZ0Ao0VU8cZ~o|rqL4ziSO?rq7~6!EL^S)DOmK>tHkY*ORHPHr-k3- z=RYpW@ynmDnp0>((7(RBqD*Vv+*H?ept+(|(fQ}wye_hRVe@qT*EMsiy=pWKo~?HV z_o>zqQKBU2b~{J;AGT#SH>Iy_8s*s*`{R1%c2c)!ms7c09^(M>80*)u=u zeVJR#Eq#dAXS#p%+unI?Ctl_@i0V}hHm`EpLV7R0OP;KmxjXxKRx&%R+M_-~2LgAa zMG{N>yH>P8+ILYn2w`s;WndG@dk;9b%gb1t8mGE%P5Jh zwb~|B9_bM3nCYl=kjsm$UBw%PmIUB-(|fdKn$wznno{+EYU-nGVtAAs_892w+uUC| zc=X-M4~f$f%?N#w^+Fo73(o^NP(Ym)^qORvk6P`JW!X8)Wp*!ZZdwId%n=oth>Zh{ zdW2_$O@c^%Iq3kNF}B)EGhLIOAKJ&BjkSztP8^;JnogS`R6zB|%(0ol8N1n7&1pJ| z>x35khek(Dmy1}@2T`=>teL=U*fh$_N@OW+6N}Avil3V;GEoYgC2GlZ_$bUG=99Uk12s!|^Ob^HqlYFL zX4Rr-v5A-ztu+lZwiH_OQz#EImZ*kHVJ0|^Whj#M)I%MoPMTGy#H#J8WwQs>?HUK& zr}TR|MPH)lGsl^|YzJ3}8zG-^=T8e(8`&CfGIlo3HF_@$71j$f1qTF21m6kV1!?@X zhQFSGlUUFBu#NiXbO@Yh(#O*( zol+;IFVP8lKSs(9u;(}@l!pZP1a<}Epb1tJ#bi3=%sa(v=C$)GdE0pm^*yB~v&aSH z6j4HKBN(_9=7KVO4-IlITrs-dT{03dNhHy;9OjSuj69;1nY1Z$OAU;EHo$f z5)X+9gV;?J5UGSWp@UE1RhSKbf`{P_=nwnBR?vb2@dLC5$&dhvkt+&E$>s8 zjWI@VQ6u^b4InT48|Hzv;Aij?I1X|^G3WyvkV6UN!EwX&Suhtyz%Stvs0P=-GQi+w z{1<+P-x#)kjUVDihEn2pcnr7TQhX4{;V7JlPvSZ}gQdU~cmsbB1Qr|GA1nodARMd! zQD6;-2CEF3CvY$%*pR_1#@Fx#d;^!^$G8)Jz?31?F#d>paks(mG5BMc##+o_ArJ!> K-~&Po=KlfA3w3k= literal 0 HcmV?d00001 diff --git a/templates/simple-online/index.html b/templates/simple-online/index.html new file mode 100644 index 0000000..2e8d4e8 --- /dev/null +++ b/templates/simple-online/index.html @@ -0,0 +1,13 @@ + + + + + + [app_name] + + + + + + + diff --git a/templates/simple-online/lib/load-audio-buffer.js b/templates/simple-online/lib/load-audio-buffer.js new file mode 100644 index 0000000..d9bb88f --- /dev/null +++ b/templates/simple-online/lib/load-audio-buffer.js @@ -0,0 +1,17 @@ +const contexts = new Map(); + +export default async function loadAudioBuffer(pathname, sampleRate = 48000) { + if (!contexts.has(sampleRate)) { + const context = new OfflineAudioContext(1, 1, sampleRate); + console.log(context.sampleRate); + contexts.set(sampleRate, context); + } + + const response = await fetch(pathname); + const arrayBuffer = await response.arrayBuffer(); + + const context = contexts.get(sampleRate); + const audioBuffer = await context.decodeAudioData(arrayBuffer); + + return audioBuffer; +} diff --git a/templates/simple-online/lib/resume-audio-context.js b/templates/simple-online/lib/resume-audio-context.js new file mode 100644 index 0000000..bd47083 --- /dev/null +++ b/templates/simple-online/lib/resume-audio-context.js @@ -0,0 +1,15 @@ +import { html, render } from 'https://unpkg.com/lit-html'; + +export default async function resumeAudioContext(audioContext) { + return new Promise(resolve => { + render(html` + { + await audioContext.resume(); + resolve(); + }} + >Resume context + `, document.body); + }); +} diff --git a/templates/simple-online/main.js b/templates/simple-online/main.js new file mode 100644 index 0000000..4ba24af --- /dev/null +++ b/templates/simple-online/main.js @@ -0,0 +1,22 @@ +import { html, render } from 'https://unpkg.com/lit-html'; +import 'https://unpkg.com/@ircam/sc-components@latest'; + +import resumeAudioContext from './lib/resume-audio-context.js'; +import loadAudioBuffer from './lib/load-audio-buffer.js'; + +const audioContext = new AudioContext(); +await resumeAudioContext(audioContext); + +const buffer = await loadAudioBuffer('./assets/sample.wav', audioContext.sampleRate); + +render(html` +

[app_name]

+ { + const src = audioContext.createBufferSource(); + src.connect(audioContext.destination); + src.buffer = buffer; + src.start(); + }} + > +`, document.body); diff --git a/templates/simple-online/styles.css b/templates/simple-online/styles.css new file mode 100644 index 0000000..d98197f --- /dev/null +++ b/templates/simple-online/styles.css @@ -0,0 +1,27 @@ +:root { + --background-color: #181817; + --font-color: #ffffff; + --font-family: Consolas, monaco, monospace; + --font-size: 62.5%; // such that 1rem == 10px +} + +* { + box-sizing: border-box; + font-family: var(--font-family); +} + +html, body { + width: 100%; + min-height: 100vh; + background-color: var(--background-color); + color: var(--font-color); +} + +html { + font-size: var(--font-size); +} + +body { + padding: 20px; + margin: 0; +}