NRT Export to FLAC

I’m curious if there is a way to export to FLAC from an NRT score. I seem to be able to record into FLAC and playback FLAC without any difficulty - but doing a recordNRT to FLAC produces the following error:
Couldn't open non real time output file.

Does anyone know of a way around this? Thanks!

Not too sure, but judging from the error message, I assume the NRT process needs be able to write the samples directly into the file and because FLAC is encoded (and therefore the samples might not appear simply consecutively) it can’t do that.

What happens if you record into a buffer and then try to save the buffer as a FLAC?

I seem to be able to save a buffer as FLAC without any trouble. Is there a way to recordNRT to a buffer and then save as FLAC?

(
b = Buffer.alloc(s, 512, 1);
b.sine1(1.0 / [1, 2, 3, 4], true, true, true);
b.write("/Users/bd/Desktop/test.flac", "flac", "int24");
)

Using the first example from the NRT guide (which I won’t quote in full, just the rendering statement), this way does not reproduce the problem – the file is created with the expected, correct contents:

a.recordNRT(
    outputFilePath: "~/nrt-help.flac".standardizePath,
    headerFormat: "flac",
    sampleFormat: "int16",
    options: server.options,
    duration: 1,
    action: { "done".postln }
);

Changing “sampleFormat’” to “float” does produce the “couldn’t open” error:

a.recordNRT(
    outputFilePath: "~/nrt-help.flac".standardizePath,
    headerFormat: "flac",
    sampleFormat: "float",
    options: server.options,
    duration: 1,
    action: { "done".postln }
);

So my best guess, with available information, is that you might be setting the wrong sample format. FLAC supports int16 and int24, but is incompatible with float samples.

SC uses libsndfile for all sound file reading and writing. We just ask libsndfile to open the file, and pass the raw sample values to libsndfile. Then libsndfile is responsible for any codec involvement. From our side, access to any sound file format that libsndfile supports should be completely transparent.

hjh

Ah, interesting. I did try the sample format arguments for int16 and int24 and still got the same issue. I wonder if it might be an issue with my libsndfile. I’ll try that next.

The full error actually is now reading:

nrt : setting clientID to 0.
-> nrt
VSTPlugin 0.5.4
read cache file /Users/bd/.VSTPlugin/cache.ini
Found 0 LADSPA plugins
Couldn't open non real time output file.

done

My suspicion is that this means SC is looking for libsndfile in that weird VST cache file. I’m not sure why this would be or how to go about fixing it.

I don’t believe this is the case - IIUC that’s not possible.

It would be recommended to post a full reproducer to your issue.
Also, what is the SC version and the operating system you are using?

For completeness sake:
It’s true that we depend on libsndfile for all sound file operations and in principle every format supported by libsndfile should be supported by SC.

That’s only partially true, because there’s a translation from strings in SC indicating sample format to proper symbols in libsndfile and that part had at least one bug regarding the vorbis format (this is fixed in SC 3.13). Flac however was not, and is not broken, as far as I know.
Also, when new format is added to libsndfile, we need to manually update that part of SC sourcecode to support new formats, and we need to make sure our Windows and macOS builds ship with the updated version of the library. E.g. this was recently done to add mpeg support.

Sure -
I’m using Mac OSX 10.14.6 - I’ve been switching back and forth between SuperCollider 3.13rc1 and 3.12.2.

This is the full code:

(
var server = Server(\nrt,
    options: ServerOptions.new
    .numOutputBusChannels_(2)
    .numInputBusChannels_(2)
);

a = Score([
    [0.0, ['/d_recv',
        SynthDef(\NRTsine, { |out, freq = 440|
            Out.ar(out, SinOsc.ar(freq, 0, 0.2).dup)
        }).asBytes
    ]],
    [0.0, (x = Synth.basicNew(\NRTsine, server, 1000)).newMsg(args: [freq: 400])],
    [1.0, x.freeMsg]
]);

a.recordNRT(
    outputFilePath: "~/nrt-help.flac".standardizePath,
    headerFormat: "flac",
    sampleFormat: "int16",
    options: server.options,
    duration: 1,
    action: { "done".postln }
);

server.remove;
)

This is the full error message:

nrt : setting clientID to 0.
-> nrt
VSTPlugin 0.5.4
read cache file /Users/bd/.VSTPlugin/cache.ini
Found 0 LADSPA plugins
Couldn't open non real time output file.

done

Thanks for sharing the example.

It seems that VSTPlugin indeed messes something up here. Your example works for me if I remove VSTPlugin from Extensions, but I get the same error as you when VSTPlugin is installed. I’m also on macOS, SC 3.13.0-rc1

@Spacechild1 do you have any ideas about this?

Hmm… I just removed VSTPlugin and I’m still getting an error:

-> nrt
Found 0 LADSPA plugins
Couldn't open non real time output file.

done

Can you try writing into your Documents folder?

I wonder if OS X doesn’t want you writing to home

outputFilePath: “~/Documents/nrt-help.flac".standardizePath,

Sad to say this doesn’t work either… Maybe it would be smart to do a full re-install at this point.

Well, I deleted all Quarks and Extensions, loaded SC 3.13.0-rc2… and still no good. I’m at a loss!

This is a shot in the dark, but when something weird is happening, it could be any little difference.

Looking into the sources:

  • NRT output file is prepared in SC_World.cpp, L579 ff.
  • b_write output file is prepared in SC_SequencedCommand.cpp, L996 ff.

The steps are:

  • Have a SF_INFO variable.
  • Set sample rate and output channels on this object.
  • Call sndfileFormatInfoFromStrings() with header and sample format strings.
  • sndfileOpenFromCStr() gives the audio file handle.

For NRT (where there’s a problem with FLAC in some systems), these are: L579 (declare variable), L585-586 (SR/numCh), L587 (format info), L590 (open).

For b_write (where no problem was observed), it’s: SC_SequencedCommand.h L337 (member variable), L1013-1014 (sr/numch), L997 (format info), L1016 (open).

All these appear to be functionally the same… except that b_write initializes the memory for the file info object – memset(&mFileInfo, 0, sizeof(mFileInfo)); – while I cannot see anything like this in the NRT code.

I think C does not automatically initialize memory for functions’ local vars (but I could be wrong). If not, and we aren’t initializing, then it’s a possible source of otherwise unaccountable behavior. (Seems unlikely to me, because I didn’t see a problem… but… when things are weird, anything could be a culprit.)

hjh

“Couldn’t open non real time output file.”

It would be nice if scsynth would also print the actual libsndfile error message…

@b.d Does it work with Supernova? If yes, we know it is a scsynth bug.

@jamshark70 The missing memset is certainly a bug and should be fixed. Looking at the libsndfile sources, it does not seem to cause any immediate problems, though, so it could be a red herring.

@Spacechild1
I haven’t worked too much with Supernova - is it just as simple as changing the server like this?

(
var server = Server(\supernova,
    options: ServerOptions.new
    .numOutputBusChannels_(2)
    .numInputBusChannels_(2)
);

If so, this produces the same error for me.

You need to do the following before calling recordNRT:

Server.supernova;
Score.program = Server.program;

Aha! That seems to work.

Do you mean that you can successfully write the FLAC file with supernova?