Print sample values to comma-separated text file

Hi all,

I’m trying to write an audio application to stream the audio samples from the input, and place them in a .txt file (comma-separated, for example). So for example, a single square wave would look like (0.00,0.00,0.00,1.00,1.00,1.00,0.00,0.00).

So far from rummaging through the forums, I’ve put this together:

MainComponent.h public variables:

class MainComponent   : public AudioAppComponent

{
public:
   File resourceFile = File::getCurrentWorkingDirectory().getChildFile ("file.txt");
   TemporaryFile tempFile;
   FileOutputStream output(TemporaryFile tempFile);

In the Cpp File:

in Prepare to Play:

void MainComponent::prepareToPlay ( **int** samplesPerBlockExpected, **double** sampleRate)
{
    if (! resourceFile.existsAsFile())
    {
        DBG ("File doesn't exist ...");
    }

    TemporaryFile tempFile (resourceFile);
    FileOutputStream output (tempFile.getFile());
    
    if (! output.openedOk())
    {
        DBG ("FileOutputStream didn't open correctly ...");
        // ... some other error handling
    }
}

and in the getNextAudioBlock:

void MainComponent::getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill)
{       auto* bufferL=bufferToFill.buffer->getWritePointer(0);
    
    for (int sample=0; sample<bufferToFill.numSamples;sample++){   
    
    FileOutputStream output(tempFile.getFile());
    output.setNewLineString("\n");
    std:String myString = std::to_string(bufferL[sample]);
    output.writeText(myString,false,false,nullptr);
    
    output.flush(); // (called explicitly to force an fsync on posix)
    
    if (output.getStatus().failed())
    {
        DBG ("An error occurred in the FileOutputStream");
        // ... some other error handling
    }
    
    bool success = tempFile.overwriteTargetFileWithTemporary();
}
}

I’ve been messing around with it quite a bit, and the best I could get was it to print a single float into the text (0.000). Any advice on what I’ve done wrong, and how to append the values one after the other separated by a comma would be very appreciated

Without reading the fuill code:
You must not call os functions in getNextAudioBlock(), which is called from the audio thread.
Especially bad are OS functions, that access the filesystem.

You will need a software buffer where you store the data you want to save, and an asynchronous writer, that writes from that buffer to keep it empty.

Also have a strategy, what shall happen if that buffer is full, because you cannot wait for the writer to finish writing.

Hi Daniel, thanks for your reply
So, if I understand correctly, you’re saying I should use getNextAudioBlock() only to store the input into a buffer. Then i can write from it. Do you have any suggestions on what class to use to implement the writer?

You need something like a ring buffer that has multiple buffer slots so it can deal with the lag or ahead buffer values.

The File IO in the audio thread is the main issue, place strings in memory (ring buffer), background thread read from buffer and write to disk, clear, rinse and repeat.

It is worse than that, a string is also an allocation. You need preallocated strings if you really want to fill the string inside getNextAudioBlock().
It would be much better to collect the information more machine friendly. Strings are for humans really, machines prefer numbers.

If you really need and want to go the string way, copy the raw samples on the audio thread to some kind of fifo and write them to a file on a dedicated thread.

I did something like this for a project were (non audio) sample buffers had to be written from a realtime thread to a custom file format. You can find the implementation here

There is a lot of stuff in this class, but maybe looking at appendSampleBuffer and MCVWriterThread will give you some inspiration on how this could be done

1 Like

True, I dumbed it down a bit. :slight_smile:

Thank you very much! As a beginner I appreciate the concrete material. I’ll start looking through your code :slight_smile: