Skip to content

Instantly share code, notes, and snippets.

@angelormrl
Last active May 8, 2019 17:50
Show Gist options
  • Save angelormrl/2c2acd548c499b3e228af607592881d2 to your computer and use it in GitHub Desktop.
Save angelormrl/2c2acd548c499b3e228af607592881d2 to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"collapsed": true
},
"source": [
"## Rendering and Exporting\n",
"\n",
"This notebook handles the first step in the generation of our data set for synthesiser patch recognition. Using the Renderman library, developed by Leon Fedden, it will render and write to .wav audio samples from a VST synth at a variety of preset configurations. The stages of this process are:\n",
"1. Fill list with VST preset names in directory.\n",
"2. Load VST synthesiser.\n",
"3. Load preset.\n",
"4. Render VST audio and write to wav for each MIDI note between min and max.\n",
"5. repeat step 4 for each preset."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"## ======== libraries ======== ##\n",
"\n",
"\n",
"# for loading presets to and rendering audio from VST's\n",
"import librenderman as rm\n",
"\n",
"# retrieves lists of filenames in a directory\n",
"from os import listdir\n",
"\n",
"# handles writing to wave file format\n",
"import wave\n",
"\n",
"# returns string containg values packed to the given format\n",
"from struct import pack\n",
"\n",
"# clears output and will allow us to create a progress indicator\n",
"from IPython.display import clear_output"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"## ======== function definitions ======== ##\n",
"\n",
"\n",
"# sorts indices for files positions in a directory into sublists corresponding to their class\n",
"def label_indices(preset_names, labels):\n",
" \n",
" indices = []\n",
" \n",
" # loops through files in directory and checks whether class label is present in eaches name\n",
" for i in range(len(labels)):\n",
" \n",
" indices.append([])\n",
" \n",
" for j in range(len(preset_names)):\n",
" \n",
" if(labels[i] in preset_names[j]):\n",
" \n",
" # if label is present in name store file index\n",
" indices[i].append(j)\n",
" \n",
" return indices\n",
"\n",
"\n",
"# render audio frames for indicated preset and note\n",
"def render_frames(plugin_path, final_preset_path, note):\n",
" \n",
" # due to a bug with the library the engine must be initiated every time a note is rendered\n",
" engine = rm.RenderEngine(44100, 512)\n",
"\n",
" engine.load_plugin(plugin_path)\n",
" \n",
" engine.load_preset(final_preset_path)\n",
"\n",
" engine.render_patch(note, 127, 3.0, 4.0)\n",
"\n",
" audio_frames = engine.get_audio_frames()\n",
" \n",
" return audio_frames\n",
"\n",
"\n",
"# concatenates strings to form final write path\n",
"def generate_final_path(write_path, label, vst_name, n, note):\n",
" \n",
" final_write_path = write_path + \"/\" + label + \"_\" + vst_name + \"_\" + str(n) + \"_\" + str(note) + \".wav\"\n",
" \n",
" return final_write_path\n",
"\n",
"\n",
"# write audio to wav at path\n",
"def write_wav(final_write_path, audio_frames):\n",
" \n",
" write = wave.open(final_write_path, 'w')\n",
"\n",
" # number of channels, sample depth and sample rate are some of the parameters\n",
" params = (1, 2, 44100, len(audio_frames), 'NONE', 'NONE')\n",
"\n",
" write.setparams(params)\n",
"\n",
" # loop through each frame of audio\n",
" for i in range(len(audio_frames)):\n",
" \n",
" # multiply each frame by 1000 as the output of renderman is low\n",
" byte = int(audio_frames[i] * 10000)\n",
" \n",
" data = pack('<h', byte)\n",
" \n",
" write.writeframesraw(data)\n",
" \n",
" write.close()\n",
" \n",
" return final_write_path + \" written to wav!\"\n",
"\n",
"\n",
"# returns positions of a target character in a string\n",
"def find_char(target, string):\n",
"\n",
" positions = []\n",
"\n",
" # compares each element of a string with the target character\n",
" for i, char in enumerate(string):\n",
" \n",
" if char == target:\n",
" \n",
" positions.append(i)\n",
" \n",
" return positions\n",
"\n",
"\n",
"# extracts vst name form path\n",
"def vst_name_from_path(plugin_path):\n",
" \n",
" # locate slashes and fullstops in file names to locate vst name which is between final slash and full stop\n",
" slashes = find_char(\"/\", plugin_path)\n",
" \n",
" full_stop = find_char(\".\", plugin_path)\n",
" \n",
" name = plugin_path[slashes[-1]+1:full_stop[0]]\n",
" \n",
" return name\n",
"\n",
"\n",
"# progress as completed/total samples processed in output\n",
"def percentage_progress(total, current):\n",
" \n",
" percentage = float(current / total) * 100\n",
" \n",
" percentage = round(percentage, 2)\n",
" \n",
" message = \"progress: \" + str(percentage) + \"%\"\n",
" \n",
" # this function clears the previous output when the next message is printed\n",
" clear_output(wait = True)\n",
" \n",
" return message\n",
"\n",
"\n",
"# calculates total samples to render and export for use in progress calculator\n",
"def sample_num(indices, max_note, min_note):\n",
" \n",
" total_presets = 0\n",
"\n",
" for i in range(len(indices)):\n",
" \n",
" total_presets += len(indices[i])\n",
" \n",
" # total examples equals number of presets multiplied by the number of midi notes rendered from each\n",
" total_samples = total_presets * (max_note-min_note)\n",
" \n",
" return total_samples"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Main\n",
"In the cell below the entire rendering and writing process is automated. When running an indicator in the cell output shows the percentage progress through the task. This is useful as it can take a long time depending on the number of examples to render."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"progress: 101.19%\n",
"rendering and exporting complete!\n"
]
}
],
"source": [
"## ======== main ======== ##\n",
"\n",
"\n",
"plugin_path = '/Library/Audio/Plug-Ins/VST/KORG/Monopoly.vst'\n",
"\n",
"presets_path = \"/Users/angelorussell/Desktop/monopoly_presets_final\"\n",
"\n",
"# lists names of all VST presets in directory\n",
"preset_names = listdir(presets_path)\n",
"\n",
"write_path = \"/Users/angelorussell/Desktop/monopoly_renders\"\n",
"\n",
"labels = [\"Lead\", \"Bass\", \"Pad\"]\n",
"\n",
"# only renders MIDI notes between min and max\n",
"#c0\n",
"min_note = 24\n",
"#c7\n",
"max_note = 108\n",
"\n",
"# sorts indices for file positions in a directory into sublists corresponding to their class \n",
"indices = label_indices(preset_names, labels)\n",
"\n",
"# total samples to render calculated to determien progress\n",
"total_samples = sample_num(indices, max_note, min_note)\n",
"\n",
"vst_name = vst_name_from_path(plugin_path)\n",
"\n",
"# counts number of examples rendered\n",
"current = 0\n",
"\n",
"print percentage_progress(total_samples, current)\n",
"\n",
"# loop through each class label\n",
"for i in range(len(labels)):\n",
" \n",
" # loop through each preset file index in order of class label\n",
" for j in range(len(indices[i])):\n",
" \n",
" # concatenate string for preset path\n",
" final_preset_path = presets_path + \"/\" + preset_names[indices[i][j]]\n",
" \n",
" for note in range(min_note, max_note + 1):\n",
" \n",
" # render audio frames\n",
" audio_frames = render_frames(plugin_path, final_preset_path, note)\n",
" \n",
" # generate file name and path to be written to\n",
" final_write_path = generate_final_path(write_path, labels[i], vst_name, j, note)\n",
" \n",
" # write file\n",
" write_wav(final_write_path, audio_frames)\n",
" \n",
" current += 1\n",
" \n",
" print percentage_progress(total_samples, current)\n",
"\n",
"print \"rendering and exporting complete!\""
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 2",
"language": "python",
"name": "python2"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 2
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython2",
"version": "2.7.14"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment