Merge pull request #1329 from hpunq/sample-ui

Add new "import-sounds" tab with explanation on folder import
This commit is contained in:
Jade (Rose) Rowland 2025-04-27 01:53:40 -04:00 committed by GitHub
commit b5d48b2f0b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 57 additions and 5 deletions

View File

@ -22,7 +22,7 @@ export default function ImportSoundsButton({ onComplete }) {
return (
<label
style={{ alignItems: 'center' }}
className="flex bg-background ml-2 pl-2 pr-2 max-w-[300px] rounded-md hover:opacity-50 whitespace-nowrap cursor-pointer"
className="flex bg-background ml-2 pl-2 pr-2 max-w-[210px] rounded-md hover:opacity-50 whitespace-nowrap cursor-pointer"
>
<input
disabled={isUploading}
@ -38,7 +38,7 @@ export default function ImportSoundsButton({ onComplete }) {
onChange();
}}
/>
{isUploading ? 'importing...' : 'import sounds'}
{isUploading ? 'importing...' : 'import sounds folder'}
</label>
);
}

View File

@ -14,6 +14,8 @@ export function SoundsTab() {
const sounds = useStore(soundMap);
const { soundsFilter } = useSettings();
const [search, setSearch] = useState('');
const { BASE_URL } = import.meta.env;
const baseNoTrailing = BASE_URL.endsWith('/') ? BASE_URL.slice(0, -1) : BASE_URL;
const soundEntries = useMemo(() => {
if (!sounds) {
@ -37,6 +39,9 @@ export function SoundsTab() {
if (soundsFilter === 'synths') {
return filtered.filter(([_, { data }]) => ['synth', 'soundfont'].includes(data.type));
}
if (soundsFilter === 'importSounds') {
return [];
}
return filtered;
}, [sounds, soundsFilter, search]);
@ -51,7 +56,6 @@ export function SoundsTab() {
ref?.stop(getAudioContext().currentTime + 0.01);
});
});
return (
<div id="sounds-tab" className="px-4 flex flex-col w-full h-full text-foreground">
<Textbox placeholder="Search" value={search} onChange={(v) => setSearch(v)} />
@ -65,9 +69,9 @@ export function SoundsTab() {
drums: 'drum-machines',
synths: 'Synths',
user: 'User',
importSounds: 'import-sounds',
}}
></ButtonGroup>
<ImportSoundsButton onComplete={() => settingsMap.setKey('soundsFilter', 'user')} />
</div>
<div className="min-h-0 max-h-full grow overflow-auto text-sm break-normal pb-2">
@ -101,7 +105,55 @@ export function SoundsTab() {
</span>
);
})}
{!soundEntries.length ? 'No custom sounds loaded in this pattern (yet).' : ''}
{!soundEntries.length && soundsFilter === 'importSounds' ? (
<div className="prose dark:prose-invert min-w-full pt-2 pb-8 px-4">
<ImportSoundsButton onComplete={() => settingsMap.setKey('soundsFilter', 'user')} />
<p>
To import sounds into strudel, they must be contained{' '}
<a href={`${baseNoTrailing}/learn/samples/#from-disk-via-import-sounds`} target="_blank">
within a folder or subfolder
</a>
. The best way to do this is to upload a samples folder containing subfolders of individual sounds or
soundbanks (see diagram below).{' '}
</p>
<pre className="bg-background" key={'sample-diagram'}>
{`└─ samples <-- import this folder
swoop
swoopshort.wav
swooplong.wav
swooptight.wav
smash
smashhigh.wav
smashlow.wav
smashmiddle.wav`}
</pre>
<p>
The name of a subfolder corresponds to the sound name under the user tab. Multiple samples within a
subfolder are all labelled with the same name, but can be accessed using .n( ) - remember sounds are
zero-indexed and in alphabetical order!
</p>
<p>
For more information, and other ways to use your own sounds in strudel,{' '}
<a href={`${baseNoTrailing}/learn/samples/#from-disk-via-import-sounds`} target="_blank">
check out the docs
</a>
!
</p>
<h3>Preview Sounds</h3>
<pre className="bg-background" key={'sample-preview'}>
n("0 1 2 3 4 5").s("sample-name")
</pre>
<p>
Paste the line above into the main editor to hear the uploaded folder. Remember to use the name of your
sample as it appears under the "user" tab.
</p>
</div>
) : (
''
)}
{!soundEntries.length && soundsFilter !== 'importSounds'
? 'No custom sounds loaded in this pattern (yet).'
: ''}
</div>
</div>
);