Skip to content

Instantly share code, notes, and snippets.

@dyfer
Last active August 23, 2018 18:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dyfer/36ea2967a5ef59e81575b370f9748a63 to your computer and use it in GitHub Desktop.
Save dyfer/36ea2967a5ef59e81575b370f9748a63 to your computer and use it in GitHub Desktop.
/*
SuperCollider real time audio synthesis system
Copyright (c) 2002 James McCartney. All rights reserved.
http://www.audiosynth.com
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "SC_WorldOptions.h"
#include "SC_Version.hpp"
#include <cstring>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <math.h>
#include "clz.h"
#include <stdexcept>
#ifdef _WIN32
# include <winsock2.h>
#else
# include <sys/wait.h>
#endif
#ifdef _WIN32
// according to this page: http://www.mkssoftware.com/docs/man3/setlinebuf.3.asp
// setlinebuf is equivalent to the setvbuf call below.
inline int setlinebuf(FILE *stream)
{
return setvbuf( stream, (char*)0, _IONBF, 0 );
}
#endif
void Usage();
void Usage()
{
WorldOptions defaultOptions;
scprintf(
"supercollider_synth options:\n"
" -v print the supercollider version and exit\n"
" -u <udp-port-number> a port number 0-65535\n"
" -t <tcp-port-number> a port number 0-65535\n"
" -B <bind-to-address> an IP address\n"
" -c <number-of-control-bus-channels> (default %d)\n"
" -a <number-of-audio-bus-channels> (default %d)\n"
" -i <number-of-input-bus-channels> (default %d)\n"
" -o <number-of-output-bus-channels> (default %d)\n"
" -z <block-size> (default %d)\n"
" -Z <hardware-buffer-size> (default %d)\n"
" -S <hardware-sample-rate> (default %d)\n"
" -b <number-of-sample-buffers> (default %d)\n"
" -n <max-number-of-nodes> (default %d)\n"
" -d <max-number-of-synth-defs> (default %d)\n"
" -m <real-time-memory-size> (default %d)\n"
" -w <number-of-wire-buffers> (default %d)\n"
" -r <number-of-random-seeds> (default %d)\n"
" -D <load synthdefs? 1 or 0> (default %d)\n"
" -R <publish to Rendezvous? 1 or 0> (default %d)\n"
" -l <max-logins> (default %d)\n"
" maximum number of named return addresses stored\n"
" also maximum number of tcp connections accepted\n"
" -p <session-password>\n"
" When using TCP, the session password must be the first command sent.\n"
" The default is no password.\n"
" UDP ports never require passwords, so for security use TCP.\n"
" -N <cmd-filename> <input-filename> <output-filename> <sample-rate> <header-format> <sample-format>\n"
#ifdef __APPLE__
" -I <input-streams-enabled>\n"
" -O <output-streams-enabled>\n"
#endif
#if (_POSIX_MEMLOCK - 0) >= 200112L
" -L enable memory locking\n"
#endif
" -H <hardware-device-name>\n"
" -V <verbosity>\n"
" 0 is normal behaviour.\n"
" -1 suppresses informational messages.\n"
" -2 suppresses informational and many error messages, as well as\n"
" messages from Poll.\n"
" The default is 0.\n"
#ifdef _WIN32
" -U <ugen-plugins-path>\n"
" A list of paths seperated by `;`.\n"
#else
" -U <ugen-plugins-path>\n"
" A list of paths seperated by `:`.\n"
#endif
" If specified, standard paths are NOT searched for plugins.\n"
" -P <restricted-path> \n"
" if specified, prevents file-accessing OSC commands from\n"
" accessing files outside <restricted-path>.\n"
"\nTo quit, send a 'quit' command via UDP or TCP, or press ctrl-C.\n\n",
defaultOptions.mNumControlBusChannels,
defaultOptions.mNumAudioBusChannels,
defaultOptions.mNumInputBusChannels,
defaultOptions.mNumOutputBusChannels,
defaultOptions.mBufLength,
defaultOptions.mPreferredHardwareBufferFrameSize,
defaultOptions.mPreferredSampleRate,
defaultOptions.mNumBuffers,
defaultOptions.mMaxNodes,
defaultOptions.mMaxGraphDefs,
defaultOptions.mRealTimeMemorySize,
defaultOptions.mMaxWireBufs,
defaultOptions.mNumRGens,
defaultOptions.mRendezvous,
defaultOptions.mLoadGraphDefs,
defaultOptions.mMaxLogins
);
exit(1);
}
#define checkNumArgs(n) \
if (i+n > argc) { \
if (n == 2) scprintf("ERROR: Argument expected after option %s\n", argv[j]); \
else scprintf("ERROR: More arguments expected after option %s\n", argv[j]); \
Usage(); \
} \
i += n;
int main(int argc, char* argv[]);
int main(int argc, char* argv[])
{
setlinebuf(stdout);
#ifdef _WIN32
// initialize winsock
WSAData wsaData;
int nCode;
if ((nCode = WSAStartup(MAKEWORD(1, 1), &wsaData)) != 0) {
scprintf( "WSAStartup() failed with error code %d.\n", nCode );
return 1;
}
#endif
int udpPortNum = -1;
int tcpPortNum = -1;
std::string bindTo("0.0.0.0");
WorldOptions options;
for (int i=1; i<argc;) {
if (argv[i][0] != '-' || argv[i][1] == 0 || strchr("utBaioczblndpmwZrCNSDIOMHvVRUhPL", argv[i][1]) == 0) {
scprintf("ERROR: Invalid option %s\n", argv[i]);
Usage();
}
int j = i;
switch (argv[j][1]) {
case 'u' :
checkNumArgs(2);
udpPortNum = atoi(argv[j+1]);
break;
case 't' :
checkNumArgs(2);
tcpPortNum = atoi(argv[j+1]);
break;
case 'B':
checkNumArgs(2);
bindTo = argv[j+1];
break;
case 'a' :
checkNumArgs(2);
options.mNumAudioBusChannels = atoi(argv[j+1]);
break;
case 'i' :
checkNumArgs(2);
options.mNumInputBusChannels = atoi(argv[j+1]);
break;
case 'o' :
checkNumArgs(2);
options.mNumOutputBusChannels = atoi(argv[j+1]);
break;
case 'c' :
checkNumArgs(2);
options.mNumControlBusChannels = atoi(argv[j+1]);
break;
case 'z' :
checkNumArgs(2);
options.mBufLength = NEXTPOWEROFTWO(atoi(argv[j+1]));
break;
case 'Z' :
checkNumArgs(2);
options.mPreferredHardwareBufferFrameSize = NEXTPOWEROFTWO(atoi(argv[j+1]));
break;
case 'b' :
checkNumArgs(2);
options.mNumBuffers = NEXTPOWEROFTWO(atoi(argv[j+1]));
break;
case 'l' :
checkNumArgs(2);
options.mMaxLogins = NEXTPOWEROFTWO(atoi(argv[j+1]));
break;
case 'n' :
checkNumArgs(2);
options.mMaxNodes = NEXTPOWEROFTWO(atoi(argv[j+1]));
break;
case 'd' :
checkNumArgs(2);
options.mMaxGraphDefs = NEXTPOWEROFTWO(atoi(argv[j+1]));
break;
case 'p' :
checkNumArgs(2);
options.mPassword = argv[j+1];
break;
case 'm' :
checkNumArgs(2);
options.mRealTimeMemorySize = atoi(argv[j+1]);
break;
case 'w' :
checkNumArgs(2);
options.mMaxWireBufs = atoi(argv[j+1]);
break;
case 'r' :
checkNumArgs(2);
options.mNumRGens = atoi(argv[j+1]);
break;
case 'S' :
checkNumArgs(2);
options.mPreferredSampleRate = (uint32)atof(argv[j+1]);
break;
case 'D' :
checkNumArgs(2);
options.mLoadGraphDefs = atoi(argv[j+1]);
break;
case 'N' :
#ifdef NO_LIBSNDFILE
scprintf("NRT mode not supported: scsynth compiled without libsndfile\n");
exit(0);
#endif
// -N cmd-filename input-filename output-filename sample-rate header-format sample-format
checkNumArgs(7);
options.mRealTime = false;
options.mNonRealTimeCmdFilename = strcmp(argv[j+1], "_") ? argv[j+1] : 0;
options.mNonRealTimeInputFilename = strcmp(argv[j+2], "_") ? argv[j+2] : 0;
options.mNonRealTimeOutputFilename = argv[j+3];
options.mPreferredSampleRate = (uint32)atof(argv[j+4]);
options.mNonRealTimeOutputHeaderFormat = argv[j+5];
options.mNonRealTimeOutputSampleFormat = argv[j+6];
break;
#ifdef __APPLE__
case 'I' :
checkNumArgs(2);
options.mInputStreamsEnabled = argv[j+1];
break;
case 'O' :
checkNumArgs(2);
options.mOutputStreamsEnabled = argv[j+1];
break;
case 'M':
#endif
case 'H' :
checkNumArgs(2);
options.mInDeviceName = argv[j+1];
if (i+1>argc || argv[j+2][0]=='-')
{
options.mOutDeviceName = options.mInDeviceName;
}
else
{
// If there's a second argument then the user wants separate I/O devices
options.mOutDeviceName = argv[j+2];
++i;
#ifdef JACK_BACKEND //JACK_BACKEND is not the right cmake flag!
// if (options.mInDeviceName.compare(options.mOutDeviceName) != 0)
scprintf("Warning: Two device names were specified, using %s\n", options.mInDeviceName);
#endif
}
break;
case 'L' :
checkNumArgs(1);
#if (_POSIX_MEMLOCK - 0) >= 200112L
options.mMemoryLocking = true;
#else
options.mMemoryLocking = false;
#endif
break;
case 'V' :
checkNumArgs(2);
options.mVerbosity = atoi(argv[j+1]);
break;
case 'v' :
scprintf("scsynth %s (%s)\n", SC_VersionString().c_str(), SC_BuildString().c_str());
exit(0);
break;
case 'R' :
checkNumArgs(2);
options.mRendezvous = atoi(argv[j+1]) > 0;
break;
case 'U' :
checkNumArgs(2);
options.mUGensPluginPath = argv[j+1];
break;
case 'P' :
checkNumArgs(2);
options.mRestrictedPath = argv[j+1];
break;
case 'C' :
checkNumArgs(2);
break;
case 'h':
default: Usage();
}
}
if (udpPortNum == -1 && tcpPortNum == -1 && options.mRealTime) {
scprintf("ERROR: There must be a -u and/or a -t options, or -N for nonrealtime.\n");
Usage();
}
if (options.mNumInputBusChannels + options.mNumOutputBusChannels > options.mNumAudioBusChannels) {
scprintf("ERROR: number of audio bus channels < inputs + outputs.\n");
Usage();
}
if (options.mRealTime) {
int port = (udpPortNum > 0) ? udpPortNum
: tcpPortNum;
options.mSharedMemoryID = port;
} else
options.mSharedMemoryID = 0;
struct World *world = World_New(&options);
if (!world) return 1;
if (!options.mRealTime) {
#ifdef NO_LIBSNDFILE
return 1;
#else
int exitCode = 0;
try {
World_NonRealTimeSynthesis(world, &options);
} catch (std::exception& exc) {
scprintf("%s\n", exc.what());
exitCode = 1;
}
return exitCode;
#endif
}
if (udpPortNum >= 0) {
if (!World_OpenUDP(world, bindTo.c_str(), udpPortNum)) {
World_Cleanup(world,true);
return 1;
}
}
if (tcpPortNum >= 0) {
if (!World_OpenTCP(world, bindTo.c_str(), tcpPortNum, options.mMaxLogins, 8)) {
World_Cleanup(world,true);
return 1;
}
}
if(options.mVerbosity >=0){
#ifdef NDEBUG
scprintf("SuperCollider 3 server ready.\n");
#else
scprintf("SuperCollider 3 server ready (debug build).\n");
#endif
}
fflush(stdout);
World_WaitForQuit(world,true);
#ifdef _WIN32
// clean up winsock
WSACleanup();
#endif // _WIN32
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment