Closed luismartimor closed 4 years ago
Thanks for the suggestion.
What difficulties are you encountering in loading a .wav into a stream? The RhythmGame
sample has examples in loading a mp3 to a stream if that could be of assistance.
A mixer sample sounds like a good idea, what exactly do you mean by two bus streams? For an example on mixing square waves, see MegaDrone
.
Thanks for the answer, atneya. Ok, I'm testing with RhythmGame, gonna try.
Two streams, I mean just two instruments audio files looped. Drum loop and a guitar riff, for example. And a mixer. Just to see how to stream and mix more than one audio file, like a very simple mixer. With the ability to start / stop any one of these loops.
It would be very helpful
Thanks for the suggestion, we are always looking for examples that are helpful to start out from.
Well... trying to replicate a simple audio bus from RhythmGame...
I think these samples are more complicated than should be, cause the main AudioStreamCallback class ( Game ) is very dependent on other classes ( AAsetDataSource, NDKExtractor, OpenGLFunctions, UtilityFunctions, and all linking with others ... ) complicating, specially for newbies in Android C++.
I think best sample code examples are the simplest and direct ones.
The RhythmGame uses compressed .mp3 files, extracted with AAssetDataSource::newFromCompressedAsset
, with FFMpegExtractor, NDKExtractor ...
To get better sound quality need to use .wav or .aiff files, any library to get these instead of mp3 ?
Need an example to get data from .wav / .aiff files to the Player in a direct clear way.
The RhythmGame uses compressed .mp3 files, extrated with AAssetDataSource::newFromCompressedAsset
, with FFMpegExtractor, NDKExtractor ...
To get better sound quality need to use .wav or .aiff files, any library to get these instead of mp3 ?
Need an example to get data from .wav / .aiff files to the Player in a direct clear way.
Oboe does not support sound file I/O. You could use libsndfile. http://www.mega-nerd.com/libsndfile/
Or you could adapt something like the JSyn WAV and AIFF file parsers. https://github.com/philburk/jsyn/tree/master/src/com/jsyn/util/soundfile
Oboe does not support sound file I/O. You could use libsndfile. http://www.mega-nerd.com/libsndfile/
Or you could adapt something like the JSyn WAV and AIFF file parsers. https://github.com/philburk/jsyn/tree/master/src/com/jsyn/util/soundfile
Thanks philburk! In c ? ups .. it's gonna be harder than i thought ... Just read a .wav file to the stream. Any example code ?
Most sound file I/O libraries will have example code for decoding and encoding lossless. Decoding files are generally a very finicky task that should be left to libraries.
Libsndfile, which is used in PortAudio is a good general purpose I/O library. An example of reading and writing a WAV file can be found here: https://github.com/erikd/libsndfile/blob/master/examples/sfprocess.c
Using the library in a C++ should be as simple as using an extern C
. I also believe libsndfile now has CMake support, we should make it easy to import into an existing NDK project.
Most sound file I/O libraries will have example code for decoding and encoding lossless. Decoding files are generally a very finicky task that should be left to libraries.
Libsndfile, which is used in PortAudio is a good general purpose I/O library. An example of reading and writing a WAV file can be found here: https://github.com/erikd/libsndfile/blob/master/examples/sfprocess.c
Using the library in a C++ should be as simple as using an
extern C
. I also believe libsndfile now has CMake support, we should make it easy to import into an existing NDK project.
How nice would be a sample example of it ... Many barriers to entry for developers not used to work with C++ on android
Oboe does not support sound file I/O. You could use libsndfile. http://www.mega-nerd.com/libsndfile/
Or you could adapt something like the JSyn WAV and AIFF file parsers. https://github.com/philburk/jsyn/tree/master/src/com/jsyn/util/soundfile
@dturner explains FFmpeg audio decoding here https://medium.com/@donturner/using-ffmpeg-for-faster-audio-decoding-967894e94e71
What is convenient to read .wav/aiff data in Oboe , libsndfile or FFmpeg ?
FFmpeg is for reading MP3 files. libsndfile is for WAV and AIFF
If you just have a few files then you could export the WAV file from Audacity as raw int16. Then you can just load that directly from the raw file into your app. Make sure the endianness matches.
you could try using https://github.com/jniemann66/ReSampler, I just got it working successfully on android a few hours ago https://github.com/jniemann66/ReSampler/issues/8#issuecomment-509023082
however it is an IMPORTANT note that Output file quality takes precedence over all other considerations, such as processing speed (although efforts to improve the latter will certainly be explored, they cannot be at the expense of the former)
"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);
}
"
Completed with DrumThumper app
I think we need more examples. I'm having difficulties in loading just a .wav into a stream. Would be nice to have a simple sample code for just a mixer with two bus streams, like Apple had with MixerHost.