{"id":9849,"date":"2026-09-15T11:06:07","date_gmt":"2026-09-15T10:06:07","guid":{"rendered":"https:\/\/andyland.info\/wordpress\/?p=9849"},"modified":"2026-09-15T11:11:07","modified_gmt":"2026-09-15T10:11:07","slug":"roland-smp-to-wav-converter","status":"publish","type":"post","link":"https:\/\/andyland.info\/wordpress\/roland-smp-to-wav-converter\/","title":{"rendered":"Roland SMP to WAV converter"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Over the last couple of years I owned 2 Roland SP404 MK2. Bought the first one, hated it, sold it. Found new interest, bought another one, sold it again. I, of course, saved all my projects &#8216;for later&#8217; but did not export the samples and got stuck with a huge pile of Roland&#8217;s proprietary SMP-files &#8211; a format the device uses that is distinct from the .WAV files it exports. Since their was no tool for conversion available I decided to try this on my own. Comparing SMP files with their exported WAV-counterpart showed an identical file-size between the 2 formats. By using little more than 1 sloppy AI prompt I was then able to decode the SPM container and create a python-script that you can use yourself.<\/p>\n\n\n\n<figure class=\"wp-block-image size-full\"><img loading=\"lazy\" decoding=\"async\" width=\"541\" height=\"962\" src=\"https:\/\/andyland.info\/wordpress\/wp-content\/uploads\/image.png\" alt=\"\" class=\"wp-image-9871\" srcset=\"https:\/\/andyland.info\/wordpress\/wp-content\/uploads\/image.png 541w, https:\/\/andyland.info\/wordpress\/wp-content\/uploads\/image-169x300.png 169w, https:\/\/andyland.info\/wordpress\/wp-content\/uploads\/image-84x150-1.png 84w\" sizes=\"auto, (max-width: 541px) 100vw, 541px\" \/><\/figure>\n\n\n\n<!--more-->\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The SMP format uses a RIFF-like 32-byte header, but with big-endian fields (unlike WAV&#8217;s little-endian ones): a &#8220;RFWV&#8221; magic number, followed by the total file size, sample rate, channel count, and bit depth. Immediately after the header sits a fixed block of roughly 480 extra bytes that don&#8217;t correspond to the actual sample. This appears to be leftover data from the sampler&#8217;s internal recording buffer \u2014 a byproduct of flash memory not being wiped between takes, so a trace of a previous recording lingers there. Past that block, the real audio begins: standard interleaved 16-bit little-endian PCM, sample-for-sample identical to the exported WAV (aside from occasional single-bit rounding noise, inaudible in practice).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">With the format mapped, converting .SMP files to standard .WAV is straightforward \u2014 just parse the header, skip the buffer remnant, and wrap the PCM data in a proper WAV container. You can use the converter provided on this website or take a look at the corrsponding github repository if you want to get a deeper inside into the code: <a href=\"https:\/\/github.com\/andymann\/roland-smp-to-wav-converter\">https:\/\/github.com\/andymann\/roland-smp-to-wav-converter<\/a><\/p>\n\n\n\n<div id=\"smp-converter\" style=\"max-width:480px;margin:1.5em auto;padding:1.5em;border:1px solid #ddd;border-radius:8px;font-family:sans-serif;\">\n  <h3 style=\"margin-top:0;\">SP-404 mk2 .SMP \u2192 .WAV Converter<\/h3>\n  <p style=\"font-size:0.9em;color:#555;\">Upload a single .SMP file (max 500&nbsp;KB). Conversion happens entirely in your browser \u2014 nothing is uploaded anywhere.<\/p>\n\n  <input type=\"file\" id=\"smp-file-input\" accept=\".smp,.SMP\" style=\"display:block;margin-bottom:1em;\">\n\n  <div id=\"smp-status\" style=\"font-size:0.9em;min-height:1.4em;\"><\/div>\n\n  <a id=\"smp-download-link\" style=\"display:none;padding:0.6em 1.2em;background:#2271b1;color:#fff;text-decoration:none;border-radius:4px;font-weight:bold;\">\n    Download .WAV\n  <\/a>\n<\/div>\n\n<script>\n(function () {\n  const MAX_SIZE = 500 * 1024; \/\/ 500 KB\n  const HEADER_SIZE = 32;\n  const LEADER_SIZE = 481;     \/\/ empirically-determined SP-404 buffer remnant\n  const DATA_START = HEADER_SIZE + LEADER_SIZE; \/\/ 513\n\n  const input = document.getElementById('smp-file-input');\n  const status = document.getElementById('smp-status');\n  const downloadLink = document.getElementById('smp-download-link');\n\n  function setStatus(msg, isError) {\n    status.textContent = msg;\n    status.style.color = isError ? '#c00' : '#555';\n  }\n\n  function convertSmpToWav(buffer) {\n    const view = new DataView(buffer);\n\n    \/\/ Check magic \"RFWV\"\n    const magic = String.fromCharCode(\n      view.getUint8(0), view.getUint8(1), view.getUint8(2), view.getUint8(3)\n    );\n    if (magic !== 'RFWV') {\n      throw new Error('Not a recognized .SMP file (bad header).');\n    }\n\n    const sampleRate = view.getUint32(8, false);  \/\/ big-endian\n    const channels   = view.getUint32(12, false);\n    const bits       = view.getUint32(16, false);\n    const bytesPerSample = bits \/ 8;\n    const frameSize = bytesPerSample * channels;\n\n    if (buffer.byteLength <= DATA_START) {\n      throw new Error('File too short to contain audio data.');\n    }\n\n    let pcm = buffer.slice(DATA_START);\n    const usableLen = Math.floor(pcm.byteLength \/ frameSize) * frameSize;\n    if (usableLen !== pcm.byteLength) {\n      pcm = pcm.slice(0, usableLen);\n    }\n\n    \/\/ Build a standard 44-byte WAV header\n    const dataSize = pcm.byteLength;\n    const blockAlign = frameSize;\n    const byteRate = sampleRate * blockAlign;\n    const wavBuffer = new ArrayBuffer(44 + dataSize);\n    const wav = new DataView(wavBuffer);\n\n    function writeString(offset, str) {\n      for (let i = 0; i < str.length; i++) {\n        wav.setUint8(offset + i, str.charCodeAt(i));\n      }\n    }\n\n    writeString(0, 'RIFF');\n    wav.setUint32(4, 36 + dataSize, true);\n    writeString(8, 'WAVE');\n    writeString(12, 'fmt ');\n    wav.setUint32(16, 16, true);          \/\/ fmt chunk size\n    wav.setUint16(20, 1, true);           \/\/ PCM\n    wav.setUint16(22, channels, true);\n    wav.setUint32(24, sampleRate, true);\n    wav.setUint32(28, byteRate, true);\n    wav.setUint16(32, blockAlign, true);\n    wav.setUint16(34, bits, true);\n    writeString(36, 'data');\n    wav.setUint32(40, dataSize, true);\n\n    new Uint8Array(wavBuffer, 44).set(new Uint8Array(pcm));\n\n    return { wavBuffer, sampleRate, channels, bits, dataSize };\n  }\n\n  input.addEventListener('change', function () {\n    downloadLink.style.display = 'none';\n    downloadLink.removeAttribute('href');\n\n    const file = input.files[0];\n    if (!file) return;\n\n    if (file.size > MAX_SIZE) {\n      setStatus('File is too large (' + (file.size \/ 1024).toFixed(1) + ' KB). Max allowed is 500 KB.', true);\n      return;\n    }\n\n    setStatus('Converting\u2026', false);\n\n    const reader = new FileReader();\n    reader.onload = function (e) {\n      try {\n        const result = convertSmpToWav(e.target.result);\n        const blob = new Blob([result.wavBuffer], { type: 'audio\/wav' });\n        const url = URL.createObjectURL(blob);\n\n        const outName = file.name.replace(\/\\.smp$\/i, '') + '.wav';\n        downloadLink.href = url;\n        downloadLink.download = outName;\n        downloadLink.style.display = 'inline-block';\n\n        setStatus(\n          'Done: ' + result.sampleRate + ' Hz, ' + result.channels +\n          ' ch, ' + result.bits + '-bit, ' +\n          (result.dataSize \/ result.channels \/ (result.bits \/ 8) \/ result.sampleRate).toFixed(3) + 's',\n          false\n        );\n      } catch (err) {\n        setStatus('Error: ' + err.message, true);\n      }\n    };\n    reader.onerror = function () {\n      setStatus('Could not read the file.', true);\n    };\n    reader.readAsArrayBuffer(file);\n  });\n})();\n<\/script>\n\n\n\n<p class=\"wp-block-paragraph\">Since everything is happening in your browser locally you can also point to complete folders and have them converted recursively. Tests on my side all went cool &#8211; it just works.<\/p>\n\n\n\n<div id=\"smp-folder-converter\" style=\"max-width:480px;margin:1.5em auto;padding:1.5em;border:1px solid #ddd;border-radius:8px;font-family:sans-serif;\">\n  <h3 style=\"margin-top:0;\">SP-404 mk2 .SMP \u2192 .WAV Folder Converter<\/h3>\n  <p style=\"font-size:0.9em;color:#555;\">Select a folder. All .SMP files inside it (including subfolders) will be converted and bundled into a downloadable .zip. Everything happens in your browser \u2014 nothing is uploaded anywhere.<\/p>\n\n  <input type=\"file\" id=\"smp-folder-input\" webkitdirectory directory multiple style=\"display:block;margin-bottom:1em;\">\n\n  <div id=\"smp-folder-status\" style=\"font-size:0.9em;min-height:1.4em;white-space:pre-line;\"><\/div>\n\n  <a id=\"smp-folder-download-link\" style=\"display:none;padding:0.6em 1.2em;background:#2271b1;color:#fff;text-decoration:none;border-radius:4px;font-weight:bold;\">\n    Download converted-samples.zip\n  <\/a>\n<\/div>\n\n<script src=\"https:\/\/cdnjs.cloudflare.com\/ajax\/libs\/jszip\/3.10.1\/jszip.min.js\"><\/script>\n<script>\n(function () {\n  const HEADER_SIZE = 32;\n  const LEADER_SIZE = 481;     \/\/ empirically-determined SP-404 buffer remnant\n  const DATA_START = HEADER_SIZE + LEADER_SIZE; \/\/ 513\n  const MAX_TOTAL_SIZE = 50 * 1024 * 1024; \/\/ 50 MB safety cap for the whole folder\n\n  const input = document.getElementById('smp-folder-input');\n  const status = document.getElementById('smp-folder-status');\n  const downloadLink = document.getElementById('smp-folder-download-link');\n\n  function setStatus(msg, isError) {\n    status.textContent = msg;\n    status.style.color = isError ? '#c00' : '#555';\n  }\n\n  function readFileAsArrayBuffer(file) {\n    return new Promise((resolve, reject) => {\n      const reader = new FileReader();\n      reader.onload = e => resolve(e.target.result);\n      reader.onerror = () => reject(new Error('could not read file'));\n      reader.readAsArrayBuffer(file);\n    });\n  }\n\n  function convertSmpToWav(buffer) {\n    const view = new DataView(buffer);\n\n    const magic = String.fromCharCode(\n","protected":false},"excerpt":{"rendered":"<p>Over the last couple of years I owned 2 Roland SP404 MK2. Bought the first one, hated it, sold it. Found new interest, bought another one, sold it again. I, of course, saved all my projects &#8216;for later&#8217; but did not export the samples and got stuck with a huge \u2026 <a class=\"continue-reading-link\" href=\"https:\/\/andyland.info\/wordpress\/roland-smp-to-wav-converter\/\"> Continue reading <span class=\"meta-nav\">&rarr; <\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","_links_to":"","_links_to_target":""},"categories":[19],"tags":[462,522,460,523],"class_list":["post-9849","post","type-post","status-publish","format-standard","hentry","category-musik","tag-roland","tag-smp","tag-sp404","tag-wav","odd"],"_links":{"self":[{"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/posts\/9849","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/comments?post=9849"}],"version-history":[{"count":26,"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/posts\/9849\/revisions"}],"predecessor-version":[{"id":9877,"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/posts\/9849\/revisions\/9877"}],"wp:attachment":[{"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/media?parent=9849"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/categories?post=9849"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/andyland.info\/wordpress\/wp-json\/wp\/v2\/tags?post=9849"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}