ReSampler icon indicating copy to clipboard operation
ReSampler copied to clipboard

memory buffer based file conversion

Open mgood7123 opened this issue 4 years ago • 3 comments

what are your thoughts about implementing memory based file conversion? (eg using memory buffers instead of physical/RAM-based filesystem files)

also perhaps a queue based conversion, based on memory buffers, something like this

// assume the user wants to convert then process the output file as it is being converted

char * waveFile;

extern size_t read__(char *file, char * *p); // reads an entire file

read__("someWaveFile.wav", &waveFile);

// Re->open_mem opens a memory file for processing as if it where a standard physical file

Re->open_mem(waveFile);

bool has_header = false;

// process header if output has one
// NOTE: if data is required in order for the header to be correctly written then do so first
// NOTE: the user implementation MUST be able to support this

// NOTE: if the user knows what data to expect in the header they could avoid reading it entirely

// in the event the user require the header and it is required in order for data to be processed

if (!Re->header_requires_all_data())
    if (Re->has_header()) {
        process_header(Re->get_header());
        has_header = true;
    }

// another way to obtain the header should it require data, could be to process all data before hand

// however this approach eliminates the real-time aspect since the data would be pre-converted
// and would produce lag/stuttering given sufficiently large data
// and converting the file twice would just waste time since it is already converted

// in the event the user require the header and it is required in order for data to be processed

if (Re->header_requires_all_data())
    // process all data before hand
    while (Re->has_samples()) Re->get_one_sample();
    // rewind memory file index back to start without erasing header information
    // and without erasing converted data
    Re->rewind_keep_header_keep_conversion();
    // obtain header
    if (Re->has_header()) {
        process_header(Re->get_header());
        has_header = true;
    }

// Re->has_samples returns true if there is data to convert, otherwise false for EOF or equivilant
while (Re->has_samples())
    // Re->get_one_sample converts and return one sample
    process_one_sample(Re->get_one_sample());

// in the event the user require the header and it is not required in order for data to be processed
if (!has_header)
    if (Re->has_header())
        process_header(Re->get_header());
/*    from http://www.mega-nerd.com/libsndfile/FAQ.html#Q017

Q17 : Can libsndfile read/write files from/to UNIX pipes?

Yes, libsndfile can read files from pipes. Unfortunately, the write case is much more complicated.

File formats like AIFF and WAV have information at the start of the file (the file header) which states the length of the file, the number of sample frames etc. This information must be filled in correctly when the file header is written, but this information is not reliably known until the file is closed. This means that libsndfile cannot write AIFF, WAV and many other file types to a pipe.

However, there is at least one file format (AU) which is specifically designed to be written to a pipe. Like AIFF and WAV, AU has a header with a sample frames field, but it is specifically allowable to set that frames field to 0x7FFFFFFF if the file length is not known when the header is written. The AU file format can also hold data in many of the standard formats (ie SF_FORMAT_PCM_16, SF_FORMAT_PCM_24, SF_FORMAT_FLOAT etc) as well as allowing data in both big and little endian format.

See also FAQ Q6. 

Q6 : What's the best format for storing temporary files?

When you want to store temporary data there are a number of requirements;

    A simple, easy to parse header.
    The format must provide the fastest possible read and write rates (ie avoid conversions and encoding/decoding).
    The file format must be reasonably common and playable by most players.
    Able to store data in either endian-ness. 

The format which best meets these requirements is AU, which allows data to be stored in any one of short, int, float and double (among others) formats.

For instance, if an application uses float data internally, its temporary files should use a format of (SF_ENDIAN_CPU | SF_FORMAT_AU | SF_FORMAT_FLOAT) which will store big endian float data in big endian CPUs and little endian float data on little endian CPUs. Reading and writing this format will not require any conversions or byte swapping regardless of the host CPU. 
*/

mgood7123 avatar Oct 21 '19 15:10 mgood7123

Found a very informative video related to this, may be useful for improving realtime decoding speed (eg for streamed resampling and playback)

CPU Performance vs. Real-Time Performance in Digital Audio Workstations (DAW) https://m.youtube.com/watch?v=GUsLLEkswzE

mgood7123 avatar Dec 10 '19 14:12 mgood7123

@mgood7123 yeah it's been on my to-do list for a while. Having said that, though, the performance bottleneck is the actual interpolation/decimation/convolution. I have tried reading larger blocks of data and didn't make a lot of difference to the speed, and reading the whole file is just extending the block size to it's logical conclusion. It turns out the file i/o is a fairly small percentage of the processing time.

As far as operating as a resampler as a library, this is where memory buffers make more sense than reading from a file. So I can see why you would want that.

I might be able to have a look at it over the Christmas break.

(Note: the clipping-protection mechanism writes the whole conversion to a temp file (as floating point) and then scales it down if it clipped.)

.

One thing I do want to do is enable live input from a pipe, but this is pretty much the opposite of processing the whole thing in memory, and instead using small blocks to reduce latency.

jniemann66 avatar Dec 14 '19 05:12 jniemann66

Interesting

mgood7123 avatar Dec 14 '19 06:12 mgood7123

Closing this, but noted for future reference.

jniemann66 avatar Jul 26 '23 14:07 jniemann66