Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

notepat: shift+whistle = messy 'blow' with noise layer

First per-instrument Shift alternate after harp→pluck. When whistle
is the active wave and Shift is held, the note trigger layers a
noise voice at 4× the pitched tone on top of the whistle synth:

- main whistle @ playFreq (volume 0.42 instead of 0.5 to leave
room for the noise without clipping)
- noise @ playFreq × 4 (volume 0.18, slow attack so it
feathers in behind the pitched tone)

Both voices are tracked together via compositeVoices so the release
kills them in sync — press → whistle + breath, release → both fade
together with the user's selected decay. Feels like blowing harder
across the whistle mouth: more air, same pitch.

Runs alongside the existing global Shift outline + shift-boost
velocity so the "global alternate mode" reads both visually and
sonically. Harp's short-pluck path untouched.

Queued: sine/triangle/saw/square/sample Shift alternates still open.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

+26 -6
+26 -6
fedac/native/pieces/notepat.mjs
··· 3055 3055 compositeVoices: [a, b, c, d, e2], 3056 3056 }, system, 1); 3057 3057 } else { 3058 - // Shift+letter on harp = short staccato pluck. Pass decay=0.1 as 3059 - // a signal to the C generate_harp_sample (which switches to a 3060 - // tighter stretch factor and damps in ~0.4s). Finite duration 3061 - // so the voice naturally ends without needing kill(). 3058 + // Shift modifiers — per-instrument alternate sound recipes. 3059 + // harp + shift → short staccato pluck (tight stretch in C) 3060 + // whistle+ shift → "blow" — whistle plus a noise layer for 3061 + // breathy/airy character 3062 3062 const isShortPluck = wave === "harp" && shiftHeld; 3063 + const isMessyBlow = wave === "whistle" && shiftHeld; 3063 3064 synth = sound.synth({ 3064 3065 type: wave, tone: playFreq, 3065 3066 duration: isShortPluck ? 0.4 : Infinity, 3066 - volume: 0.5, 3067 + volume: isMessyBlow ? 0.42 : 0.5, 3067 3068 attack: currentAttack(), 3068 3069 decay: isShortPluck ? 0.1 : currentDecay(), 3069 3070 pan, 3070 3071 }); 3071 - rememberSound(hitNote.key, { synth, note: hitNote.letter, octave: hitNote.octave, baseFreq: freq }, system, 1); 3072 + if (isMessyBlow) { 3073 + // Noise layer riding two octaves above the whistle — reads as 3074 + // breath passing across the whistle mouth. Volume stays low 3075 + // so the pitched tone still dominates; releases with the 3076 + // main voice via compositeVoices bookkeeping below. 3077 + const blow = sound.synth({ 3078 + type: "noise", tone: playFreq * 4, 3079 + duration: Infinity, 3080 + volume: 0.18, 3081 + attack: Math.max(0.02, currentAttack()), 3082 + decay: currentDecay(), 3083 + pan, 3084 + }); 3085 + rememberSound(hitNote.key, { 3086 + synth, note: hitNote.letter, octave: hitNote.octave, baseFreq: freq, 3087 + compositeVoices: [synth, blow], 3088 + }, system, 1); 3089 + } else { 3090 + rememberSound(hitNote.key, { synth, note: hitNote.letter, octave: hitNote.octave, baseFreq: freq }, system, 1); 3091 + } 3072 3092 } 3073 3093 if (!sounds[hitNote.key]) { 3074 3094 synth = sound.synth({