You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
251 lines
6.2 KiB
251 lines
6.2 KiB
#!/bin/bash
|
|
#
|
|
# Converter for WAV to C Header
|
|
# Used for MicroDexed sampler
|
|
#
|
|
# (c) 2021 Holger Wirtz
|
|
#
|
|
|
|
SOX=`which sox`
|
|
XXD=`which xxd`
|
|
TMP="/tmp/wav2c"
|
|
AUDIO_BLOCK_SIZE=128
|
|
DRUMSET_H="drumset.h"
|
|
DRUMS_H="drums.h"
|
|
|
|
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
|
|
;;
|
|
# -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}"
|
|
rm -f "${DRUMSET_H}"
|
|
touch drumset.h
|
|
rm -f "${DRUMS_H}"
|
|
cat >> "${DRUMS_H}" << EOF
|
|
/*
|
|
MicroDexed
|
|
|
|
MicroDexed is a port of the Dexed sound engine
|
|
Dexed ist heavily based on https://github.com/google/music-synthesizer-for-an
|
|
droid
|
|
|
|
(c)2018-2021 H. Wirtz <wirtz@parasitstudio.de>
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
THE SOFTWARE.
|
|
*/
|
|
|
|
#include <Arduino.h>
|
|
#include "config.h"
|
|
#include "drumset.h"
|
|
|
|
#ifndef _DRUMS_H
|
|
#define _DRUMS_H
|
|
|
|
typedef struct drum_config_s {
|
|
uint8_t drum_class; // Type of drum
|
|
uint8_t midinote; // Triggered by note
|
|
char name[DRUM_NAME_LEN];
|
|
const unsigned int* drum_data;
|
|
char shortname[2]; // 1 char name for sequencer
|
|
uint32_t len; // number of elements in drum_data
|
|
float32_t pitch; //
|
|
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_CHRASH, DRUM_LOWTOM, DRUM_MIDTOM, DRUM_HIGHTOM, DRUM_PERCUSSION};
|
|
|
|
// DEFAULT MIDI CHANNEL FOR SAMPLEDRUMS
|
|
uint8_t drum_midi_channel = 10;
|
|
|
|
drum_config_t drum_config[NUM_DRUMSET_CONFIG] =
|
|
{
|
|
EOF
|
|
|
|
declare -A converted_files
|
|
|
|
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['data_name']="${sample['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
|
|
file "${WAV_DIR}/${sample['filename']}" | grep -i -q "WAVE audio"
|
|
if [ "${?}" == 0 ]
|
|
then
|
|
# Generate drumset.h
|
|
|
|
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 int8_t ${sample['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['name']},${sample['len']}"
|
|
else
|
|
sample['data_name']=`echo ${converted_files[${sample['filename']}]} | cut -d"," -f1`
|
|
sample['len']=`echo ${converted_files[${sample['filename']}]} | cut -d"," -f2`
|
|
fi
|
|
|
|
# Generate drums.h
|
|
cat >> "${DRUMS_H}" << EOF
|
|
{
|
|
${sample[class]},
|
|
${sample[midinote]},
|
|
"${sample[name]}",
|
|
${sample[data_name]},
|
|
"${sample[shortname]}",
|
|
${sample[len]},
|
|
${sample[pitch]},
|
|
${sample[pan]},
|
|
${sample[vol_max]},
|
|
${sample[vol_min]},
|
|
${sample[reverb_send]}
|
|
},
|
|
EOF
|
|
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
|
|
}
|
|
};
|
|
|
|
#endif
|
|
EOF
|
|
|