|
resources
|
Getting Starting with SuperCollider3 Source Code, Plugins & DebuggingLast Updated 16-Dec 2004
.: Notes, Warnings, etc :.
Someday I'll php-ify this page so that folks can add comments to the actual site, but until then please do send any commments or corrections to mailto:a[at]plus1plus1plus[dot]org|a[at]plus1plus1plus[dot]org
Special thanks to Aaron Spafford for additional suggestions and contributions, and of course to anyone who has contributed to the SuperCollider Swiki
My original "Program Notes":
Warning: Please note that I use OSX, so some of this info may be different, unusable, or confusing to Linux or Windows users. Or not - I think most of it generally the same... Just be forewarned...
Getting Started: Downloading and Compiling Other Required Software
Before you get started with building SC3 plugins, you'll need to get the SC3 source code PLUS a couple other programs and libraries, some of which also have to be compiled. You will need: Apple's Developer Tools which will provide you with various Unix and compilation programs like CVS and Xcode, and libsndfile.
much of the following info was gathered from the SuperCollider Swiki website which has a good deal of information related to SC3 stuff...
.................................
make sure you have Developer Tools installed on your computer, specifically Xcode if you're running OS 10.3 or higher, or Project Builder if you're running OS 10.2. if you don't have either of these, you can get the one you need for FREE from Apple's website after filling out a few forms and dodging their requests for money: http://developer.apple.com/tools/download/
...................................
make sure you have libsndfile downloaded and installed. you can download it here: http://www.mega-nerd.com/libsndfile/
as of March 6, 2004, the latest version is 1.0.7. beware that v.1.0.6 has major bugs that will prevent SC3 from compiling, so make sure you get the right, most up-to-date version, or else you'll spend a couple sleepless nights trying to figure out what you're doing wrong, like i did last week...
..................................
3rd:
install libsndfile using Terminal (it's typically located on your mac in the Utilities folder)
you may want to save your libsndfile folder that you just downloaded in your Developer Tools folder so that you keep everything nice and organized. you're going to need to know where to find this file in just a second.
For your reference, the instructions for installing libsndfile can be found in the INSTALL file in the folder, but i will guide you through the process here:
1) Open Terminal and type the following:
2) drag-and-drop the actual libsndfile folder to the Terminal window - the pathname will magically appear and should look something like this, although it may vary depending on where your file is located:
3) type in the following commands in order, making sure to wait until each one is done executing; they all take awhile...
then you'll need to log in as the 'root user' by typing
type in your 'root user' password where it tells you to. note that you you won't be able to see your password as you type it, in fact the cursor won't even move forward. just hit enter once you're done typing. you may have set this up when you first got your computer. if not, you might be screwed for the moment. go here and see if this works:
aaron spafford has recommended the following for procedure for setting up your root password if you haven't done it already:
If you know your admin (login) password, but havn't yet set up a root password,
at prompt enter your admin password
Now, at the password prompt, type in your desired root password, hit enter and type
Now you're all set!
after you're logged in, your user name should be the same, except now it will have a # sign after it instead of a $ sign, for instance mine is
now type in the following:
if everything goes alright and finishes correctly, type the following to log out of the root user mode. (it is dangerous to stay logged into root user mode.)
great - libsndfile should now be installed on your machine and you are ready to proceed...
Downloading the SC3 source code with CVSDownload the SuperCollider3 source code using CVS, which is accessed by once again by using the Terminal app. CVS should already installed on your mac if you have Developer Tools installed.
figure out which folder on your computer you want to put the SC source code folder in, and then go there in terminal, for instance:
[the following are instructions from the swiki site]:
Then type the following command:
When it asks for the password, just press enter and wait for the prompt to return.
You should see lines like the following:
If you get "
to update, from the same location, do
Compiling the SC3 Source Code
there are a handful of ways you can do this, but it's probably easiest to do it from the Terminal. if you want to know the other ways, go to the web for instructions (http://swiki.hfbk-hamburg.de:8888/MusicTechnology/554) and scroll down.
the following instructions can be found listed in the file 'compile-xcode.sh' in the SuperCollider3 folder you just downloaded, and will compile the source code into the actual SC3 app you've come know and love:
copy and paste the following text all at once into Terminal; this might take a while to finish executing. go grab a glass of wine or juice:
echo "building scsynth"; xcodebuild -project xSC3synth.pbproj -target "All" -buildstyle "Deployment" build; echo "building plugins"; xcodebuild -project xSC3plugins.pbproj -target "All" -buildstyle "Deployment" build; echo "building sclang"; xcodebuild -project xSC3lang.pbproj -target "All" -buildstyle "Deployment" build;
How To Compile A Test Plugin in SC3
guess what? every single unit generator in SuperCollider3 is a plugin. what does that mean? well, it means that in order to learn how to make your own, you can use the preexisting source code of your favorite Ugen as a starting point by simply renaming it and then modifying it. below are instructions on how to get started and by compiling your first example plugin. before you do this, though, you must download the SuperCollider source code.
NOTE: These instructions might be outdated now. James McCartney has since placed a plugin-writing help-file in the SC3 distribution - you will want to look at that first before going on
here are some good links:
Part I -- Hacking the Source Code
let's make a test-run plugin by grabbing the source code of Osc (a table lookup oscillator), and turning it into TestOsc - note that this is only a test to make sure that we know the procedure for quickly getting started on a plugin. in the end, this example will just produce an Osc.ar when you type TestOsc.ar in SC. the point, though, is to demonstrate how easy it might be to get started on a plugin.
alrighty. here's how:
go here: SuperCollider3/source/plugins/ and get the OscUGens.cpp file. duplicate it (command-D) and rename it TestOsc.cpp, and then open it with a good text editor like BBEdit (you won't want to use TextEdit or anything that will save it as an rtf)...
find the code that you will need to compile in order to make an Osc only and delete all the rest. Notice that alllllll of the Oscillator ugens can be found here snuggled together. be careful in your editing - you'll need a handful of stuff. after the code is extracted, change every name with 'Osc' in it to 'TestOsc'. save your changes. here's what i came up with:
/////////////// C++ code in a file named TestOsc.cpp ///////////////////
#include "SC_PlugIn.h"
#include <limits.h>
static InterfaceTable *ft;
struct BufUnit : public Unit
{
SndBuf *m_buf;
float m_fbufnum;
};
struct TableLookup : public BufUnit
{
double m_cpstoinc, m_radtoinc;
int32 mTableSize;
int32 m_lomask;
};
struct TestOsc : public TableLookup
{
int32 m_phase, m_phaseoffset;
float m_phasein;
};
////////////////////////////////////////////////////////////////
extern "C"
{
void load(InterfaceTable *inTable);
void TestOsc_Ctor(TestOsc *unit);
void TestOsc_next_ikk(TestOsc *unit, int inNumSamples);
void TestOsc_next_ika(TestOsc *unit, int inNumSamples);
void TestOsc_next_iak(TestOsc *unit, int inNumSamples);
void TestOsc_next_iaa(TestOsc *unit, int inNumSamples);
}
////////////////////////////////////////////////////////////////
#define GET_TABLE \
float fbufnum = ZIN0(0); \
if (fbufnum != unit-->m_fbufnum) { \
uint32 bufnum = (uint32)fbufnum; \
World *world = unit-->mWorld; \
if (bufnum >= world-->mNumSndBufs) bufnum = 0; \
unit-->m_buf = world-->mSndBufs + bufnum; \
} \
SndBuf *buf = unit-->m_buf; \
if(!buf) { \
ClearUnitOutputs(unit, inNumSamples); \
return; \
} \
float *bufData __attribute__((__unused__)) = buf-->data; \
if (!bufData) { \
ClearUnitOutputs(unit, inNumSamples); \
return; \
} \
int tableSize = buf-->samples;
////////////////////////////////////////////////////////////////
void TestOsc_Ctor(TestOsc *unit)
{
unit-->m_fbufnum = -1e9f;
if (INRATE(1) == calc_FullRate) {
if (INRATE(2) == calc_FullRate) {
//Print("next_iaa\n");
SETCALC(TestOsc_next_iaa);
} else {
//Print("next_iak\n");
SETCALC(TestOsc_next_iak);
}
} else {
if (INRATE(2) == calc_FullRate) {
//Print("next_ika\n");
SETCALC(TestOsc_next_ika);
} else {
//Print("next_ikk\n");
SETCALC(TestOsc_next_ikk);
}
}
unit-->m_buf = unit-->mWorld-->mSndBufs;
unit-->mTableSize = -1;
unit-->m_phasein = ZIN0(2);
unit-->m_phaseoffset = (int32)(unit-->m_phasein * unit-->m_radtoinc);
if (INRATE(2) == calc_FullRate) {
unit-->m_phase = 0;
} else {
unit-->m_phase = unit-->m_phaseoffset;
}
TestOsc_next_ikk(unit, 1);
}
////////////////////////////////////////////////////////////////
void TestOsc_next_ikk(TestOsc *unit, int inNumSamples)
{
// get table
GET_TABLE
float *table0 = bufData;
float *table1 = table0 + 1;
if (tableSize != unit-->mTableSize) {
unit-->mTableSize = tableSize;
int tableSize2 = tableSize >> 1;
unit-->m_lomask = (tableSize2 - 1) << 3; // Osc, OscN, COsc, COsc, COsc2, OscX4, OscX2
unit-->m_radtoinc = tableSize2 * (rtwopi * 65536.); // Osc, OscN, PMOsc
// SigOsc, Osc, OscN, PMOsc, COsc, COsc2, OscX4, OscX2
unit-->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.;
}
float *out = ZOUT(0);
float freqin = ZIN0(1);
float phasein = ZIN0(2);
int32 phase = unit-->m_phase;
int32 lomask = unit-->m_lomask;
int32 freq = (int32)(unit-->m_cpstoinc * freqin);
int32 phaseinc = freq + (int32)(CALCSLOPE(phasein, unit-->m_phasein) * unit-->m_radtoinc);
unit-->m_phasein = phasein;
LOOP(inNumSamples,
ZXP(out) = lookupi1(table0, table1, phase, lomask);
phase += phaseinc;
);
unit-->m_phase = phase;
}
void TestOsc_next_ika(TestOsc *unit, int inNumSamples)
{
// get table
GET_TABLE
float *table0 = bufData;
float *table1 = table0 + 1;
if (tableSize != unit-->mTableSize) {
unit-->mTableSize = tableSize;
int tableSize2 = tableSize >> 1;
unit-->m_lomask = (tableSize2 - 1) << 3; // Osc, OscN, COsc, COsc, COsc2, OscX4, OscX2
unit-->m_radtoinc = tableSize2 * (rtwopi * 65536.); // Osc, OscN, PMOsc
// SigOsc, Osc, OscN, PMOsc, COsc, COsc2, OscX4, OscX2
unit-->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.;
}
float *out = ZOUT(0);
float freqin = ZIN0(1);
float *phasein = ZIN(2);
int32 phase = unit-->m_phase;
int32 lomask = unit-->m_lomask;
int32 freq = (int32)(unit-->m_cpstoinc * freqin);
float radtoinc = unit-->m_radtoinc;
//Print("Osc_next_ika %d %g %d\n", inNumSamples, radtoinc, phase);
LOOP(inNumSamples,
int32 phaseoffset = phase + (int32)(radtoinc * ZXP(phasein));
ZXP(out) = lookupi1(table0, table1, phaseoffset, lomask);
phase += freq;
);
unit-->m_phase = phase;
//unit-->m_phasein = phasein;
}
void TestOsc_next_iaa(TestOsc *unit, int inNumSamples)
{
// get table
GET_TABLE
float *table0 = bufData;
float *table1 = table0 + 1;
if (tableSize != unit-->mTableSize) {
unit-->mTableSize = tableSize;
int tableSize2 = tableSize >> 1;
unit-->m_lomask = (tableSize2 - 1) << 3; // Osc, OscN, COsc, COsc, COsc2, OscX4, OscX2
unit-->m_radtoinc = tableSize2 * (rtwopi * 65536.); // Osc, OscN, PMOsc
// SigOsc, Osc, OscN, PMOsc, COsc, COsc2, OscX4, OscX2
unit-->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.;
}
float *out = ZOUT(0);
float *freqin = ZIN(1);
float *phasein = ZIN(2);
int32 phase = unit-->m_phase;
int32 lomask = unit-->m_lomask;
float cpstoinc = unit-->m_cpstoinc;
float radtoinc = unit-->m_radtoinc;
//Print("Osc_next_iaa %d %g %g %d\n", inNumSamples, cpstoinc, radtoinc, phase);
LOOP(inNumSamples,
int32 phaseoffset = phase + (int32)(radtoinc * ZXP(phasein));
float z = lookupi1(table0, table1, phaseoffset, lomask);
phase += (int32)(cpstoinc * ZXP(freqin));
ZXP(out) = z;
);
unit-->m_phase = phase;
//unit-->m_phasein = ZX(phasein);
}
void TestOsc_next_iak(TestOsc *unit, int inNumSamples)
{
// get table
GET_TABLE
float *table0 = bufData;
float *table1 = table0 + 1;
if (tableSize != unit-->mTableSize) {
unit-->mTableSize = tableSize;
int tableSize2 = tableSize >> 1;
unit-->m_lomask = (tableSize2 - 1) << 3; // Osc, OscN, COsc, COsc, COsc2, OscX4, OscX2
unit-->m_radtoinc = tableSize2 * (rtwopi * 65536.); // Osc, OscN, PMOsc
// SigOsc, Osc, OscN, PMOsc, COsc, COsc2, OscX4, OscX2
unit-->m_cpstoinc = tableSize2 * SAMPLEDUR * 65536.;
}
float *out = ZOUT(0);
float *freqin = ZIN(1);
float phasein = ZIN0(2);
int32 phase = unit-->m_phase;
int32 lomask = unit-->m_lomask;
float cpstoinc = unit-->m_cpstoinc;
int32 phaseinc = (int32)(CALCSLOPE(phasein, unit-->m_phasein) * unit-->m_radtoinc);
int32 phaseoffset = unit-->m_phaseoffset;
LOOP(inNumSamples,
float z = lookupi1(table0, table1, phase + phaseoffset, lomask);
phaseoffset += phaseinc;
phase += (int32)(cpstoinc * ZXP(freqin));
ZXP(out) = z;
);
unit-->m_phase = phase;
unit-->m_phasein = phasein;
unit-->m_phaseoffset = phaseoffset;
}
////////////////////////////////////////////////////////////////
void load(InterfaceTable *inTable)
{
ft = inTable;
DefineSimpleUnit(TestOsc);
}
////////////////////////////////////////////////////////////////
.............................................
Part II -- Compiling Your SC3 Plugin...
1) you won't be needing Terminal anymore at this point, so quit it...
2) go to the folder SuperCollider3 and duplicate (command-D) the file 'xSC3plugins.pbproj'
rename the new file something like 'xSC3pluginsTEST.pbproj'
3) now open that file in Xcode. go to 'Project' on the menu bar, select 'Add Files...', and select the 'TestOsc.cpp' file you just created. hit OK. 'TestOsc.cpp' will appear up at the top of the 'Groups & Files' column. we will come back to this file in a moment...
4) toggle the 'Targets' arrow so that you can see all of the targets. option-click on the Target called 'OscUGens' and select 'duplicate'. down at the bottom of the target list a duplicate file with the same name will appear. option-click the duplicate and select 'rename'. rename it 'TestOsc'.
5) drag the the 'TestOsc.cpp' file to the 'Sources' icon under the Target 'TestOsc'.
6) now we have to do some searching to modify a handful of things. first make sure that the editor frame is open by clicking the editor window button in the toolbar. then click on the new Target, 'TestOsc' - information should appear in the editor. do the following:
7) go back up and double-click the Target 'All Plugins' so that it's info panel pops up. click the + button at the bottom and add the 'TestOsc' Target to the list.
8) close the window and hit the Build icon. if you've done everything correctly, you should in a few minutes have a nice TestOsc.scx plugin sitting in the 'SuperCollider3/build/plugins' folder.
9) now open SuperCollider but don't boot it up yet. find the Osc.sc file by 1) typing 'Osc', 2) highlighting it, and 3) then hitting command-J. find the class definition for Osc and copy it into another file - name that file TestOsc.sc and change the mention of Osc in it to 'TestOsc'. your file should end up looking like this:
TestOsc : UGen {
*ar {
arg bufnum, freq=440.0, phase=0.0, mul=1.0, add=0.0;
^this.multiNew('audio', bufnum, freq, phase).madd(mul, add)
}
*kr {
arg bufnum, freq=440.0, phase=0.0, mul=1.0, add=0.0;
^this.multiNew('control', bufnum, freq, phase).madd(mul, add)
}
}
save that file somewhere into your SCClassLibrary folder.
10) now boot up your SC Server. if you get any error messages, retrace your steps...
11) open the Osc helpfile and change the SynthDef contents so that it says TestOsc.ar instead of Osc.ar.
12) compile the code and listen to your new plugin that you just created by modifying some pre-existing SC3 code. if you're getting an error message, retrace your steps...
congrats. that's all there is to getting started with Plugins in SC3. after a few times through the process, you'll find it to be a pretty simple procedure. the hardest parts really have less to do with SuperCollider and more to do with the clunkiness of the Xcode interface.
as for dsp code, all of SuperCollider is laying there before you. chop away. i've also heard that http://www.musicdsp.org has a good deal of code online in its archive...
good luck. contact me if i've missed something and i'll update this...
Debugging your SC3 Plugin
I can't believe it took me sooooo long (almost a year) to figure out that I could use the Xcode debugger in SuperCollider. Part of the reason it took so long for me to figure this out is that a teacher of mine was of the belief that it wasn't possible because of such and such. I sadly took his advice... But recently I went online and did a search and found the information that I was looking for right here: Nick Collin's Plugin Tutorial. The only reason I will reproduce the steps down here is because I found his description a little vague and confusing at first, AND he failed to mention one very important thing: YOU CAN ONLY DEBUG WHILE USING THE INTERNAL SERVER!! This took me quite awhile to figure out. Anyways, here are the steps that need to be taken:
1. Make Sure You're in Development Mode. In your Xcode project, either double-click on the plugin project icon or highlight it and Get Info (Cmd-I) - this will bring up the Project Info Pane. Click over to the 'Styles' menu and make sure the 'Active Build Style' is set to "Development". Also make sure in the scroll-down list that 'Generate Debug Symbols' is enabled.
2. Create a Custom Executable. Now ctrl-click your plugins project icon to bring up a pop-up menu. Go to the 'Add' sub-menu and select 'New Custom Executable'. Name this whatever you want, choose the path to the SuperCollider3 application as your executable path, and add this to your existing project by clicking 'Finish'.
3. Add Some Stuff to the Custom Executable. Highlight the new custom executable that you have created and either double-click or Get Info. Go to the 'Arguments' menu. Add the following Argument:
Leave the variables area alone and close the window.
4. Add Some Debugging Breakpoints. Click around in the grey left-hand column of your code document in Xcode - you'll notice little pointers will appear and disappear - they are your break-points. When debugging, the compiler will freeze the action of the program wherever you place these breakpoints so that you can then jump around and look at what values your variables are holding, and also to see if your algorithms are executing correctly.
5. Attempt to Debug. Make sure your SuperCollider app is not already open - if it is open I've found that Xcode will open multiple copies of it which can become confusing. Click either 'Compile and Debug' (or just 'Debug' if you haven't made any changes to your code). It may take a few seconds, but after awhile SC3 will automatically open. You should boot the INTERNAL SERVER (THIS WILL NOT WORK WITH THE LOCAL SERVER!!!), open the SuperCollider code that uses your new plugin, and execute it as you normally would. If SC ends up cycling past one of your breakpoints then it will freeze and the Debugger window in Xcode will appear, showing you the current position in the plugin code and all the various values being stored in memory. Explore by clicking all of the various navigation buttons. The 'continue' button takes you from breakpoint to breakpoint; the 'step into' button advances forward line-by-line -- if you reach a function, however, it will jump to the location in your document where the function's innards exist before proceeding; the 'step over' button does basically the same line-by-line action except it jumps over functions and only shows their results. Explore explore explore.
It's it important to remember two things regarding debugging with the Internal or Local Servers: as I said earlier, the debugger only works (at least with the debug argument that we're using) with the Internal Server. On the other hand, another way to debug is to add printf() statements - however, these seem to only print out when you're using the Localhost Server(!?). So just remain aware, or else you risk wasting a lot of time trying to figure out why your code isn't working/debugging properly.
PLEASE NOTE: For a number of personal reasons I am currently unable to support this page and am unable to respond to any further questions, requests, demands, etc posted here. I sincerely apologize for this. The material above is simply presented as archival material (some of it incomplete) of a project that I am not actively involved with anymore, and it will probably not be updated any further. You are free to use it in whatever non-commercial ways you wish (see the CreativeCommons license below). In addition, feel free to use the comments-section below to post ideas, solutions, or to ask questions, but with the understanding that any queries will have to be answered by the community at large - not by me. Thanks for understanding.
|
http://plus1plus1plus.org/Resources/SC3PluginTutorial
last updated 21 January 2010, at 05:06 PM PST
.