REF / Music API / SampleMgr

Ascene . Agraph . Aengine
Anode . Modulator . Envelope
Songbook . Song . TimeKeeper
Voices . SampleMgr . StreamMgr
Loader . Async . Plot
Random . Rhythm . Util
MIDI . OSC . HID . Piano
Music Theory with Tonal

right-click to navigate to page sections


You use audio sample files to produce music.
You hunger for new, unusual samples for inspiration.
The internet has samples.

SampleMgr describes, collects and organizes your sample files. Use it to fill up your local drive with the samples you want rather than a random pile that come with music apps.

SampleMgr manages audio sample files and communicates their location to Hz.Samplo or other sample file consumer. SampleMgr supports asynchronous (background) downloading, caching and serving of network-based samples.

Samples are organized on concepts of repository, library, bank, and voice. We can think of a repository as equivalent to a github repository (repo) that obeys a standard directory structure. We currently support two file organizing schemes below a repository:

  1. repo/bank/voice, eg: MIDIJS/FatBoy/accordion
  2. repo/voice, eg: DrumKits/AkaiXR10
Concept Description
repo name+internet URL containing sample libraries or banks.
bank collection of voices or sounds
voice collection of sound files organized either by MIDI key. Voices can be either tonal or percussive.
sound collection of 1 or more sound files organized sound name (eg bd, hh). These are usually percussive.

Repo File

Since the internet is a big place, we introduce the repo file. This file is a list of your favorite repositories (their internet location and contents). The repo file is used to convert a simple name to one or more internet URLs and these are converted to a directory name in your workspace. Hz ships with a default repo file, shown below. You can create your own repo file and TOC-files to suit your own tastes.

All this machinery is presented in order to make literally thousands of internet-hosted sample files easily accessible automatically and portably. Of course you also have your own personal/private collection of sample files and these can be either be explicitly organized into your repo file or presented to SampleMgr directly in your songs.

Strudel Support

If you are a Strudel user and have your own favorite online repositories you can access their files directly through SampleMgr methods. This approach bypasses the repo file just-described but requires these steps:

  1. fetch its TOC-file, strudel.json
  2. fetch a subset of files described within its TOC to our local sample file cache.

Note that this approach is the same as used by standalone Strudel differing only insofar as the sample files are downloaded and managed by your internet browser and secreted in an obscure location on your computer's filesystem. We've streamlined this process via Synchronize() method described below.

SampleMgr API

Here's a quick overview of the SampleMgr API. For most cases these one or two methods are all that's required to use internet-based sample files in your projects. All the remaining details are presented for more advanced use-cases.

Approach 1: Preload Samples via Repolist

For the common use-case where you know a bank and a voice, you only need a single method to ensure sample files are available on your computer as shown here:

let asamps = await SampleMgr.PreloadSamples("MIDIJS/FatBoy", "accordion");
let presetStr = asamps.AsPreset();

Once complete, you'll find 88 sample files below your current workspace:

${WS}/_cache/github/paulrosen/midi-js-soundfonts/FatBoy/accordion-mp3/
Approach 2: Preload Samples from Strudel-compatible Repositories
  1. fetch the online table of contents file (TOC), strudel.json from the repository via eg:
  let repo = "github:tidalcycles/dirt-samples";
  let sampleMap = await SampleMgr.FetchSampleMap(repo);
  1. preload a subset of sound files by downloading them to a cache directory on your computer's filesystem via:
  let [presetStr, sndTOC] =  await SampleMgr.PreloadRemoteSamples(sampleMap, 
                                                          sounds, asPreset);

For your convenience we've combined these two steps into a single method, async Synchronize(requestlist). This method supports multiple repo requests defined as the combination of a repo reference and the collection of sounds you require from it. Note that the elements of requestlist may be interpretted as MIDI channel indices. Moreover, when a repo supports tonal sounds (like a soundfont), only a single sound should be present on a channel.

let {result, preset} = await SampleMgr.Synchronize([ 
   {
        url: 'github:eddyflux/crate',
        sounds: ['bd', 'rim', 'sd', 'rd', 'hh'],
   },
   {
        url: 'hz:MIDIJS/FatBoy',
        sounds: ['electric_piano_1'], // one tonal sound  per channel
        aliases: {
            'gm_epiano1': 'electric_piano_1', 
            'epiano': 'electric_piano_1', 
        }
   },
   {
        url: 'hz:MIDIJS/FatBoy',
        sounds: ['acoustic_bass'],
        aliases: {
            'gm_acoustic_bass': 'acoustic_bass',
            'abass': 'acoustic_bass'
        }
   },
]);
Use the Local Sample Files

After preloading ther requested sample files, you can either inspect the result for individual local file path names or make these files known to Hz.Samplo like so:

await samplo.LoadPreset(presetStr, "MIDIJS/FatBoy_accordion"); 

You can find complete examples here.

SampleMgr
SampleMgr method Description
async Init(repolist?) Optional, returns a promise that resolves to an initialized SMgrRepolist. If filename isn't provided, the default is returned.
GetRepolists() Returns an array of names of repolists.
GetRepolist(name) Returns the named SMgrRepoList.
async PreloadSamples(bank, voice, repolist=null) Ensures that the bank+voice sample files are available in the local cache. Returns a promise that resolves to a SMgrVoice instance. This can be used to produce a Hz.Plugin-style preset value.
AsPresetFromLocalVoice(cwd, name, voicedata) Returns a Hz.Samplo preset that refers to a locally defined voice. voicedata is either an array or a dictionary.
async FetchSampleMap(reporef) Returns a sample map associated with an internet sample file source.
async PreloadRemoteSamples(sampleMap, sounds, asPreset) Ensures that sample files associated with the list of sounds(voices) are available in the local cache. Returns a promise that resolves to a pair: [value, sndMap] where the type of value depends upon asPreset. sndMap is used to map sound references (like "bd:0") to integer offsets within the sample set.
{result, preset} = async Synchronize(reqlist) A convenience method that combines FetchSampleMap and PreloadRemoteSamples.
SMgrRepolist
SMgrRepolist method Description
GetFile() Returns the filename associated with this repolist.
async Initialize() Ensures that all TOC files supporting the repo are loaded.
GetBankNames() Returns a list of bank names known to the repo.
GetBank(name) Returns a SMgrBank for the named repo bank.
SMgrBank
SMgrBank method Description
GetName() returns the bank name.
GetVoiceNames() returns the list of voices present in the bank.
GetVoice(name) returns the SMgrVoice for the voicename in the bank.
SMgrVoice
SMgrVoice method Description
AsPreset() returns a Hz.Samplo preset that refers to a locally cached voice files.
GetName() returns the voice's name
GetBank() returns the voice's bank name
IsPercussive() returns true if the voice is percussive
IsTonal() returns true if the voice is tonal
GetCategory() returns either "tonal" or "percussive"
GetURLs() returns an array of local sample file references
GetNumPercSamps() returns 0 or the size of the samples array
GetNumTonalSamps() returns 0 or the number of entries in the samples object
GetURLForNote(note) returns [fileref, transpose]
GetURLForIndex(i) returns fileref at i

Examples

You can find complete examples here.

Repo File

The repo file is a JSON formatted dictionary that maps a repo name to a repo TOC (table of contents) file. When you request samples for VCSL/handchimes, we first locate the repo named VCSL in the repolist, then find handchimes in its TOC. There we'll find an enumeration of the voice sample files.

{
    "Dirt": {
        "URL": "https://raw.githubusercontent.com/tidalcycles/Dirt-Samples/master",
        "TOC": "tocs/dirt-samples.json",
        "CacheDir":  "github/tidalcycles/Dirt-Samples"
    },
    "Strudel": {
        "URL": "https://raw.githubusercontent.com/tidalcycles/strudel/main/website/public",
        "TOC": "tocs/strudel.json",
        "CacheDir":  "github/tidalcycles/strudel"
    },
    "DrumKits": {
        "URL": "https://raw.githubusercontent.com/ritchse/tidal-drum-machines/main/machines",
        "TOC": "tocs/tidal-drum-machines.json",
        "CacheDir":  "github/ritchse/tidal-drum-machines",
        "Multibank": 1
    },
    "VCSL": {
        "URL": "https://raw.githubusercontent.com/sgossner/VCSL/master",
        "TOC": "tocs/vcsl.json",
        "CacheDir":  "github/sgossner/VCSL"
    },
    "midi-js-soundfonts": {
        "URL": "https://raw.githubusercontent.com/paulrosen/midi-js-soundfonts/master",
        "TOC": "tocs/midi-js-soundfonts.json",
        "CacheDir":  "github/paulrosen/midi-js-soundfonts",
        "Multibank": 1,
        "LICENSE": "MIT, Copyright (C) 2012 Benjamin Gleitzman (gleitz@mit.edu)"
    },
    "loophole": {
        "URL": "https://loophole-letters.vercel.app/samples",
        "TOC": "tocs/loophole.json",
        "CacheDir":  "loophole-letters.vercel.app/samples"
    }
}

Repo TOC File

The Repo TOC file is a JSON formatted dictionary that maps voice names to their collection of sample files. Here's a portion of the VCSL TOC file. We've selected this subset because it shows the difference between tonal and percussive voices. The first is a dictionary whose keys are note-names and percussion voice are an array indexed by a voice variation/index. In both cases the value of each entry is a relative pathname to a sample file.

{
  "handchimes": {
    "A#3": "Idiophones/Struck Idiophones/Hand Chimes/sus_A#3_r01_main.wav",
    "A#5": "Idiophones/Struck Idiophones/Hand Chimes/sus_A#5_r01_main.wav",
    "A4": "Idiophones/Struck Idiophones/Hand Chimes/sus_A4_r01_main.wav",
    "C3": "Idiophones/Struck Idiophones/Hand Chimes/sus_C3_r01_main.wav",
    "C4": "Idiophones/Struck Idiophones/Hand Chimes/sus_C4_r01_main.wav",
    "C5": "Idiophones/Struck Idiophones/Hand Chimes/sus_C5_r01_main.wav",
    "C6": "Idiophones/Struck Idiophones/Hand Chimes/sus_C6_r01_main.wav",
    "D3": "Idiophones/Struck Idiophones/Hand Chimes/sus_D3_r01_main.wav",
    "D4": "Idiophones/Struck Idiophones/Hand Chimes/sus_D4_r01_main.wav",
    "D5": "Idiophones/Struck Idiophones/Hand Chimes/sus_D5_r01_main.wav",
    "E3": "Idiophones/Struck Idiophones/Hand Chimes/sus_E3_r01_main.wav",
    "E4": "Idiophones/Struck Idiophones/Hand Chimes/sus_E4_r01_main.wav",
    "E5": "Idiophones/Struck Idiophones/Hand Chimes/sus_E5_r01_main.wav",
    "F#3": "Idiophones/Struck Idiophones/Hand Chimes/sus_F#3_r01_main.wav",
    "F#4": "Idiophones/Struck Idiophones/Hand Chimes/sus_F#4_r01_main.wav",
    "F#5": "Idiophones/Struck Idiophones/Hand Chimes/sus_F#5_r01_main.wav",
    "G#3": "Idiophones/Struck Idiophones/Hand Chimes/sus_G#3_r01_main.wav",
    "G#4": "Idiophones/Struck Idiophones/Hand Chimes/sus_G#4_r01_main.wav",
    "G#5": "Idiophones/Struck Idiophones/Hand Chimes/sus_G#5_r01_main.wav"
  },
  "hihat": [
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_Close_rr1_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_Close_rr2_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitC_v1_rr1_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitC_v1_rr2_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitC_v2_rr1_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitC_v2_rr2_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitC_v3_rr1_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitC_v3_rr2_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitC_v4_rr1_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitC_v4_rr2_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitLoose_rr1_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitLoose_rr2_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitOC_rr5_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitO_rr1_Mid.wav",
    "Idiophones/Struck Idiophones/Hi-Hat Cymbal/HiHat_HitO_rr2_Mid.wav"
  ],
 }
home .. topics .. interface .. reference .. examples .. tipjar