EncoderFLAC.Start (bassenc_flac) BASS_ERROR_FILEOPEN

Started by VorTechS,

VorTechS

Hi all!  It's been a while!  I hope everyone is keeping well!

Today I've been looking to experiment with FLAC encoding using bassenc_flac, having resolved all of my previous issues and having a nice stable platform to build on - using slightly out of date versions of BASS et al, but all 2.4.14 orientated.

I downloaded the latest version of bassenc_flac.dll (win32, v2.4.5) to build a FLAC plugin for my software. 

I'm using Bass.NET v2.4.13.3 and bass.dll v2.4.14.0 and bassenc.dll of 2.4.14.0

I'm using the following C# code to open an instance of the encoder, alongside data provided by a core DSP Callback (which pushes the received and modified data to all listening endpoints, of which this is one of them):

        private bool StartFlacEncoder(int freq, int chans)
        {
            _flacFilename = GetTargetFilename();

            Log($"StartFlacEncoder — outputFile='{_flacFilename}' freq={freq} chans={chans}");

            string outputDir = Path.GetDirectoryName(_flacFilename);
            if (!Directory.Exists(outputDir))
            {
                try
                {
                    Directory.CreateDirectory(outputDir);
                    Log($"StartFlacEncoder — created output directory '{outputDir}'");
                }
                catch (Exception ex)
                {
                    _lastEncoderError = $"Cannot create output directory '{outputDir}': {ex.Message}";
                    Log(_lastEncoderError);
                    return false;
                }
            }

            try
            {
                string testFile = Path.Combine(outputDir, $"__flac_write_test_{Guid.NewGuid():N}.tmp");
                File.WriteAllBytes(testFile, new byte[0]);
                File.Delete(testFile);
                Log($"StartFlacEncoder — output directory write check passed");
            }
            catch (Exception ex)
            {
                _lastEncoderError = $"Output directory not writable '{outputDir}': {ex.Message}";
                Log(_lastEncoderError);
                return false;
            }

            // bassenc_flac.dll uses ANSI fopen() internally and fails on any path
            // containing spaces — including the directory portion.  Write to a
            // fixed short name in %TEMP% (e.g. C:\Users\Stuart\AppData\Local\Temp)
            // which is always a space-free ASCII path, then rename to the real
            // long-path filename once encoding has finished and the file is closed.
            _encoderTempFilename = GetSafeEncoderTempPath();

            try { if (File.Exists(_encoderTempFilename)) File.Delete(_encoderTempFilename); }
            catch { }

            Log($"StartFlacEncoder — tempFile='{_encoderTempFilename}'");

            int avail = Bass.BASS_ChannelGetData(_sourceChannel, IntPtr.Zero, (int)BASSData.BASS_DATA_AVAILABLE);
            _useDspFeed = (avail < 0);

            Log($"StartFlacEncoder — availProbe={avail} useDspFeed={_useDspFeed}");

            _encoderMixer = BassMix.BASS_Mixer_StreamCreate(
                freq, chans,
                BASSFlag.BASS_SAMPLE_FLOAT | BASSFlag.BASS_MIXER_NONSTOP | BASSFlag.BASS_STREAM_DECODE);

            if (_encoderMixer == 0)
            {
                GetError("Failed to create FLAC encoder mixer");
                return false;
            }

            Log($"StartFlacEncoder — mixer={_encoderMixer}");

            if (_useDspFeed)
            {
                int ringCapacity = freq * chans * 2;
                _ringBuffer = new float[ringCapacity];
                _ringWritePos = 0;
                _ringReadPos = 0;

                _streamProc = new STREAMPROC(FlacStreamCallback);
                _callbackStream = Bass.BASS_StreamCreate(
                    freq, chans,
                    BASSFlag.BASS_STREAM_DECODE | BASSFlag.BASS_SAMPLE_FLOAT,
                    _streamProc,
                    IntPtr.Zero);

                if (_callbackStream == 0)
                {
                    GetError("Failed to create FLAC callback stream");
                    CleanupBassHandles();
                    return false;
                }

                bool added = BassMix.BASS_Mixer_StreamAddChannel(
                    _encoderMixer, _callbackStream,
                    BASSFlag.BASS_MIXER_NORAMPIN | BASSFlag.BASS_STREAM_AUTOFREE);

                if (!added)
                {
                    GetError("Failed to add FLAC callback stream to mixer");
                    CleanupBassHandles();
                    return false;
                }

                Log($"StartFlacEncoder — DSP-feed: callbackStream={_callbackStream} ringCapacity={ringCapacity}");
            }
            else
            {
                bool added = BassMix.BASS_Mixer_StreamAddChannel(
                    _encoderMixer, _sourceChannel,
                    BASSFlag.BASS_MIXER_NORAMPIN);

                if (!added)
                {
                    GetError("Failed to add source channel to FLAC mixer");
                    CleanupBassHandles();
                    return false;
                }

                Log($"StartFlacEncoder — pull: sourceChannel={_sourceChannel} added to mixer");
            }

            _flacEncoder = new EncoderFLAC(_encoderMixer);
            _flacEncoder.InputFile = null;
            _flacEncoder.OutputFile = _encoderTempFilename;
            _flacEncoder.Force16Bit = BitDepth == 16;

            Log($"StartFlacEncoder — calling EncoderFLAC.Start: outputFile='{_flacEncoder.OutputFile}'");

            if (!_flacEncoder.Start(null, IntPtr.Zero, false))
            {
                _lastEncoderError = $"EncoderFLAC.Start failed: {Bass.BASS_ErrorGetCode()}";
                Log(_lastEncoderError);
                CleanupBassHandles();
                return false;
            }

            Log($"StartFlacEncoder — EncoderFLAC started, tempFile='{_encoderTempFilename}'");

            StartEncoderPump();

            return true;
        }

[FlacEncoder] StartRecording — recordChannel=-2147483640, title='Faye Day Hardcore', artist='DJ VorTechS'
[FlacEncoder] StartRecording — channel state=BASS_ACTIVE_PLAYING
[FlacEncoder] StartRecording — source info: freq=48000 chans=2 flags=BASS_MUSIC_FLOAT, BASS_MUSIC_DECODE
[FlacEncoder] StartFlacEncoder — outputFile='C:\Users\Stuart\Music\Audio Streamer Services\Faye Day Hardcore - DJ VorTechS - 09 Mar 2026 - 10-17-01.flac' freq=48000 chans=2
[FlacEncoder] StartFlacEncoder — output directory write check passed
[FlacEncoder] StartFlacEncoder — tempFile='C:\Users\Stuart\AppData\Local\Temp\rec_tmp.flac'
[FlacEncoder] StartFlacEncoder — availProbe=-1 useDspFeed=True
[FlacEncoder] StartFlacEncoder — mixer=-2147483639
[FlacEncoder] StartFlacEncoder — DSP-feed: callbackStream=-2147483638 ringCapacity=192000
[FlacEncoder] StartFlacEncoder — calling EncoderFLAC.Start: outputFile='C:\Users\Stuart\AppData\Local\Temp\rec_tmp.flac'
[FlacEncoder] EncoderFLAC.Start failed: BASS_ERROR_FILEOPEN

As you can see I've done everything I can to rule out an issue with filenames and paths, but the encoder appears to be returning the error BASS_ERROR_FILEOPEN. 

Are there any other potential causes of the encoder not being able to write the file other than paths/filenames?

Ian @ un4seen

I believe BASS.Net's EncoderFLAC class actually uses the external FLAC.EXE encoder rather than the BASSenc_FLAC add-on, and BASS_ERROR_FILEOPEN would indicate that it can't find FLAC.EXE. You should use the BassEnc_Flac.BASS_Encode_FLAC_StartFile function instead:

_flacEncoder = BassEnc_Flac.BASS_Encode_FLAC_StartFile(_encoderMixer, null, BASSEncode.BASS_ENCODE_FP_16BIT, _encoderTempFilename);

And then call BASS_Encode_Stop(_flacEncoder) when you're done.

VorTechS

Thanks Ian.... I got my wires crossed!

I hadn't appreciated that the Bass.NET encoder instance was reliant on the external EXE, and the moment I dropped flac.exe into place data started flowing!

I'll take a look at the full implementation via BassEnc_Flac route too, as that would negate the need for the EXE.

Thanks again!