NRT process not outputting sound from DiskIn

Hey everyone. I am having some unexpected difficulty in trying to process a sound file using NRT and the DiskIN ugen. The resulting file is empty, even though it has the correct length, channels etc. Any hints on why? I suspect it’s got something to do with the buffer allocation, perhaps even something embarrasing!

prATK2Ambix{
        var targetFormat = \ambix;
        var score;
        var synthdefname = "hoaatk2ambix_o%".format(order).asSymbol;
        var fileprefix = targetFormat.asString ++ "_";
        var outFileName = path.pathOnly +/+ fileprefix ++ path.fileName;

        var synthfunc = {|out=0, fileBuffer|
            var hoa = DiskIn.ar(numChannels:order.asHoaOrder.size, bufnum:fileBuffer, loop:0);

            hoa = HoaNFCtrl.ar(
                in: hoa,
                encRadius: AtkHoa.refRadius,
                decRadius: 10.0,
                order: order
            );

            // exchange normalisation: N3D to SN3D
            hoa = HoaDecodeMatrix.ar(
                in: hoa,
                hoaMatrix: HoaMatrixDecoder.newFormat(format: targetFormat, order: order)
            );

            Out.ar(bus: out,  channelsArray: hoa);
        };
        var opts = ServerOptions.new
        .numOutputBusChannels_(soundfile.numChannels)
        .maxSynthDefs_(100000)
        .memSize_(65536 * 4)
        .numInputBusChannels_(soundfile.numChannels);

        fork{
            var cond = Condition.new;
            var server = Server("nrt%".format(Date.getDate.stamp), options: opts);
            var bufnum = 999;

            // HOAFX.loadSynthDefs(order:order);

            score = Score([
                // Allocate and read buffer for sound file
                [0.0, '/b_alloc', bufnum, soundfile.numFrames, soundfile.numChannels],
                [0.0, '/b_read', bufnum, path.fullPath, 0, -1, 0, 1],

                // Make synthdef
                [0.0, ['/d_recv',
                    SynthDef(synthdefname, synthfunc).asBytes
                ]],

                // Run synth
                [0.0, Synth.basicNew(synthdefname, server, 1000).newMsg(args: [\fileBuffer, bufnum])],

                // Close file
                [soundfile.duration, '/b_close', bufnum],

                // End process
                [soundfile.duration, nil]

            ]);

            "Starting file processing. This might take a bit of time...".postln;

            score.recordNRT(
                outputFilePath: outFileName,
                inputFilePath: soundfile.path,
                sampleRate: soundfile.sampleRate,
                headerFormat: soundfile.headerFormat,
                sampleFormat: soundfile.sampleFormat,
                options: server.options,
                duration: soundfile.duration ,
                action: {
                    cond.unhang();
                    "Done processing".postln;

                    defer{
                        var donewin, donelay, donebutton;
                        donewin = Window.new("Done");
                        donebutton = Button.new(donewin).states_([["Open folder"]]).action_({path.pathOnly.openOS()});
                        donelay = VLayout(StaticText.new(donewin).string_("Done processing file!"), donebutton);
                        donewin.layout_(donelay);
                        donewin.front();

                    }
                }
            );

            "Waiting for process to finish".postln;

            cond.hang;
        }
    }

Not sure if this is it, but this looks suspect. You wouldn’t allocate space for the whole file when using DiskIn.

Just an initial thought.

hjh

Oh wait, I see the real issue – the second pair of brackets for the command is missing, for both of these, and also for b_close later.

I’m certain I’ve made this same mistake before – it’s way too easy to overlook. I wonder if we should add a method to Score with a time and msg argument: 2-level array is confusing.

hjh

I might be missing something, but I thought that if you use inputFilePath for .recordNRT, then you’d read that sound with SoundIn.ar, isn’t that right? You don’t need to allocate the buffer then.
And if you do allocate the buffer, then you’d read it with PlayBuf.ar, not DiskIn.

This is true, but you don’t have control over where to start in the input file (must always start at the beginning).

DiskIn requires an allocated buffer, which has been pre-filled by b_read with the “leaveOpen” flag set to true. You would use PlayBuf if the buffer has been read and the file handle closed.

But the real problem in the OP is the missing brackets around the messages proper.

hjh

Sure I know that, however I missed the leaveOpen flag. I didn’t know you can still use it in NRT though.

I’ve used it – for some screencasts, I had a requirement to play back the audio very slightly faster/slower into a new file. VDiskIn in NRT got that job done in something like 10-20 seconds processing time, for 30 minutes of audio :+1:

Streaming a long audio file for processing is an excellent use case for NRT.

hjh

You were absolutely right!! Thanks so much !

I thought that as well but in this case I could not get it working for some reason. I tried changing the DiskIn line of my synthdef to
SoundIn.ar((0..numChannels)) but with equally silent result.

Hm, I’ve definitely used the audio input file before.

For instance, here’s an unpublished extension that I have locally, part of a SoundFile normalizeNRT implementation. There is an issue with it – it has a startFrame argument, but there is no way to specify the starting frame of the input file, so effectively it’s always 0. For that reason, I should probably rewrite it with DiskIn – but in the meantime, it’s a known working example using the NRT input file.

hjh

+ SoundFile {
	scaleAndWriteNRT { |outPath, scale, startFrame, numFrames, chunkSize, threaded = false, newHeaderFormat(this.headerFormat), newSampleFormat(this.sampleFormat)|
		var score, outbuf, options, cond, oscpath, inbuf;

		scale = scale.asArray.keep(this.numChannels);

		// erm, yeah, this is an oops
		if(numFrames.isNil or: { numFrames < 0 }) {
			numFrames = this.numFrames - startFrame;
		};

		score = Score([
			[0, [\d_recv, SynthDef(\scaler, {
				Out.ar(0, SoundIn.ar((0 .. this.numChannels - 1)) * scale)
			}).asBytes]],
			[0, Synth.basicNew(\scaler, Server.default, 1000).newMsg]
		]);

		options = ServerOptions.new
		.verbosity_(-1)
		.numInputBusChannels_(this.numChannels)
		.numOutputBusChannels_(this.numChannels)
		.sampleRate_(this.sampleRate);

		oscpath = (PathName.tmp +/+ "osc" ++ this.hash);

		forkIfNeeded {
			cond = Condition.new;
			score.recordNRT(oscpath, outPath, this.path, this.sampleRate, newHeaderFormat, newSampleFormat, duration: numFrames / this.sampleRate, options: options, action: { cond.unhang });
			cond.hang;

			File.delete(oscpath);
		};
	}
}
1 Like