in SuperCollider what is the best way to render a sound a file? - supercollider

What is the best way to programatically render a SuperCollider program to a file (say a wav file).
Can I specify the duration of the file (eg 30 seconds)?

You can do this with Score.recordNRT.
There's a tutorial on how to use it here.

There are lots of different ways to do this in addition to Score.recordNRT (which is maybe one of the more convenient ones, and also something I did not know about). DiskOut.ar takes path and channelsArray as args. You could also try the .record instance method that Server has. Here are examples (from the help docs) of both:
The DiskOut.ar way
// start something to record
x = Synth.new("bubbles");
// allocate a disk i/o buffer
b= Buffer.alloc(s, 65536, 2);
// create an output file for this buffer, leave it open
b.write("~/diskouttest.aiff".standardizePath, "aiff", "int16", 0, 0, true);
// create the diskout node; making sure it comes after the source
d = Synth.tail(nil, "help-Diskout", ["bufnum", b]);
// stop recording
d.free;
// stop the bubbles
x.free;
// close the buffer and the soundfile
b.close;
// free the buffer
b.free;
// play it back
(
x = Synth.basicNew("help-Diskin-2chan");
m = { arg buf; x.addToHeadMsg(nil, [\bufnum,buf])};
b = Buffer.cueSoundFile(s,"~/diskouttest.aiff".standardizePath, 0, 2, completionMessage: m);
)
x.free; b.close; b.free; // cleanup
The Server.record way:
s.boot; // start the server
// something to record
(
SynthDef("bubbles", {
    var f, zout;
    f = LFSaw.kr(0.4, 0, 24, LFSaw.kr([8,7.23], 0, 3, 80)).midicps; // glissando function
    zout = CombN.ar(SinOsc.ar(f, 0, 0.04), 0.2, 0.2, 4); // echoing sine wave
    Out.ar(0, zout);
}).add;
SynthDef("tpulse", { arg out=0,freq=700,sawFreq=440.0;
    Out.ar(out, SyncSaw.ar(freq,  sawFreq,0.1) )
}).add;
)
x = Synth.new("bubbles");
s.prepareForRecord; // you have to call this first
s.record;
s.pauseRecording; // pausable
s.record // start again
s.stopRecording; // this closes the file and deallocates the buffer recording node, etc.
x.free; // stop the synths
// look in your recordings folder and you'll find a file named for this date and time

Related

Passing an argument to a SynthDef doesn't register when synth is initialized

I have a simple SynthDef where I want to use the CCIn class, like so:
(
SynthDef(\lfo_sin, {|bus, amp, myArg|
var m = CCIn.new;
var v = [300, 700, \exp].asSpec;
var sig = SinOsc.ar(m.kr(0, myArg, v), mul:amp);
Out.ar(bus, sig);
}).add;
)
When I instantiate it like so y = Synth(\lfo_sin, [\bus, 0, \amp, 1, \myArg, 71]);, to match with the MIDI CC on my MIDI controller, I am not able to use the CCIn.kr method like I should.
If I however directly type in the MIDI CC when I define the SynthDef like so:
(
SynthDef(\lfo_sin2, {|bus, amp|
var m = CCIn.new;
var v = [300, 700, \exp].asSpec;
var sig = SinOsc.ar(m.kr(0, 71, v), mul:amp);
Out.ar(bus, sig);
}).add;
)
everything runs like it should and I am able to control the frequency using my MIDI controller.
Why does this behavior happen and how can I modify my code so that I can pass in the MIDI CC when initializing the synth or setting the argument afterwards?
If you take a look at the source for CCIn, you can see it's doing something a bit more complex than an ordinary UGen:
kr { |chan = 0, num = 0, spec = \amp, lag = 0.05|
var outArray = [chan, num, spec, lag].flop.collect{ |args|
var ch, n, sp, lg;
# ch, n, sp, lg = args;
(sp.asSpec.map( In.kr(this.prGetBus(ch, n).index) ).lag3(lg))
};
if (outArray.size>1) {^outArray} {^(outArray[0])} //fix to work with muliout
Specifically, this...
this.prGetBus(ch, n)
is using the provided channel and number (ch and n) to look up the Bus from which it can read the MIDI data (see prGetBus). It's doing this lookup as part of BUILDING the SynthDef, not RUNNING the Synth, so once it's been built the bus it's reading from is pretty much fixed. The CCIn quark obscures some fairly complex things under the hood in order to behave as a simple UGen, so it's unlikely you'll easily be able to get the behavior you're looking for.
Here are a few alternatives.
1. Write your MIDI data to a bus yourself
// One for each cc number
~ccBusses = 127.collect({
Bus.control(s, 1);
});
// A midi responder that sets the value of the right bus
MIDIdef.cc(\cc, {
|value, cc|
~ccBusses[cc].set(value);
}, ccNum: (0..127) ) // meaning: all cc values
// Once those are set up, to map a cc to a new synth use:
Synth(\mySynth, args:[\freq, ~ccBusses[10].asMap]);
2. Using the Connection quark
// Create a value between 100..2400, controlled by MIDI
~freq = MIDIControlValue(spec:ControlSpec(100, 2400));
~freq.cc_(10); // cc number 10
// Run your synth
~note = Synth(\mySynth, args:[\freq, ~freq]);
// Connect the value of ~freq to the \freq argument of your synth. Now, MIDI changes will be broadcast to your synth.
~freq.signal(\value).connectTo(~note.argSlot(\freq));

Where is the callback function in Apple's PlaySequence project?

I want to bounce a midi file offline, and as the PlaySequence example does exactly this, I am trying to understand it.
I keep reading everywhere that you need a callback function to do anything in CoreAudio, yet I cannot see any in this project.
I paste the loop containing the AudioUnitRender, thanks for your help!
CAStreamBasicDescription clientFormat = CAStreamBasicDescription();
size = sizeof(clientFormat);
FailIf ((result = AudioUnitGetProperty (outputUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Output, 0,
&clientFormat, &size)), fail, "AudioUnitGetProperty: kAudioUnitProperty_StreamFormat");
size = sizeof(clientFormat);
FailIf ((result = ExtAudioFileSetProperty(outfile, kExtAudioFileProperty_ClientDataFormat, size, &clientFormat)), fail, "ExtAudioFileSetProperty: kExtAudioFileProperty_ClientDataFormat");
{
MusicTimeStamp currentTime;
AUOutputBL outputBuffer (clientFormat, numFrames);
AudioTimeStamp tStamp;
memset (&tStamp, 0, sizeof(AudioTimeStamp));
tStamp.mFlags = kAudioTimeStampSampleTimeValid;
int i = 0;
int numTimesFor10Secs = (int)(10. / (numFrames / srate));
do {
outputBuffer.Prepare();
AudioUnitRenderActionFlags actionFlags = 0;
FailIf ((result = AudioUnitRender (outputUnit, &actionFlags, &tStamp, 0, numFrames, outputBuffer.ABL())), fail, "AudioUnitRender");
tStamp.mSampleTime += numFrames;
FailIf ((result = ExtAudioFileWrite(outfile, numFrames, outputBuffer.ABL())), fail, "ExtAudioFileWrite");
FailIf ((result = MusicPlayerGetTime (player, &currentTime)), fail, "MusicPlayerGetTime");
if (shouldPrint && (++i % numTimesFor10Secs == 0))
printf ("current time: %6.2f beats\n", currentTime);
} while (currentTime < sequenceLength);
}
I had a look at the project and you're right, it does not have a rendercallback. Render callbacks have their place withing coreaudio audiounit effect processing. The call to setup a render callback looks like this:
inline OSStatus SetInputCallback (CAAudioUnit &inUnit, AURenderCallbackStruct &inInputCallback)
{
return inUnit.SetProperty (kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&inInputCallback,
sizeof(inInputCallback));
}
However this code is just one big main() which setups up the sequence, augraph, music player and then the filewriter WriteOutputFile in case there's an outputfile to bounce to.
I recommend you set some breakpoints at key methods, and walk through the code, watching what it does and looking at variables.
EDIT: Note, that in setting up your rendercallback on iOS on your RemoteIO (which doubles as input & output units), getting the correct stream format on the correct scope & bus element numbers in your setproperty calls can be tricky. Refer to this from the Apple docs.

Cannot get OpenAL to play sound

I've searched the net, I've searched here. I've found code that I could compile and it works fine, but for some reason my code won't produce any sound. I'm porting an old game to the PC (Windows,) and I'm trying to make it as authentic as possible, so I'm wanting to use generated wave forms. I've pretty much copied and pasted the working code (only adding in multiple voices,) and it still won't work (even thought the exact same code for a single voice works fine.) I know I'm missing something obvious, but I just cannot figure out what. Any help would be appreciated thank you.
First some notes... I was looking for something that would allow me to use the original methodology. The original system used paired bytes for music (sound effects - only 2 - were handled in code.) A time byte that counted down every time the routine was called, and a note byte that was played until time reached zero. this was done by patching into the interrupt vector, windows doesn't allow that, so I set up a timer that routing that accomplished the same thing. The timer kicks in, updates the display, and then runs the music sequence. I set this up with a defined time so that I only have one place to adjust the timing at (to get it as close as possible to the original sequence. The music is a generated wave form (and I've double checked the math, and even examined the generated data in debug mode,) and it looks good. The sequence looks good, but doesn't actually produce sound. I tried SDL2 first, and it's method of only playing 1 sound doesn't work for me, also, unless I make the sample duration extremely short (and the sound produced this way is awful,) I can't match the timing (it plays the entire sample through it's own interrupt without letting me make adjustments.) Also, blending the 3 voices together (when they all run with different timings,) is a mess. Most of the other engines I examined work in much the same way, they want to use their own callback interrupt and won't allow me to tweak it appropriately. This is why I started working with OpenAL. It allows multiple voices (sources,) and allows me to set the timings myself. On advice from several forums, I set it up so that the sample lengths are all multiples of full cycles.
Anyway, here's the code.
int main(int argc, char* argv[])
{
FreeConsole(); //Get rid of the DOS console, don't need it
if (InitLog() < 0) return -1; //Start logging
UINT_PTR tim = NULL;
SDL_Event event;
InitVideo(false); //Set to window for now, will put options in later
curmusic = 5;
InitAudio();
SetTimer(NULL,tim,_FREQ_,TimerProc);
SDL_PollEvent(&event);
while (event.type != SDL_KEYDOWN) SDL_PollEvent(&event);
SDL_Quit();
return 0;
}
void CALLBACK TimerProc(HWND hWind, UINT Msg, UINT_PTR idEvent, DWORD dwTime)
{
RenderOutput();
PlayMusic();
//UpdateTimer();
//RotateGate();
return;
}
void InitAudio(void)
{
ALCdevice *dev;
ALCcontext *cxt;
Log("Initializing OpenAL Audio\r\n");
dev = alcOpenDevice(NULL);
if (!dev) {
Log("Failed to open an audio device\r\n");
exit(-1);
}
cxt = alcCreateContext(dev, NULL);
alcMakeContextCurrent(cxt);
if(!cxt) {
Log("Failed to create audio context\r\n");
exit(-1);
}
alGenBuffers(4,Buffer);
if (alGetError() != AL_NO_ERROR) {
Log("Error during buffer creation\r\n");
exit(-1);
}
alGenSources(4, Source);
if (alGetError() != AL_NO_ERROR) {
Log("Error during source creation\r\n");
exit(-1);
}
return;
}
void PlayMusic()
{
static int oldsong, ofset, mtime[4];
double freq;
ALuint srate = 44100;
ALuint voice, i, note, len, hold;
short buf[4][_BUFFSIZE_];
bool test[4] = {false, false, false, false};
if (curmusic != oldsong) {
oldsong = (int)curmusic;
if (curmusic > 0)
ofset = moffset[(curmusic - 1)];
for (voice = 1; voice < 4; voice++)
alSourceStop(Source[voice]);
mtime[voice] = 0;
return;
}
if (curmusic == 0) return;
//Only 3 voices for music, but have
for (voice = 0; voice < 3; voice ++) { // 4 set asside for eventual sound effects
if (mtime[voice] == 0) { //is note finished
alSourceStop(Source[voice]); //It is, so stop the channel (source)
mtime[voice] = music[ofset++]; //Get the next duration
if (mtime[voice] == 0) {oldsong = 0; return;} //zero marks end, so restart
note = music[ofset++]; //Get the next note
if (note > 127) { //Old HW data was designed for could only
if (note == 255) note = 127; //use values 128 - 255 (255 = 127)
freq = (15980 / (voice + (int)(voice / 3))) / (256 - note); //freq of note
len = (ALuint)(srate / freq); //A single cycle of that freq.
hold = len;
while (len < (srate / (1000 / _FREQ_))) len += hold; //Multiply till 1 interrup cycle
while (len > _BUFFSIZE_) len -= hold; //Don't overload buffer
if (len == 0) len = _BUFFSIZE_; //Just to be safe
for (i = 0; i < len; i++) //calculate sine wave and put in buffer
buf[voice][i] = (short)((32760 * sin((2 * M_PI * i * freq) / srate)));
alBufferData(Buffer[voice], AL_FORMAT_MONO16, buf[voice], len, srate);
alSourcei(openAL.Source[i], AL_LOOPING, AL_TRUE);
alSourcei(Source[i], AL_BUFFER, Buffer[i]);
alSourcePlay(Source[voice]);
}
} else --mtime[voice];
}
}
Well, it turns out there were 3 problems with my code. First, you have to link the built wave buffer to the AL generated buffer "before" you link the buffer to the source:
alBufferData(buffer,AL_FORMAT_MONO16,&wave_sample,sample_lenght * sizeof(short),frequency);
alSourcei(source,AL_BUFFER,buffer);
Also in the above example, I multiplied the sample_length by how many bytes are in each sample (in this case "sizeof(short)".
The final problem was that you need to un-link a buffer from the source before you change the buffer data
alSourcei(source,AL_BUFFER,NULL);
The music would play, but not correctly until I added that line to the note change code.

Joystick won't work using SDL

I'm building a simple game in SDL. I've been through countless tutorials and I've clearly missed something as it still ignoring my Joystick completely
In my constructor
SDL_JoystickEventState(SDL_ENABLE);
joystick = SDL_JoystickOpen(0);
In my update I'm calling a test to check I have actually initialized the joystick
if (SDL_NumJoysticks() <= 0)
{
done = true;
}
Here is my player update as well
void World::playerMovement()
{
SDL_Event event;
while (SDL_PollEvent (&event))
{
switch (event.type)
{
case SDL_QUIT:
done = true;
break;
case SDL_JOYAXISMOTION:
if ( ( event.jaxis.value < -3200 ) || (event.jaxis.value > 3200 ) )
{
test = true;
}
break;
}
}
}
Test is simply a bool which once true will mean my enemies start spawning. I also run a check in main
if (SDL_Init( SDL_INIT_VIDEO | SDL_INIT_JOYSTICK ) < 0)
{
fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
done = true;
}
When I run the game it loads as normal but no matter how much I move the joystick it won't set test to true.
I also tried using the following in the while poll event loop instead.
if (event.type == SDL_JOYAXISMOTION)
{
if(SDL_JoystickGetAxis(joystick, 1) > 0)
{
test = true;
}
}
Any idea's what I have missed?
I think emartel has the best answer to make sure SDL_joystick is working.
When does World::playerMovement() happen? The overall flow of your program is hard to determine from these snippets.
I'm happy to share with you my code for handling joysticks, which keeps track of: multiple joysticks, axes scaled [-1,1] with deadzone removed, and buttons held down.
http://www.raptor007.com/code/RaptorEngine_Joystick.zip
And here's a snippet of how that would be utilized as part of your main loop:
// FIXME: SDL needs to be initialized before we get here.
JoystickManager Joy;
Joy.Initialize();
double deadzone = 0.02;
// Main loop.
bool done = false;
while( ! done )
{
// Keep the list of joysticks up-to-date.
Joy.FindJoysticks();
// Handle all user input.
SDL_Event event;
while( SDL_PollEvent( &event ) )
{
// Let the JoystickManager track events relevant to it.
Joy.TrackEvent( &event );
// FIXME: Handle single-press events here (next target, etc).
// Don't handle button-held-down events like firing (see below).
if( event.type == SDL_QUIT )
done = true;
}
// Read joystick 0 analog axes.
double roll = Joy.Axis( 0, 0, deadzone );
double pitch = Joy.Axis( 0, 1, deadzone );
double yaw = Joy.Axis( 0, 3, deadzone );
double throttle = Joy.AxisScaled( 0, 2, 1., 0., 0., deadzone );
// Read joystick 0 buttons held down.
bool firing = Joy.ButtonDown( 0, 0 );
// FIXME: Update game objects and draw graphics.
}
I found a weird behaviour in SDL2:
If no events are put into the queue, try adding the following before the SDL_Init call:
SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS,"1");
Are you sure joystick points to a valid joystick?
You state that you're getting it in your Constructor... does that contructor happen to be called before you initialize SDL with SDL_INIT_JOYSTICK? This could happen if your player is a global variable.
Make sure that in order you:
Init the Joystick subsystem, either by adding it to your SDL_Init with | SDL_INIT_JOYSTICK or by calling SDL_InitSubSystem(SDL_INIT_JOYSTICK);
Check SDL_NumJoysticks() > 0
Get joystick 0: joystick = SDL_JoystickOpen(0);
Enable events: SDL_JoystickEventState(SDL_ENABLE);
Process your events with SDL_PollEvent
At the end of your program, close your joystick: SDL_JoystickClose(joystick);
Also, make sure the joystick is properly detected in Windows and reports its inputs properly.
Looks like your SDL isn't init proper.
replace
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)
with
SDL_Init(SDL_INIT_EVERYTHING)
Is this SDL 1.2 or 2.0? In my case, on 2.0 SDL_PollEvent(&event) didn't actually put any data in the event struct. After that call, I had to use SDL_JoystickGetAxis(joystick_id, axis) and friends to get data.
So in your case, try to move the SDL_JoystickGetAxis call out of the if-test on event-type.
If you call SDL_NumJoysticks to get the number of controllers connected, then call SDL_JoystickOpen which returns a joystick identifier before your game loop then you will receive the SDL_JOYAXISMOTION events.
e.g.
int num_joy;
num_joy = SDL_NumJoysticks();
printf("%d joysticks found\n", num_joy);
for(int i = 0; i < num_joy; i++)
{
SDL_Joystick *joystick = SDL_JoystickOpen(i);
printf("Joystick name: %s\n", SDL_JoystickName(joystick));
}
SDL_Event event;
bool quit = false;
// Game loop
while(!quit)
{
// event loop
while(SDL_PollEvent(&event))
{
if (event.type == SDL_JOYAXISMOTION)
{
printf("Joystick______EVENT!\n");
}
// etc.....
See https://wiki.libsdl.org/SDL_JoystickName
I do not know how this can help you, but I do know that pygame supports joystick. And pygame is the python port of the SDL library. If everything fails, I guess you can always write that particular piece of code in python.

Save snapshots of minimized windows with Xlib

In short, I want to write a Gnome-Shell-style window switcher. So I need to fetch snapshots of all the windows. My current program looks like this:
char filename[101];
sprintf(filename, "%d.png", (int)win_list[i]);
GdkWindow *win_gdk = gdk_x11_window_foreign_new_for_display
(gdk_display_get_default(), win_list[i]);
gint _w, _h;
gdk_drawable_get_size(GDK_DRAWABLE(win_gdk), &_w, &_h);
XEvent _xevent;
_xevent.xexpose =
(XExposeEvent)
{
.type = Expose,
.send_event = True,
.display = xsu_vars.dpy,
.window = win_list[i],
.x = 0, .y = 0, .width = _w, .height = _h,
.count = 0
};
XSendEvent(xsu_vars.dpy, win_list[i], False, 0, &_xevent);
GdkPixbuf *_pb = gdk_pixbuf_get_from_drawable(
NULL, GDK_DRAWABLE(win_gdk), NULL, 0, 0, 0, 0, _w, _h);
if(_pb != NULL) {
cairo_surface_t *_surf_cairo = cairo_image_surface_create(
CAIRO_FORMAT_RGB24, _w, _h);
cairo_t *_cr = cairo_create(_surf_cairo);
gdk_cairo_set_source_pixbuf(_cr, _pb, 0, 0);
cairo_paint(_cr);
cairo_surface_write_to_png(_surf_cairo, filename);
printf("%s saved successfully!\n", filename);
} else {
printf("failed...\n");
}
The program works well well, but it will not generate correct images for those windows which are on a different desktop of minimized -- they would look like this:
Note that I send a expose event to all windows before generating pixbufs of them.
UPDATE:
It seems that xlib doesn't support that. So the only way may be creating cache manually.
This is possible with Composite extension - see "Preventing the backing pixmap from being freed when the window is hidden/destroyed" section in tutorial.
Yes, your update is correct. When a window is unmapped (or covered up), X just discards its contents; they don't exist anywhere in order to be snapshotted.
I believe libwnck contains code to do this and other parts of writing a switcher, btw. It's basically a library for writing things like window switchers.

Resources