#!/bin/bash # # Converter for WAV to C Header # Used for MicroDexed sampler # # (C)2021-2022 Holger Wirtz # SOX=`which sox` XXD=`which xxd` TMP="/tmp/wav2c" AUDIO_BLOCK_SIZE=128 DRUMSET_H="drumset.h" DRUMS_H="${TMP}/drums.h" MAX_NUM_DRUMSET_CONFIG=71 # ARDUINO_TEENSY41 #MAX_NUM_DRUMSET_CONFIG=40 # ARDUINO_TEENSY40 #MAX_NUM_DRUMSET_CONFIG=19 # ... function cleanexit() { #rm -rf "${TMP}" echo -n "" } trap cleanexit EXIT if [ -z "${SOX}" ] then echo "Cannot find 'sox' in your PATH." >&2 exit 100 fi if [ -z "${XXD}" ] then echo "Cannot find 'xxd' in your PATH." >&2 exit 101 fi POSITIONAL=() while [[ $# -gt 0 ]]; do key="$1" case $key in -c|--config) CONFIG="$2" shift # past argument shift # past value ;; -w|--wavs) WAV_DIR="$2" shift # past argument shift # past value ;; -n|--num) MAX_NUM_DRUMSET_CONFIG="$2" shift # past argument shift # past value ;; # -t|--test) # TEST="true" # shift # past argument # ;; *) # unknown option POSITIONAL+=("$1") # save it in an array for later shift # past argument ;; esac done if [ ! -f "${CONFIG}" ] then echo "Cannot find configuration file." >&2 exit 200 fi if [ ! -d "${WAV_DIR}" ] then echo "Cannot find folder for WAV files." >&2 exit 201 fi if (( `ls "${WAV_DIR}" | wc -l` == 0 )) then echo "Cannot find any file in ${WAV_DIR}." >&2 exit 202 fi mkdir -p "${TMP}" cat >> "${DRUMSET_H}" << EOF #pragma once #include typedef struct drum_config_s { uint8_t drum_class; // Type of drum uint8_t midinote; // Triggered by note char name[DRUM_NAME_LEN]; const uint8_t* drum_data; char shortname[2]; // 1 char name for sequencer uint32_t len; // number of elements in drum_data float32_t pitch; // variable pitch per note for sequencer float32_t pan; // Panorama (-1.0 - +1.0) float32_t vol_max; // max. Volume (0.0 - 1.0) float32_t vol_min; // min. Volume (0.0 - 1.0, should be <= vol_max) float32_t reverb_send; // how much signal to send to the reverb (0.0 - 1.0) } drum_config_t; enum {DRUM_NONE, DRUM_BASS, DRUM_SNARE, DRUM_HIHAT, DRUM_HANDCLAP, DRUM_RIDE, DRUM_CRASH, DRUM_LOWTOM, DRUM_MIDTOM, DRUM_HIGHTOM, DRUM_PERCUSSION, DRUM_POLY}; EOF rm -f "${DRUMS_H}" cat >> "${DRUMS_H}" << EOF PROGMEM const drum_config_t drum_config[NUM_DRUMSET_CONFIG] = { EOF declare -A converted_files NUM_DRUMSET_CONFIG=1 while IFS= read -r l do declare -A sample if [[ "${l:0:1}" == "#" ]] then continue fi IFS=',' read -ra samplecfg <<< "${l}" sample['class']=`echo "${samplecfg[0]}" | xargs` sample['midinote']=`echo "${samplecfg[1]}" | xargs` sample['name']=`echo "${samplecfg[2]}" | xargs` sample['c_name']=`echo "${samplecfg[2]}" | xargs | sed 's/[^a-zA-Z0-9]/_/g'` sample['c_name']=`echo "DRUM_${sample[c_name]}"` sample['shortname']=`echo "${samplecfg[3]}" | xargs` sample['pitch']=`echo "${samplecfg[4]}" | xargs` sample['pan']=`echo "${samplecfg[5]}" | xargs` sample['vol_max']=`echo "${samplecfg[6]}" | xargs` sample['vol_min']=`echo "${samplecfg[7]}" | xargs` sample['reverb_send']=`echo "${samplecfg[8]}" | xargs` sample['filename']=`echo "${samplecfg[9]}" | xargs` if [ -f "${WAV_DIR}/${sample['filename']}" ] then if [ ${NUM_DRUMSET_CONFIG} -gt ${MAX_NUM_DRUMSET_CONFIG} ] then echo "/*" >> "${DRUMSET_H}" fi file "${WAV_DIR}/${sample['filename']}" | grep -i -q "WAVE audio" if [ "${?}" == 0 ] then # Generate drumset.h echo "'${WAV_DIR}/${sample['filename']}' -> '${sample['c_name']}'" if [ -z "${converted_files[${sample['filename']}]}" ] then basename=`echo "${sample['filename']}" | cut -d'.' -f1` sox "${WAV_DIR}/${sample['filename']}" -c 1 -b 16 -L "${TMP}/${basename}.raw" xxd -i "${TMP}/${basename}.raw" > "${TMP}/${basename}.h" sample['len']=`grep "^unsigned int" "${TMP}/${basename}.h" | cut -d"=" -f2 | sed 's/\s*\([0-9]\+\);/\1/'` fill_mod=`expr "${sample['len']}" % "${AUDIO_BLOCK_SIZE}"` fill=`expr "${AUDIO_BLOCK_SIZE}" - "${fill_mod}"` sample['len']=`expr "${sample['len']}" + "${fill}"` sample['len']=`expr "${sample['len']}" / 2` echo "// Converted from ${sample['filename']}, length = ${sample['len']} bytes" >> "${DRUMSET_H}" echo "PROGMEM const uint8_t ${sample['c_name']}[] = {" >> "${DRUMSET_H}" grep "^ " "${TMP}/${basename}.h" >> "${DRUMSET_H}" if (( "${fill}" > 0 )) then echo -n "," >> "${DRUMSET_H}" fill_counter=0 for i in $(seq 1 "${fill}") do echo -n "0x00" >> "${DRUMSET_H}" let fill_counter+=1 if (( "${fill_counter}" >= 8 )) then echo "," >> "${DRUMSET_H}" fill_counter=0 else echo -n ", " >> "${DRUMSET_H}" fi done fi echo "};" >> "${DRUMSET_H}" converted_files["${sample['filename']}"]="${sample['c_name']},${sample['len']}" else sample['c_name']=`echo ${converted_files[${sample['filename']}]} | cut -d"," -f1` sample['len']=`echo ${converted_files[${sample['filename']}]} | cut -d"," -f2` fi # Generate drums.h if [ ${NUM_DRUMSET_CONFIG} -gt ${MAX_NUM_DRUMSET_CONFIG} ] then echo "/*" >> "${DRUMS_H}" fi cat >> "${DRUMS_H}" << EOF { ${sample[class]}, ${sample[midinote]}, "${sample[name]}", ${sample[c_name]}, "${sample[shortname]}", ${sample[len]}, ${sample[pitch]}, ${sample[pan]}, ${sample[vol_max]}, ${sample[vol_min]}, ${sample[reverb_send]} }, EOF if [ ${NUM_DRUMSET_CONFIG} -gt ${MAX_NUM_DRUMSET_CONFIG} ] then echo "*/" >> "${DRUMS_H}" echo "*/" >> "${DRUMSET_H}" fi NUM_DRUMSET_CONFIG=`expr "${NUM_DRUMSET_CONFIG}" + 1` else echo "File ${WAV_DIR}/${sample['filename']} is not a WAV audio file" fi else echo "File \'${WAV_DIR}/${sample['filename']}\' does not exits." >&2 fi done < "${CONFIG}" cat >> "${DRUMS_H}" << EOF { DRUM_NONE, 0, "EMPTY", NULL, "-", 0, 0.0, 0.0, 0.0, 0.0, 0.0 } }; EOF echo "" >> "${DRUMSET_H}" cat "${DRUMS_H}" >> "${DRUMSET_H}" echo "" echo "Created drumset.h. Copy the file to the root dicrectory of MicroDexed and don't" echo "forget to edit config.h and change the following line to the right number:" echo "" echo " #define NUM_DRUMSET_CONFIG ${NUM_DRUMSET_CONFIG}" echo ""