jniemann66 / ReSampler

High quality command-line audio sample rate converter
GNU Lesser General Public License v2.1
159 stars 25 forks source link

opening RAW audio files #8

Closed mgood7123 closed 5 years ago

mgood7123 commented 5 years ago

what would the correct command line flags be to open a RAW audio file with a 16 bit Int PCM encoding and a sample rate of 44100 with stereo channel, as I cant seem to find any flags correcponding to those options, which are needed for libsnd to correctly open raw files

jniemann66 commented 5 years ago

Yes - I think I need to add a --raw option and probably a way to specify endianness, interleave and bit depth etc A little while back, I actually did some work on csv files, but now raw as yet. I'll see what I can do.

Also, I think it's about time I made a proper API for it, too, so that it can be used as a library as well as a commandline tool.

mgood7123 commented 5 years ago

ok, thanks ^-^

mgood7123 commented 5 years ago

btw do you have an android device (or maybe an emulator)?

mgood7123 commented 5 years ago

as if not I could try to help you verify if the program works as it should on Android, as im attempting to make a professional audio editor myself (even though I have little to no experience with digital audio I am trying to learn about it) https://github.com/mgood7123/libmedia (main API in https://github.com/mgood7123/libmedia/tree/master/app/src/main/java/libmedia )

jniemann66 commented 5 years ago

I have an Android phone, but it’s been a while since I did any Android Dev.

It might take me a while to set up the toolchain etc.

From: mgood7123 [mailto:notifications@github.com] Sent: Wednesday, July 3, 2019 10:03 PM To: jniemann66/ReSampler Cc: Judd Niemann; Comment Subject: Re: [jniemann66/ReSampler] opening RAW audio files (#8)

btw do you have an android device (or maybe an emulator)?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/jniemann66/ReSampler/issues/8?email_source=notifications&email_token=AEEXGHWRCFIRB4TLSTEIYT3P5SIRBA5CNFSM4H5EZVD2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZEHESQ#issuecomment-508064330 , or mute the thread https://github.com/notifications/unsubscribe-auth/AEEXGHXDTWGNLC7DCARIZN3P5SIRBANCNFSM4H5EZVDQ . https://github.com/notifications/beacon/AEEXGHWG2SHRJLK6X2A2CADP5SIRBA5CNFSM4H5EZVD2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZEHESQ.gif

jniemann66 commented 5 years ago

I intend to write the raw input command, but feeling a bit exhausted atm. (it's 10:41PM here and I've got work in the morning). Anyway I need to think it through a bit more - it needs to be something like --raw-input and it should take samplerate, bit format, num channels. endianness as arguments.

My code should then use this information and pass it on to libsndfile accordingly

mgood7123 commented 5 years ago

ok, could you add the ability to input and output in-memory files aswell? so for example, files could be read directly from archives and such (for example, android assets embedded in the APK, or ZiP files via a ZP reader, or object files in C/C++, ect) without needing to extract to disk, process, read output into memory, then remove the input and output files

mgood7123 commented 5 years ago

for example, something like this

int16_t * in = readfile(FILE);
int sampleRate = calculateSampleRate(in, 44100);
int16_t * out;

/*
out would probably need to be malloced to prevent users from needing to manually calculate the 
required sample size since the calculation itself would probably be complex depending on certain 
settings such as bit rate, channels, sample rate, and so on), not to say that using `trackSize / 
(bytespersample * ChannelCount);` is incorrect, more of, i am not sure if other factors could affect the 
total number of audio frames

however out could ALSO be implemented as a vector/array however the speed at which it can allocate 
and deallocate (that is, push and pop) depends on the implementation and is usually signifigantly slower 
than for example, manually allocating the array of a set size then directly filling each array index, for 
example, a 44100 buffer size, would only take 1 allocation to fill 44100 samples (or 1 second of audio), 
and would probably take about 10 ms, as apposed to pushing the data to the array 44100 times, which 
would probably take around 700ms, possibly more, as when testing this with my canvas::clear, i found 
that, for roughly 3 million indexes (1440*2960) pushing, vs setting directly, vs memset, took in respective 
order, 2 to 3 seconds average, 68 to 72 ms average, around or under 1 ms average
*/

ReSampler(in, out, ReSamplerSettings);
// do something with out, optionally keeping in aswell
free(out); // or `delete out;`
mgood7123 commented 5 years ago

do note however, that I am having a very difficult time trying to link in libsndfile cus Android Studio and cmake keep complaining about libsndfile/libsndfile.a: error adding symbols: File in wrong format

mgood7123 commented 5 years ago

this is the same on windows if your wondering (in that it cannot seem to open raw files either)

C:\Users\konek\StudioProjects\libmedia\app\src\main\assets>C:\Users\konek\StudioProjects\libmedia\app\src\main\java\libmedia\resampler\ReSampler\x64\Release\ReSampler.exe -i 00001313.raw
 -o 00001313_48000.raw -r 48000 -b 16
2.0.7 64-bit version
Input file: 00001313.raw
Output file: 00001313_48000.raw
Changing output bit format to 16
Error: Couldn't Open Input File (File contains data in an unknown format.)

C:\Users\konek\StudioProjects\libmedia\app\src\main\assets>
jniemann66 commented 5 years ago

I will get to this - I promise ! :-)

mgood7123 commented 5 years ago

ok, i think this is the only thing left lol :) im super excited ^-^

mgood7123 commented 5 years ago

ok, this can now successfully resample a 44100khz 16 bit int wav file to 48000khz 16 bit int raw audio data file

E/OboeAudio: Started conversion at 1.56253E+12 milliseconds
I/ReSampler: 2.0.7 64-bit version
I/ReSampler: Input file: /sdcard/ReSampler/00001313.wav
I/ReSampler: Output file: /data/user/0/media.player.pro/files/00001313_48000.raw
I/ReSampler: Changing output bit format to 16
I/ReSampler: Changing output file format to raw
I/ReSampler: input bit format: 16
I/ReSampler: source file channels: 2
I/ReSampler: input sample rate: 44100
    output sample rate: 48000
I/ReSampler: Scanning input file for peaks ...Done
    Peak input sample: 0.999969 (-0.000265 dBFS) at 0:0:1.259297
I/ReSampler: LPF transition frequency: 20045.45 Hz (90.91 %)
I/ReSampler: Conversion ratio: 1.088435 (160:147)
I/ReSampler: Stage: 1
    inputRate: 44100
    outputRate: 63000
    ft: 20045.454545
    stopFreq: 22050.000000
    transition width: 3.181818 %
    guarantee: 22050.000000
    Generated Filter Size: 2943
    Output Buffer Size: 46812
I/ReSampler: Stage: 2
    inputRate: 63000
    outputRate: 48000
    ft: 20045.454545
    stopFreq: 25950.000000
    transition width: 9.090909 %
    guarantee: 25950.000000
    Generated Filter Size: 2163
    Output Buffer Size: 35666
I/ReSampler: Command lines to do this conversion in discreet steps:
     -i /sdcard/ReSampler/00001313.wav -o /data/user/0/media.player.pro/files/00001313_48000-stage1.raw -r 63000 --lpf-cutoff 96.818182 --lpf-transition 3.181818 --maxStages 1
     -i /data/user/0/media.player.pro/files/00001313_48000-stage1.raw -o /data/user/0/media.player.pro/files/00001313_48000.raw -r 48000 --lpf-cutoff 90.909091 --lpf-transition 9.090909 --maxStages 1
I/ReSampler: Stage: 1
    inputRate: 44100
    outputRate: 63000
    ft: 20045.454545
    stopFreq: 22050.000000
    transition width: 3.181818 %
    guarantee: 22050.000000
    Generated Filter Size: 2943
    Output Buffer Size: 46812
I/ReSampler: Stage: 2
    inputRate: 63000
    outputRate: 48000
    ft: 20045.454545
    stopFreq: 25950.000000
    transition width: 9.090909 %
    guarantee: 25950.000000
    Generated Filter Size: 2163
    Output Buffer Size: 35666
I/ReSampler: Command lines to do this conversion in discreet steps:
     -i /sdcard/ReSampler/00001313.wav -o /data/user/0/media.player.pro/files/00001313_48000-stage1.raw -r 63000 --lpf-cutoff 96.818182 --lpf-transition 3.181818 --maxStages 1
     -i /data/user/0/media.player.pro/files/00001313_48000-stage1.raw -o /data/user/0/media.player.pro/files/00001313_48000.raw -r 48000 --lpf-cutoff 90.909091 --lpf-transition 9.090909 --maxStages 1
I/ReSampler: Writing Metadata
I/ReSampler: Converting (multi-stage, multi-threaded) ...
E/OboeAudio: Ended conversion at 1.56253E+12 milliseconds
E/OboeAudio: TIME took 10902.4 milliseconds
E/OboeAudio: /sdcard/ReSampler/00001313.wav file size: 4123400
E/OboeAudio: /data/user/0/media.player.pro/files/00001313_48000.raw file size: 4487020
D/OboeAudio: Opened backing track
D/OboeAudio: length in human time:                              23:369:895:833
D/OboeAudio: length in nanoseconds:                             2.33699E+10
D/OboeAudio: length in microseconds:                            2.33699E+07
D/OboeAudio: length in milliseconds:                            23369.9
D/OboeAudio: length in seconds:                                 23.3699
D/OboeAudio: length in minutes:                                 0.389498
D/OboeAudio: length in hours:                                   0.00649164
D/OboeAudio: bytes:                                             4487864
D/OboeAudio: frames:                                            1121755
D/OboeAudio: sample rate:                                       48000
D/OboeAudio: length of 1 frame at 48000 sample rate:
D/OboeAudio: Human Time:                                        20:833
D/OboeAudio: Nanoseconds:                                       833.333
D/OboeAudio: Microseconds:                                      20.8333
D/OboeAudio: Milliseconds:                                      0
D/OboeAudio: Seconds:                                           0
D/OboeAudio: Minutes:                                           0
D/OboeAudio: Hours:                                             0
// reads a entire file
size_t read__(char *file, char **p) {
    int fd;
    size_t len = 0;
    char *o = NULL;
    *p = NULL;
    if (!(fd = open(file, O_RDONLY)))
    {
        std::cerr << "open() failure" << std::endl;
        return 0;
    }
    len = static_cast<size_t>(lseek(fd, 0, SEEK_END));
    lseek(fd, 0, 0);
    if (!(o = static_cast<char *>(malloc(len)))) {
        std::cerr << "failure to malloc()" << std::endl;
    }
    if ((read(fd, o, len)) == -1) {
        std::cerr << "failure to read()" << std::endl;
    }
    int cl = close(fd);
    if (cl < 0) {
        std::cerr << "cannot close \"" << file << "\", returned " << cl << std::endl;
        return 0;
    }
    *p = o;
    return len;
}

SoundRecording * SoundRecording::loadFromAssets(AAssetManager *assetManager, const char *filename, int SampleRate, int mChannelCount) {

    // Load the backing track
    AAsset* asset = AAssetManager_open(assetManager, filename, AASSET_MODE_BUFFER);

    if (asset == nullptr){
        LOGE("Failed to open track, filename %s", filename);
        return nullptr;
    }

    // Get the length of the track (we assume it is stereo 48kHz)
    uint64_t trackSize = static_cast<uint64_t>(AAsset_getLength(asset));

    // Load it into memory
    const int16_t *audioBuffer = static_cast<const int16_t*>(AAsset_getBuffer(asset));
    if (audioBuffer == nullptr){
        LOGE("Could not get buffer for track");
        return nullptr;
    }
    const int actualSampleRate = 48000;
    const int actualChannelCount = 2;
    const char * infile = "/sdcard/ReSampler/00001313.wav";
    const char * outfile = static_cast<std::string>(TEMPDIR + "/00001313_48000.raw").c_str();
    extern int main(int argc, char * argv[]);
    const int argc = 12;
    const char *argv[argc];
    argv[0] = "ReSampler";
    argv[1] = "-i";
    argv[2] = infile;
    argv[3] = "-o";
    argv[4] = outfile;
    argv[5] = "-r";
    argv[6] = "48000";
    argv[7] = "-b";
    argv[8] = "16";
    argv[9] = "--showStages";
    argv[10] = "--mt";
    argv[11] = "--noTempFile";
    double s = now_ms();
    LOGE("Started conversion at %G milliseconds", s);
    main(argc, const_cast<char **>(argv));
    double e = now_ms();
    LOGE("Ended conversion at %G milliseconds", e);
    LOGE("TIME took %G milliseconds", e - s);

    // read the file into memory
    char * in = nullptr;
    size_t insize = 0;
    char * out = nullptr;
    size_t outsize = 0;
    insize = read__(const_cast<char *>(infile), &in);
    outsize = read__(const_cast<char *>(outfile), &out);

    LOGE("%s file size: %zu", infile, insize);
    LOGE("%s file size: %zu", outfile, outsize);

    const uint64_t totalFrames = outsize / (2 * actualChannelCount);
    WAVEFORMAUDIODATATOTALFRAMES = totalFrames;
    WAVEFORMAUDIODATA = reinterpret_cast<const int16_t *>(out);

    SoundRecordingAudioData * AudioData = new SoundRecordingAudioData(totalFrames, mChannelCount, SampleRate);
    AudioTime * allFrames = new AudioTime();
    allFrames->update(totalFrames, AudioData);
    LOGD("Opened backing track");
    LOGD("length in human time:                              %s", allFrames->format(true).c_str());
    LOGD("length in nanoseconds:                             %G", allFrames->nanosecondsTotal);
    LOGD("length in microseconds:                            %G", allFrames->microsecondsTotal);
    LOGD("length in milliseconds:                            %G", allFrames->millisecondsTotal);
    LOGD("length in seconds:                                 %G", allFrames->secondsTotal);
    LOGD("length in minutes:                                 %G", allFrames->minutesTotal);
    LOGD("length in hours:                                   %G", allFrames->hoursTotal);
    LOGD("bytes:                                             %ld", trackSize);
    LOGD("frames:                                            %ld", totalFrames);
    LOGD("sample rate:                                       %d", SampleRate);
    LOGD("length of 1 frame at %d sample rate:", SampleRate);
    LOGD("Human Time:                                        %s", AudioData->TimeTruncated);
    LOGD("Nanoseconds:                                       %G", AudioData->nanosecondsPerFrame);
    LOGD("Microseconds:                                      %G", AudioData->microsecondsPerFrame);
    LOGD("Milliseconds:                                      %G", AudioData->millisecondsPerFrame);
    LOGD("Seconds:                                           %G", AudioData->secondsPerFrame);
    LOGD("Minutes:                                           %G", AudioData->minutesPerFrame);
    LOGD("Hours:                                             %G", AudioData->hoursPerFrame);
    return new SoundRecording(reinterpret_cast<int16_t *>(out), AudioData);
}
mgood7123 commented 5 years ago

also It should be safe to remove the android/fallbacks directory

however add to the README:

when compiling on android, should `wrong file format` occur when linking libsndfile or fftw, please clean the build directory (`Build` > `Clean Project`) then build again
jniemann66 commented 5 years ago

ok - I got it working on Linux. I did a reasonable amount of testing but I don't have access to other platforms right now, so can only test on Linux.

you should now be able to open a raw file by specifying --raw-input <samplerate> <bits> [numchannels]

(if you omit numchannels it will assume mono input)

I added some documentation on this in the README

we may also need to add an endian-ness setting as well ... later on

mgood7123 commented 5 years ago

ok, ill try it out when I get a chance, been away/busy for a while

jniemann66 commented 5 years ago

ok, ill try it out when I get a chance, been away/busy for a while No worries - I know what it's like :-)

Just as update - I have since tested the raw conversion on some other platforms, and I also did some things like exchanging some raw files with Cool Edit Pro etc and can confirm that it works as expected in my testing (even with a-law and u-law etc).

(I will get my android dev environment set-up when I get some time ... )

jniemann66 commented 5 years ago

@mgood7123 I'm going to close this now, if that's ok

mgood7123 commented 5 years ago

ok

mgood7123 commented 5 years ago

ok, ill try it out when I get a chance, been away/busy for a while No worries - I know what it's like :-)

Just as update - I have since tested the raw conversion on some other platforms, and I also did some things like exchanging some raw files with Cool Edit Pro etc and can confirm that it works as expected in my testing (even with a-law and u-law etc). (I will get my android dev environment set-up when I get some time ... )

this works successfully on android