We have now received the new Bela I mentioned previously, which came with the latest software already installed (I did another install to be sure). It seems that the old Bela we had been using was just being stubborn about updating, I will continue to investigate the issue.

I now seem to be having other issues. Currently I'm simply trying to load a mono audio file from disk, play it from the audio output and write it to disk using AudioWriter. However, using the script below, the resulting recording is a series of buzzing noises rather than the intended sine sweep.

/*
 ____  _____ _        _    
| __ )| ____| |      / \   
|  _ \|  _| | |     / _ \  
| |_) | |___| |___ / ___ \ 
|____/|_____|_____/_/   \_\

http://bela.io

*/

#include <Bela.h>
#include <cmath>
#include <libraries/AudioFile/AudioFile.h>
#include "MonoFilePlayer.h"
#include <libraries/Pipe/Pipe.h>
#include <libraries/sndfile/sndfile.h>

AudioFileWriter writer;

// Name of the sound file (in project folder)
std::string gFilename = "sine_sweep_10.wav";

// Object that handles playing sound from a buffer
MonoFilePlayer gPlayer;

int gAudioFramesPerAnalogFrame = 0;

const char* outPath = "./recording.wav";

unsigned int gAudioFrames;
unsigned int gAudioInChannels;
float gAudioSampleRate;

std::vector<float> outBuffer(512);

AuxiliaryTask writeTask;

void writeAudio(void *)
{
	writer.setSamples(outBuffer);
}

bool setup(BelaContext *context, void *userData)
{
	
	// check audio and digital have same no. frames
	if(context->audioFrames != context->digitalFrames) {
		rt_fprintf(stderr, "This example needs audio and digital running at the same rate.\n");
		return false;
	}
	
	// Load the audio file
	if(!gPlayer.setup(gFilename)) {
    	rt_printf("Error loading audio file '%s'\n", gFilename.c_str());
    	return false;
	}

	// Print some useful info
    rt_printf("Loaded the audio file '%s' with %d frames (%.1f seconds)\n", 
    			gFilename.c_str(), gPlayer.size(),
    			gPlayer.size() / context->audioSampleRate);

	
	// calculate no. audio frames per analog frame
	if(context->analogFrames)
		gAudioFramesPerAnalogFrame = context->audioFrames / context->analogFrames;
		
	gAudioSampleRate = context->audioSampleRate;
	gAudioFrames = context->audioFrames;
	gAudioInChannels = context->audioInChannels;

	writer.setup(outPath, 441000, gAudioInChannels, gAudioSampleRate);
	
	writeTask = Bela_createAuxiliaryTask(writeAudio, 50, "bela-write-audio");
	
	return true;
}

void render(BelaContext *context, void *userData)
{
    for(unsigned int n = 0; n < context->audioFrames; n++) {
    	
    	float out = 0.5*gPlayer.process();
    	
    	for(unsigned int i = 0; i < outBuffer.size(); i++){
    		
    		outBuffer[i] = out;
    		
    	}
		// Write sweep to speaker
    	audioWrite(context, n, 0, 0.02*out);
    	
    	//audioRead(context, n, 0);
    	//audioRead(context, n, 1);
    	
    	//writer.setSamples(outBuffer);
    	
    	Bela_scheduleAuxiliaryTask(writeTask);
    }
}

void cleanup(BelaContext *context, void *userData)
{
	
}

There is at least one issue with your code, that is that writer.setSamples() should be called from within the audio thread and not in a separate thread. I am not going to look into it with any more detail because I think you should be using the example below instead, which gets rid of MonoFilePlayer and uses instead AudioFileReader.

#include <Bela.h>
#include <libraries/AudioFile/AudioFile.h>

constexpr size_t kBufferSize = 32768;
AudioFileWriter writer;
AudioFileReader reader;
std::vector<float> readBuffer;
std::vector<float> writeBuffer;

bool setup(BelaContext* context, void*)
{
	readBuffer.resize(context->audioFrames);
	writeBuffer.resize(context->audioFrames);
	if(reader.setup("to-play.wav", kBufferSize))
	{
		fprintf(stderr, "Can't open input file\n");
		return false;
	}
	reader.setLoop(false);
	if(writer.setup("another.wav", kBufferSize, 1, context->audioSampleRate))
	{
		fprintf(stderr, "Can't open output file\n");
		return false;
	}
	return true;
}

void render(BelaContext* context, void*)
{
	// playback one file
	reader.getSamples(readBuffer);
	for(unsigned int n = 0; n < context->audioFrames; ++n)
	{
		float out = readBuffer[n];
		for(unsigned int c = 0; c < context->audioOutChannels; ++c)
			audioWrite(context, n, c, out);
		// copy the output to a buffer
		writeBuffer[n] = out;
	}
	// write the output buffer to file
	writer.setSamples(writeBuffer);
}

void cleanup(BelaContext* context, void*)
{}

Thanks for the help, seems that my problem was with monofileplayer and audiofile being used at the same time. Out of curiosity, is audiofile able to do stereo reading/writing as well?

    JoelBird is audiofile able to do stereo reading/writing as well?

    Sure. In that case the readBuffer and writeBuffer need to contain interleaved audio channels and writer.setup() should have 2 as the third parameter, which indicates the number of channels.

    I've managed to get AudioFileWriter to save a stereo file when simply reading from the disk, but when using the Bela's audio input the recording sounds heavily bitcrushed. I've included a link to a Google Drive folder with an example recording, as well as the relevant code from render.cpp.

    void render(BelaContext* context, void*)
    {
    	// playback one file
    	reader.getSamples(readBuffer);
    	for(unsigned int n = 0; n < context->audioFrames; ++n)
    	{
    		//float out = 0.9*readBuffer[n];
    		//for(unsigned int c = 0; c < context->audioOutChannels; ++c)
    			//audioWrite(context, n, c, 0.1*out);
    		// copy the output to a buffer
    		
    		float in = audioRead(context, n, 0);
    
    		writeBuffer[n] = in;
    	}
    	// write the output buffer to file
    	writer.setSamples(writeBuffer);
    }

    https://drive.google.com/drive/folders/1npW2p7XjeiDG7nblLllqcqk4n-3yq6Fq?usp=drive_link

      In the audio file you can see that you have bursts of 8 non-zero samples on each channels followed by 8 zero samples.
      This suggests that you are calling writeBuffer.setup() specifying 2 channels and writeBuffer.size() == 2 * context->audioFrames but as in the loop you only write to it once per frame, you predictably obtain this. If writing a stereo file, you should write two samples per frame to the buffer (one for left, one for right), e.g.: this would give you uncorrupted audio on the left channel and silence (zeros) on the right channel

      writeBuffer[n * 2] = in; // left channel of frame n
      writeBuffer[n * 2 + 1] = 0; // right channel of frame n

      But, again, I am just guessing because you didn't post your whole code.

      Apologies about the Google drive, thought I had it set to share fully by default. You are correct, I wasn't writing the interleaved samples properly. Thanks again for all the help!
      For completeness I'll share the full script below. I've included commented out expressions that allow for easier changing between mono and stereo sources, although I'm sure there's a way to detect what's being used and to switch automatically.

      #include <Bela.h>
      #include <libraries/AudioFile/AudioFile.h>
      
      constexpr size_t kBufferSize = 32768;
      AudioFileWriter writer;
      AudioFileReader reader;
      std::vector<float> readBuffer;
      std::vector<float> writeBuffer;
      
      const char* inPath = "./white_noise_dual_mono.wav";
      const char* outPath = "./recording.wav";
      
      int gInChannels;
      int gOutChannels;
      
      bool setup(BelaContext* context, void*)
      {
      	gInChannels = context->audioInChannels;
      	gOutChannels = gInChannels;
      	
      	// use this for mono
      	//readBuffer.resize(context->audioFrames);
      	
      	// use this for stereo
      	readBuffer.resize(context->audioFrames*2);
      	
      	writeBuffer.resize(context->audioFrames*2);
      	if(reader.setup(inPath, kBufferSize))
      	{
      		fprintf(stderr, "Can't open input file\n");
      		return false;
      	}
      	reader.setLoop(false);
      	if(writer.setup(outPath, kBufferSize, gOutChannels, context->audioSampleRate))
      	{
      		fprintf(stderr, "Can't open output file\n");
      		return false;
      	}
      	return true;
      }
      
      void render(BelaContext* context, void*)
      {
      	// playback one file
      	reader.getSamples(readBuffer);
      	for(unsigned int n = 0; n < context->audioFrames; ++n)
      	{
      		
      		// use this for playing mono files (alternatively use dual mono and use stereo version)
      		//float out = readBuffer[n];
      		
      		//audioWrite(context, n, 0, 0.1*out);
      		//audioWrite(context, n, 1, 0.1*out);
      		
      		// use this for playing stereo files
      		float outL = readBuffer[2*n];
      		float outR = readBuffer[2*n + 1];
      		
      		audioWrite(context, n, 0, 0.1*outL);
      		audioWrite(context, n, 1, 0.1*outR);
      		
      		// copy the output to a buffer
      		float inL = audioRead(context, n, 0);
      		float inR = audioRead(context, n, 1);
      
      		writeBuffer[2*n] = inL;
      		writeBuffer[2*n + 1] = inR;
      	}
      	// write the output buffer to file
      	writer.setSamples(writeBuffer);
      }
      
      void cleanup(BelaContext* context, void*)
      {
      	
      }

        JoelBird

        // use this for mono
        //readBuffer.resize(context->audioFrames);
        
        // use this for stereo
        readBuffer.resize(context->audioFrames*2);

        no need to hardcode these, simply have:

        	readBuffer.resize(context->audioFrames * gInChannels);
        	writeBuffer.resize(context->audioFrames * gOutChannels);

        I did try it like that at first, and it was having issues with mono files still. I assumed it was because context->audioInChannels (and therefore gInChannels) was taking from the Bela audio input rather than the number of channels in the source file.

          JoelBird I assumed it was because context->audioInChannels (and therefore gInChannels) was taking from the Bela audio input rather than the number of channels in the source file.

          context->audioInChannels does come from the number of physical audio inputs. Use reader.getChannels() to know the number of channels in the audio file (once you called setup() on it.
          I think what you are trying to do is reading an audio file and playing it through Bela's outputs and at the same time write Bela's audio inputs to a different file. The below should do that. Note that I removed the global variables because any information about the number of input/output channels is best obtained from writer/reader after they have been initialised.

          #include <Bela.h>
          #include <libraries/AudioFile/AudioFile.h>
          
          constexpr size_t kBufferSize = 32768;
          AudioFileWriter writer;
          AudioFileReader reader;
          std::vector<float> readBuffer;
          std::vector<float> writeBuffer;
          
          const char* inPath = "./white_noise_dual_mono.wav"";
          const char* outPath = "./recording.wav";
          
          bool setup(BelaContext* context, void*)
          {	
          	int outChannels = 2; // maximum number of channels in the `writer`  file
          	if(writer.setup(outPath, kBufferSize, outChannels, context->audioSampleRate))
          	{
          		fprintf(stderr, "Can't open output file\n");
          		return false;
          	}
          	if(reader.setup(inPath, kBufferSize))
          	{
          		fprintf(stderr, "Can't open input file\n");
          		return false;
          	}
          	readBuffer.resize(context->audioFrames * reader.getChannels());	
          	writeBuffer.resize(context->audioFrames * writer.getChannels());
          	reader.setLoop(false);
          	return true;
          }
          
          void render(BelaContext* context, void*)
          {
          	// playback one file
          	reader.getSamples(readBuffer);
          	for(unsigned int n = 0; n < context->audioFrames; ++n)
          	{
          		// play as many channels as possible from the audio file to the Bela output
          		for(unsigned int c = 0; c < context->audioOutChannels && c < reader.getChannels(); ++c)
          		{
          			float sample = readBuffer[reader.getChannels()  * n + c];
          			audioWrite(context, n, c, 0.1 * sample);
          		}
          		// write as many channels as possible from the Bela output to the audio file
          		for(unsigned int c = 0; c < context->audioInChannels && c < writer.getChannels(); ++c)
          		{
          			float sample = audioRead(context, n, c);
          			writeBuffer[writer.getChannels() * n + c] = sample;
          		}
          	}
          	// write the output buffer to file
          	writer.setSamples(writeBuffer);
          }
          
          void cleanup(BelaContext* context, void*)
          {}