Mx.Samples

mx.samples

mx.samples: like mr.coffee or mr.radar, but for instrument samples.

us as a keyboard instrument or in another script. mx.samples provides an accessible way to utilize the vast trove of free instrument sample libraries. for instance, you can load in a piano that has been sampled on multiple dynamics and variations and key releases.

the core of the script + supercollider engine handles the voices and the instruments. you can have unlimited samples on disk because samples are loaded dynamically - only loading into memory when needed (max 200 samples can be loaded though). no latency on loading because it will load in the background (and use the closest pitched sample in the meantime).

my motivation for this script was to have a really nice sounding piano on the norns. also i wanted to be able to have a library of samples that works well with tmi (see studies/study1.lua and demo above) but can also be used for future projects in the idea galaxy.

a massive thank you to @zebra for helping me post-process the UofI piano samples - there is a great script available to “de-pop” samples that had glitches in recording, thanks to that work. also this project wouldn’t be possible without the generosity of the folks submitting their samples to be used freely at pianobook.co.uk and at the University of Iowa Electronic Music department.

requirements

  • norns
  • midi controller OR use in a script

documentation

mx.samples can be used as a keyboard (selecting sound+parameters via menus) or as a library (selecting sound+parameters via code).

as a keyboard

you can use mx.samples as a keyboard. just plugin your midi keyboard, open the script and choose a sample. samples are available to download (processed by me, you can process your own too - see below).

there are a bunch of effects (filters / delay) and options (tuning, down-sampling, playing releases, velocity scaling) available from the parameters menu PARAMETERS -> MX.SAMPLES.

“warming” up the keyboard: the very first note you play will not “play” (known bug) because it is loading the sample. every subsequent new note will re-pitch the loaded sample or it will load in a sample for that note to be used the next time (so no latency from load). this means that you can get the best sound by playing the notes you want to play once before you play them.

as a library

you can use mx.samples as a lua library for your project (see demo above). the api is pretty simple to include this into another script if you want a bunch of different voices. (another goal here - to use with tmi). instruments are loaded dynamically so you can add as many as you want.

see study1.lua for an example that uses tmi to do the sequencing.

basically the syntax would be:

mxsamples=include("mx.samples/lib/mx.samples")
engine.name="MxSamples"
skeys=mxsamples:new()

-- play an instrument
skeys:on({name="ghost piano",midi=60,velocity=120})
skeys:on({name="box violin",midi=42,velocity=120})

-- turn them off
skeys:off({name="ghost piano",midi=60})
skeys:off({name="box violin",midi=42})

the parameters can be added into the on function as well:

skeys:on({
	name="ghost piano",midi=60,velocity=120,
	attack=1,
	release=3,
	-- every parameter in the menu is available here
})

getting samples

this script will allow you to download samples that i’ve already processed. in theory you can use any kontakt / vst sample pack if you have access to the raw audio. in the samples/ folder there is a utility script convert.py that is specific to each type of sample and shows basically how its done (its easy). here’s an example for the UofI piano.

the current samples are from the following sources, which are free and do not restrict to distributing them for this purpose:

download

;install https://github.com/schollz/mx.samples

80 Likes

I don’t seem to be getting any output from norns. I downloaded 3 sample libraries (included in the script) and using microlab plugged in. Checked several midi channels just in case.

1 Like

Working perfectly here after a few tweaks with the OP1 midi, only query here is assuming its
ok to delete the .zip file from the samples folder to save a bit of space on my shields?

1 Like

tried with op-1 still no output

1 Like

yeah! sorry about that - that was a bug. i fixed it now so the zip file is deleted after extraction.

op-1 works for me but i’ve had weird problems with it in the past for other midi stuff. can you try doing this (in order): plug in op-1 and turn on, goto SYSTEM > DEVICES > MIDI and re-add it. then start mx.samples. then goto a sound bank (1-8) on the op-1. then it should work :crossed_fingers:

2 Likes

Sweet! Looking forward to tying this out. Nice demo video.

1 Like

It works now on both OP-1 and Microlab. Thanks!

2 Likes

mx.samples working perfectly with op-1, but some issues with tmi study - here’s what maiden says:

Summary

script load: /home/we/dust/code/mx.samples/studies/study1.lua

cleanup

script clear

including /home/we/dust/code/mx.samples/lib/mx.samples.lua

script run

loading engine: MxSamples

reading PMAP /home/we/dust/data/mx.samples/studies/study1/study1.pmap

m.read: /home/we/dust/data/mx.samples/studies/study1/study1.pmap not read.

Engine.register_commands; count: 4

___ engine commands ___

mxsamplesload is

mxsamplesoff i

mxsampleson iifffffffffffff

mxsamplesrelease

___ polls ___

amp_in_l

amp_in_r

amp_out_l

amp_out_r

cpu_avg

cpu_peak

pitch_in_l

pitch_in_r

script init

ls: cannot access ‘/home/we/dust/code/mx.samples/samples/depop.py/’

: Not a directory

ls: cannot access ‘/home/we/dust/code/mx.samples/samples/utils.py/’

: Not a directory

including /home/we/dust/code/tmi/lib/tmi.lua

including /home/we/dust/code/tmi/lib/json.lua

including /home/we/dust/code/tmi/lib/music.lua

including /home/we/dust/code/tmi/lib/utils.lua

including /home/we/dust/code/tmi/lib/utils.lua

including /home/we/dust/code/kolor/lib/lattice.lua

tmi: name_folder: /home/we/dust/data/tmi/

swell nil

melody nil

bass nil

chords nil

tmi: connecting /home/we/dust/code/mx.samples/studies/chords.tmi to chords

loading chords.tmi into chords1

swell nil

melody nil

bass nil

tmi: connecting /home/we/dust/code/mx.samples/studies/bass.tmi to bass

chords nil

loading bass.tmi into bass2

swell nil

melody nil

tmi: connecting /home/we/dust/code/mx.samples/studies/melody.tmi to melody

bass nil

chords nil

loading melody.tmi into melody3

swell nil

tmi: connecting /home/we/dust/code/mx.samples/studies/swell.tmi to swell

melody nil

bass nil

chords nil

loading swell.tmi into swell4

toggle_play

tmi: instrument chords, track 1, measure 1, beat 1.0, note_on=48, v=127

tmi: instrument chords, track 1, measure 1, beat 1.0, note_on=52, v=127

sample_closest_loaded: /home/we/dust/code/mx.samples/samples/steinway_model_b/48.2.3.1.0.wav on voice 1

tmi: instrument chords, track 1, measure 1, beat 1.0, note_on=55, v=127

sample_closest_loaded: /home/we/dust/code/mx.samples/samples/steinway_model_b/52.2.3.1.0.wav on voice 2

tmi: instrument chords, track 1, measure 1, beat 1.0, note_on=59, v=127

sample_closest_loaded: /home/we/dust/code/mx.samples/samples/steinway_model_b/55.2.3.1.0.wav on voice 3

tmi: instrument bass, track 2, measure 1, beat 1.7916666666667, note_on=36, v=127

lua: /home/we/norns/lua/core/clock.lua:82: /home/we/dust/code/mx.samples/lib/mx.samples.lua:247: attempt to index a nil value (field ‘?’)

stack traceback:

[C]: in function ‘error’

/home/we/norns/lua/core/clock.lua:82: in function ‘core/clock.resume’

1 Like

I enjoy playing with piano tones and microtonal tuning.

Is it possible to pass pitchbend parameters to note-on? Or even better, is it possible to invoke note on with a hertz frequency instead of a MIDI number?

3 Likes

Thanks, gonna give this a try. Into the idea of soundfonts at the moment :slight_smile:

it will load in the background (and use the closest pitched sample in the meantime).

super clever idea!

1 Like

A norns piano is so helpful - thank you! this is going to be a favourite of mine.

I’m finding it’s triggering notes when I press a key AND when I release. It’s on an M-Audio Keystation32.

Any idea if that’s just me?

1 Like

Beautiful thank you for this

1 Like

can you share some of the output from maiden? that seems weird…

i added this now! you should be able to do

skeys:on({name="ghost piano",hz=440,velocity=120})

(untested by me, but should work :crossed_fingers: )

i think maybe you don’t have the samples needed - which is my fault because i never specified which you need. you should download “cello”, “alto sax choir”, “steinway model b”, and “ghost piano” for it to work. i also added this into the study itself so it tells you more obviously.

great :slight_smile: thanks!

and thank you for the kind words @encephalitislethargi, and @ohm - much appreciated.

3 Likes

I’m not sure how to share output from maiden, but I’ll check again today and see if I can share a video clip or work out how to share from maiden.

1 Like

First of all - huge thanks for your work, amazing stuff!
Have some feedback:
I have no output with a Arturia Keystep, tried all the channels and different modes. Tried re-adding it in settings. It works with other scripts. The script works straight away with Op-z. And I have this going in Maiden:

When I play notes on op-z it says “sample_closest_loaded”, when after that I am trying to play note on Keystep it gives me loads of cannot acces errors. I only have steinway_model_b, alto_sax and ghost piano downloaded.

Log

sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/65.1.1.1.0.wav on voice 3
mxsamples: turning off alto_sax_choir:65
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/63.1.1.1.0.wav on voice 4
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/69.1.1.1.0.wav on voice 5
mxsamples: turning off alto_sax_choir:62
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/71.1.1.1.0.wav on voice 6
mxsamples: turning off alto_sax_choir:69
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/69.1.1.1.0.wav on voice 7
mxsamples: turning off alto_sax_choir:72
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/65.1.1.1.0.wav on voice 8
mxsamples: turning off alto_sax_choir:69
mxsamples: turning off alto_sax_choir:65
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/63.1.1.1.0.wav on voice 9
mxsamples: turning off alto_sax_choir:64
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/59.1.1.1.0.wav on voice 10
mxsamples: turning off alto_sax_choir:59
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/65.1.1.1.0.wav on voice 11
mxsamples: turning off alto_sax_choir:65
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/77.1.1.1.0.wav on voice 1
mxsamples: turning off alto_sax_choir:76
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/alto_sax_choir/71.1.1.1.0.wav on voice 12
mxsamples: turning off alto_sax_choir:72
ls:
cannot access ‘/home/we/dust/code/mx.samples/samples/box_violin/.wav’
: No such file or directory
ls: cannot access '/home/we/dust/code/mx.samples/samples/cello/
.wav’
: No such file or directory
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/cello_pad/.wav’
: No such file or directory
ls: cannot access '/home/we/dust/code/mx.samples/samples/tatak_piano/
.wav’
: No such file or directory
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/steinway_model_b/60.3.3.1.0.wav on voice 13
mxsamples: turning off steinway_model_b:60
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/steinway_model_b/62.3.3.1.0.wav on voice 2
mxsamples: turning off steinway_model_b:62
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/box_violin/.wav’
: No such file or directory
ls: cannot access '/home/we/dust/code/mx.samples/samples/cello/
.wav’
: No such file or directory
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/cello_pad/.wav’
: No such file or directory
ls: cannot access '/home/we/dust/code/mx.samples/samples/tatak_piano/
.wav’
: No such file or directory
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/box_violin/.wav’
: No such file or directory
ls: cannot access '/home/we/dust/code/mx.samples/samples/cello/
.wav’
: No such file or directory
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/cello_pad/.wav’
: No such file or directory
ls: cannot access '/home/we/dust/code/mx.samples/samples/tatak_piano/
.wav’
: No such file or directory
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/steinway_model_b/62.3.3.1.0.wav on voice 3
mxsamples: turning off steinway_model_b:62
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/steinway_model_b/62.3.3.1.0.wav on voice 14
mxsamples: turning off steinway_model_b:62
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/box_violin/.wav’
: No such file or directory
ls: cannot access '/home/we/dust/code/mx.samples/samples/cello/
.wav’
: No such file or directory
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/cello_pad/.wav’
: No such file or directory
ls:
cannot access '/home/we/dust/code/mx.samples/samples/tatak_piano/
.wav’
: No such file or directory
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/box_violin/.wav’
: No such file or directory
ls: cannot access '/home/we/dust/code/mx.samples/samples/cello/
.wav’
: No such file or directory
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/cello_pad/.wav’
: No such file or directory
ls: cannot access '/home/we/dust/code/mx.samples/samples/tatak_piano/
.wav’
: No such file or directory
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/ghost_piano/58.2.2.1.0.wav on voice 4
mxsamples: turning off ghost_piano:62
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/ghost_piano/58.2.2.1.0.wav on voice 5
mxsamples: turning off ghost_piano:62
ls: cannot access ‘/home/we/dust/code/mx.samples/samples/box_violin/.wav’
: No such file or directory
ls:
cannot access '/home/we/dust/code/mx.samples/samples/cello/
.wav’
: No such file or directory
ls:
cannot access ‘/home/we/dust/code/mx.samples/samples/cello_pad/.wav’
: No such file or directory
ls:
cannot access '/home/we/dust/code/mx.samples/samples/tatak_piano/
.wav’
: No such file or directory
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/steinway_model_b/62.3.3.1.0.wav on voice 6
mxsamples: turning off steinway_model_b:62
sample_closest_loaded: /home/we/dust/code/mx.samples/samples/steinway_model_b/62.3.3.1.0.wav on voice 7
mxsamples: turning off steinway_model_b:62
ls:
cannot access ‘/home/we/dust/code/mx.samples/samples/box_violin/.wav’
: No such file or directory
ls:
cannot access '/home/we/dust/code/mx.samples/samples/cello/
.wav’
: No such file or directory
ls:
cannot access ‘/home/we/dust/code/mx.samples/samples/cello_pad/.wav’
: No such file or directory
ls:
cannot access '/home/we/dust/code/mx.samples/samples/tatak_piano/
.wav’
: No such file or directory
ls:
cannot access ‘/home/we/dust/code/mx.samples/samples/box_violin/.wav’
: No such file or directory
ls:
cannot access '/home/we/dust/code/mx.samples/samples/cello/
.wav’
: No such file or directory
ls:
cannot access ‘/home/we/dust/code/mx.samples/samples/cello_pad/.wav’
: No such file or directory
ls:
cannot access '/home/we/dust/code/mx.samples/samples/tatak_piano/
.wav’
: No such file or directory

Hope that helps, let me know if you need to repeat some steps to debug, thank you:)

1 Like

Here’s a question - Can I use this to, for example, use a piano sound on the Awake script?

2 Likes

Amazing work. Incredible community here :slight_smile:

I’ve just tested with all libraries, and I’ve notice the sustain pedal doesn’t work. There is some way to fix it? In other hand, I’ve notice some little bit latency between pushing a key and listening the sound. I guess is just for the samples on library, because for example sax and cello is more evident this latency than the pianos.

Have anyone noticed this little issues?

1 Like

You can. I just updated my script to play with mx.samples. It’s pretty straight forward following the guide in the top post.

2 Likes

thanks for your log! it helps and its puzzling. if you can, could you update the script and try again? i updated it to add the midi information to the log on a note-on event so i can see exactly what Keystep is sending.

there is no sustain pedal, yet. sustain pedal would be cool to add but its a little tricky. there are only 14 voices available, which is not a lot when using sustain (at least for me). the note releases and the note sustains will likely collide and it causes an unpleasant click when supercollider abruptly changes the buffers to the new note when stealing voices. there are a couple of fixes - i could have voice stealing work by never taking a “used voice” (so some keys end up not emitting then) or i could try to raise the number of voices in supercollider. i think the latter is possible but i haven’t yet figured it out without supercollider getting really mad (it makes this really mad sounding buzz sound when i raise the voices past 20…). so still thinking on this one.

there are two main sources of latency.

first there is latency in the actual sample. i’ve tried to remove these as much as i can (the convert.py script using ffmpeg's silencedetection and trims samples to the front). but you may notice for instance the saxophone has a breathy note at the beginning (which i love) but there is latency because of the start of the breath sound. i added in a new parameter sample start which you can change to trim the sample even more in this case.

the second source of latency is the lua → supercollider playing. i can’t do much about this. but for something like the steinway model b i’m getting pretty low latency at least not very noticeable for me. i haven’t measured it but i’d guess < 50 ms. if you are getting much more than this then it might be a :bug:

1 Like

EDIT: IGNORE - turns out I’d accidentally set my keyboard to a different prog on midi channel 3 for some reason