Unable to run the Analysis example in NRT Synthesis helpfile

Hello all,

I don’t seem to be able to run the example below from the NRT Synthesis helpfile. I’ve also tried another similar code posted in the forum with no success. Every time, it seems that the score doesn’t create the resultpath file. So when the script attempts to read it, I get a message:
ERROR: Message 'readData' not understood. RECEIVER: nil

The oscpathfile is created though, so it’s not a write access problem.

Any ideas?

I’m on Windows.

(
fork {
    var server = Server(\nrt,
        options: ServerOptions.new
        .numOutputBusChannels_(2)
        .numInputBusChannels_(2)
    );
    var resultbuf, resultpath, oscpath, score, dur, sf, cond, size, data;

    // get duration
    sf = SoundFile.openRead(Platform.resourceDir +/+ "sounds/a11wlk01.wav");
    dur = sf.duration;
    sf.close;

    resultpath = PathName.tmp +/+ UniqueID.next ++ ".aiff";
    oscpath = PathName.tmp +/+ UniqueID.next ++ ".osc";

    score = Score([
        [0, (resultbuf = Buffer.new(server, 1000, 1, 0)).allocMsg],
        [0, [\d_recv, SynthDef(\onsets, {
            var sig = SoundIn.ar(0), // will come from NRT input file
            fft = FFT(LocalBuf(512, 1), sig),
            trig = Onsets.kr(fft),
            // count the triggers: this is the index to save the data into resultbuf
            i = PulseCount.kr(trig),
            // count time in seconds
            timer = Sweep.ar(1);
            // 'i' must be audio-rate for BufWr.ar
            BufWr.ar(timer, resultbuf, K2A.ar(i), loop: 0);
            BufWr.kr(i, resultbuf, DC.kr(0), 0);  // # of points in index 0
        }).asBytes]],
        [0, Synth.basicNew(\onsets, server, 1000).newMsg],
        [dur, resultbuf.writeMsg(resultpath, headerFormat: "AIFF", sampleFormat: "float")]
    ]);

    cond = Condition.new;
    // osc file path, output path, input path - input is soundfile to analyze
    score.recordNRT(oscpath, "NUL", sf.path, sampleRate: sf.sampleRate,
        options: ServerOptions.new
            .verbosity_(0)
            .numInputBusChannels_(sf.numChannels)
            .numOutputBusChannels_(sf.numChannels)
            .sampleRate_(sf.sampleRate),
        action: { cond.unhang }  // this re-awakens the process after NRT is finished
    );
    cond.hang;  // wait for completion

    sf = SoundFile.openRead(resultpath);
    // get the size: one frame at the start
    sf.readData(size = FloatArray.newClear(1));
    size = size[0];
    // now the rest of the data
    sf.readData(data = FloatArray.newClear(size));
    sf.close;

    File.delete(oscpath);
    File.delete(resultpath);
    server.remove;

    data.postln;  // these are your onsets!
};
)

Quickly checked here.

I manage to have the code working until the end by providing a AIFF result file to score.recordNRT:

    oscresult = PathName.tmp +/+ UniqueID.next ++ ".aiff";
	format("oscresult: %",oscresult).postln;
    // osc file path, output path, input path - input is soundfile to analyze
	score.recordNRT(oscpath, oscresult, sf.path, sampleRate: sf.sampleRate,
		options: ServerOptions.new
		.verbosity_(0)
		.numInputBusChannels_(sf.numChannels)
		.numOutputBusChannels_(sf.numChannels)
		.sampleRate_(sf.sampleRate),
		action: { "about to unhang".postln; cond.unhang }  // this re-awakens the process after NRT is finished
	);
	"hanged".postln;
    cond.hang;  // wait for completion
	"unhanged".postln;

Strangely, the score.recordNRT breaks my scsynth.exe. It stops to work with an error dialog box. However, after closure of the dialog box, the code resumes from the cond.hang.

Working on Win7.

I haven’t been able to get this example to work in Windows 10, under any combination of paths. (Edit: In Windows, the output audio path should be “NUL” rather than “/dev/null,” but in my Windows machine, even supplying a real file location did not get it working. And if this were the problem, I’d expect a “file could not be opened” printed error message, but there is none.)

scsynth.exe is returning with a nonzero error code -1073740791 = 0xC0000409. This appears to be related to the filesystem.

I can run the “Basic Usage” example in the NRT Guide without any errors, and the output audio file is created.

So there is something specific about this example that is broken in Windows. I have no idea what it is. I changed the paths, I changed it to use DiskIn instead of the input audio file, I tried removing the FFT and Onsets… nothing fixes the example on this machine.

So there is an error occurring in the server process, and no error message or any feedback of any kind, apart from the error code, in other words, no way to troubleshoot except to run scsynth in a debugger. And I don’t have the environment for that.

This is kinda bad.

Why is Windows such a pain? :laughing:

hjh

Thanks James, nice you took the time to check things out. At least I know it’s not just a simple oversight on my side.
I’ll try to figure out a way around it, and if I manage I’ll post it here.
Cheers,
JP

I just reread your answer, and it’s that simple! Just add a dummy output file to recordNRT, and it works. That’s fine with me, although puzzling. :slight_smile:

JP

Would you mind trying it with an output path "NUL" (as the help file recommends, in fact).

One wouldn’t expect "/dev/null" to work in Windows as this is the Unix specifier for a dummy file. In Windows, I could open a File at "NUL" in the client for writing, no error. However, neither NUL nor a real path fixed the NRT analysis example for me.

hjh

I’ve tried this here and does not seems to work on windows 10.

Is this solution working fine on mac and linux as well? Should we commit a change to documentation with this new version?

// Example: Extract onsets into a buffer.

(
fork {
	var server = Server(\nrt,
		options: ServerOptions.new
		.numOutputBusChannels_(2)
		.numInputBusChannels_(2)
	);
	var resultbuf, resultpath, oscpath, oscresult, score, dur, sf, cond, size, data;
	
	// get duration
	sf = SoundFile.openRead(Platform.resourceDir +/+ "sounds/a11wlk01.wav");
	dur = sf.duration;
	sf.close;
	
	resultpath = PathName.tmp +/+ UniqueID.next ++ ".aiff";
	oscpath = PathName.tmp +/+ UniqueID.next ++ ".osc";
	
	score = Score([
		[0, (resultbuf = Buffer.new(server, 1000, 1, 0)).allocMsg],
		[0, [\d_recv, SynthDef(\onsets, {
			var sig = SoundIn.ar(0), // will come from NRT input file
			fft = FFT(LocalBuf(512, 1), sig),
			trig = Onsets.kr(fft),
			// count the triggers: this is the index to save the data into resultbuf
			i = PulseCount.kr(trig),
			// count time in seconds
			timer = Sweep.ar(1);
			// 'i' must be audio-rate for BufWr.ar
			BufWr.ar(timer, resultbuf, K2A.ar(i), loop: 0);
			BufWr.kr(i, resultbuf, DC.kr(0), 0);  // # of points in index 0
		}).asBytes]],
		[0, Synth.basicNew(\onsets, server, 1000).newMsg],
		[dur, resultbuf.writeMsg(resultpath, headerFormat: "AIFF", sampleFormat: "float")]
	]);
	
	cond = Condition.new;
	
	oscresult = PathName.tmp +/+ UniqueID.next ++ ".aiff";
	format("oscresult: %",oscresult).postln;
	// osc file path, output path, input path - input is soundfile to analyze
	score.recordNRT(oscpath, oscresult, sf.path, sampleRate: sf.sampleRate,
		options: ServerOptions.new
		.verbosity_(0)
		.numInputBusChannels_(sf.numChannels)
		.numOutputBusChannels_(sf.numChannels)
		.sampleRate_(sf.sampleRate),
		action: { "about to unhang".postln; cond.unhang }  // this re-awakens the process after NRT is finished
	);
	"hanged".postln;
	cond.hang;  // wait for completion
	"unhanged".postln;
	
	sf = SoundFile.openRead(resultpath);
	// get the size: one frame at the start
	sf.readData(size = FloatArray.newClear(1));
	size = size[0];
	// now the rest of the data
	sf.readData(data = FloatArray.newClear(size));
	sf.close;
	
	File.delete(oscpath);
	File.delete(resultpath);
	server.remove;
	
	data.postln;  // these are your onsets!
};
)

There is no problem in Mac and Linux because /dev/null is standard by now.

I’d argue against changing the documentation such that the user gets a large output file at the end, which won’t be used.

The problem seems to be that Windows is unclear whether it should be NUL or nul or $null.

Null device - Wikipedia says:

NUL: or NUL on CP/M and DOS (internally \DEV\NUL), nul on OS/2 and newer Windows systems (internally \Device\Null on Windows NT), … In Windows Powershell, the equivalent is $null.

… whereas in posixy systems (Mac and Linux), there is only /dev/null, hence no confusion, hence Redmond once again goes out of its way to make things difficult.

I think the solution is to figure out what is really the null device in Windows, rather than to give up prematurely.

hjh