Automate plugin generation using a bash script

Hello everyone. In my quest to develop a nice little suite of UGens, I wrote this little bash script and thought I might share it here in case anyone else finds it useful.

I found that I really wanted a simple script that would automate adding a script to my repo, create the necessary structure and all cpp and sc-files and then in the end update CMakeLists.txt with the new files / plugins at the end and so I wrote this add_plugin script.

This script expects that you are running it from the root of the repo and takes one argument which is the name of the plugin.

Example:

./add_plugin FunkyWahWah

This will create the directory FunkWahWah in plugins containing all the necessary files for a plugin (FunkyWahWah.cpp, FunkyWahWah.hpp, FunkyWahWah.schelp, FunkyWahWah.sc). After generating the files, it adds them to the CMakeLists.txt file so that they are correctly compiled by CMake.

The script

#!/bin/bash 
#########################
# add_plugin
# Generate plugin template including help file, hpp/cpp pair and the necessary supercollider class
#########################
PLUGIN_AUTHOR="Mads Kjeldgaard"
AUTHOR_EMAIL="mads@notam.no"

PLUGIN_NAME=$1
TARGET_FOLDER=plugins/$PLUGIN_NAME
if [[ -z $PLUGIN_NAME ]]; then
	echo "You need to specify Plugin name as first argument"
	exit 1
fi

function init(){
	if [[ -d $TARGET_FOLDER ]]; then
		echo "$TARGET_FOLDER already exists..." && \
			exit 1
	else
		echo "Creating $TARGET_FOLDER..."

		mkdir "$TARGET_FOLDER" && \
			welcome && \
			echo "--------------------" && \
			generate_files && \
			echo "--------------------" && \
			exit 0
	fi
}

function generate_files(){
	generate_sc_class && \
		generate_help && \
		generate_hpp && \
		generate_cpp && \
		add_to_cmakelists && \
		echo "Done generating files..." && \
		exit 0
}

function generate_help(){

# Help file
echo "Gerating help file for $PLUGIN_NAME ..."
echo "class:: $PLUGIN_NAME
summary:: A plugin developed by Notam
related:: TODO
categories:: UGens>TODO

description::

This plugin is a part of notamplugins, a collection of SuperCollider plugins developed by Notam, the Norwegian center for technology and art.

classmethods::

method::ar, kr

argument::TODO

argument::TODO


examples::

code::

{ $PLUGIN_NAME.ar(/* TODO */) }.play

::
" >> $TARGET_FOLDER/$PLUGIN_NAME.schelp
}

# SuperCollider class file
function generate_sc_class(){

echo "Generating SuperCollider class file"
echo "$PLUGIN_NAME : UGen {
	*ar { |input, gain|
		/* TODO */
		^this.multiNew('audio', input, gain);
	}
	checkInputs {
		/* TODO */
		^this.checkValidInputs;
	}
}
" >> $TARGET_FOLDER/$PLUGIN_NAME.sc
}

function generate_hpp(){
echo "Generating hpp file"
echo "// $PLUGIN_NAME.hpp
// $PLUGIN_AUTHOR ($AUTHOR_EMAIL)

#pragma once

#include \"SC_PlugIn.hpp\"
#include \"../Common/modulators.hpp\"
#include \"../Common/filters.hpp\"
#include \"../Common/allpass.hpp\"


namespace $PLUGIN_NAME {

class $PLUGIN_NAME : public SCUnit {
public:
    $PLUGIN_NAME();

    // Destructor
    ~$PLUGIN_NAME();

private:
    // Calc function
    void next(int nSamples);
};

} // namespace $PLUGIN_NAME
">> $TARGET_FOLDER/$PLUGIN_NAME.hpp

}

function generate_cpp(){
echo "Generating cpp file"

echo "// $PLUGIN_NAME.cpp
// $PLUGIN_AUTHOR ($AUTHOR_EMAIL)

#include \"SC_PlugIn.hpp\"
#include \"${PLUGIN_NAME}.hpp\"

InterfaceTable* ft;

namespace $PLUGIN_NAME {

$PLUGIN_NAME::$PLUGIN_NAME() {
    mCalcFunc = make_calc_function<$PLUGIN_NAME, &$PLUGIN_NAME::next>();
    next(1);
}

void $PLUGIN_NAME::next(int nSamples) {
    const float* input = in(0);
    const float* gain = in(1);
    float* outbuf = out(0);

    // simple gain function
    for (int i = 0; i < nSamples; ++i) {
        outbuf[i] = input[i] * gain[i];
    }
}

} // namespace $PLUGIN_NAME

PluginLoad(${PLUGIN_NAME}UGens) {
    // Plugin magic
    ft = inTable;
    registerUnit<$PLUGIN_NAME::$PLUGIN_NAME>(ft, \"$PLUGIN_NAME\", false);
}
" >> $TARGET_FOLDER/$PLUGIN_NAME.cpp

}

function add_to_cmakelists(){

if [[ -f "CMakeLists.txt" ]]; then
echo "Modifying CMakeLists.txt to add $PLUGIN_NAME as a target"
	
echo "# $PLUGIN_NAME
set(${PLUGIN_NAME}_cpp_files
    $TARGET_FOLDER/$PLUGIN_NAME.hpp
    $TARGET_FOLDER/$PLUGIN_NAME.cpp
)
set(${PLUGIN_NAME}_sc_files
    $TARGET_FOLDER/$PLUGIN_NAME.sc
)
set(${PLUGIN_NAME}_schelp_files
    $TARGET_FOLDER/$PLUGIN_NAME.schelp
)

sc_add_server_plugin(
	\"Notam Plugins/$PLUGIN_NAME\" # desination directory
	\"$PLUGIN_NAME\" # target name
	\"\${${PLUGIN_NAME}_cpp_files}\"
	\"\${${PLUGIN_NAME}_sc_files}\"
	\"\${${PLUGIN_NAME}_schelp_files}\"
)
" >> CMakeLists.txt
else
	echo "Could not find CMakeLists.txt"
fi
}

function welcome(){
echo "
add_plugin:
Generate plugin files
"
}

init
3 Likes

I should say that this of course works well in conjunction with the wonderful cookiecutter recipe for generating a plugin repo. After having generated your repo using the cookiecutter recipe you can use my script above from the repo’s root.