Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Float samples #1221

Merged
merged 6 commits into from
Mar 17, 2021
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion samples/drumthumper/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ android {
// products. The current owner of Oboe sample apps on Google Play is Phil Burk, who
// publishes using the application Id prefix of "com.plausiblesoftware".
applicationId "com.plausiblesoftware.drumthumper"
minSdkVersion 26
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
Expand Down
3 changes: 1 addition & 2 deletions samples/iolib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ android {
compileSdkVersion 29
buildToolsVersion "29.0.1"


defaultConfig {
minSdkVersion 26
minSdkVersion 16
targetSdkVersion 29
versionCode 1
versionName "1.0"
Expand Down
1 change: 0 additions & 1 deletion samples/parselib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ android {
compileSdkVersion 29
buildToolsVersion "29.0.1"


defaultConfig {
minSdkVersion 16
targetSdkVersion 29
Expand Down
225 changes: 190 additions & 35 deletions samples/parselib/src/main/cpp/wav/WavStreamReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ namespace parselib {
WavStreamReader::WavStreamReader(InputStream *stream) {
mStream = stream;

mWavChunk = 0;
mFmtChunk = 0;
mDataChunk = 0;
mWavChunk = nullptr;
mFmtChunk = nullptr;
mDataChunk = nullptr;

mAudioDataStartPos = -1;
}
Expand Down Expand Up @@ -76,21 +76,21 @@ void WavStreamReader::parse() {
// __android_log_print(ANDROID_LOG_INFO, TAG, "[%c%c%c%c]",
// tagStr[0], tagStr[1], tagStr[2], tagStr[3]);

std::shared_ptr<WavChunkHeader> chunk = 0;
std::shared_ptr<WavChunkHeader> chunk = nullptr;
android-usb marked this conversation as resolved.
Show resolved Hide resolved
if (tag == WavRIFFChunkHeader::RIFFID_RIFF) {
chunk = mWavChunk = std::shared_ptr<WavRIFFChunkHeader>(new WavRIFFChunkHeader(tag));
chunk = mWavChunk = std::make_shared<WavRIFFChunkHeader>(WavRIFFChunkHeader(tag));
mWavChunk->read(mStream);
} else if (tag == WavFmtChunkHeader::RIFFID_FMT) {
chunk = mFmtChunk = std::shared_ptr<WavFmtChunkHeader>(new WavFmtChunkHeader(tag));
chunk = mFmtChunk = std::make_shared<WavFmtChunkHeader>(WavFmtChunkHeader(tag));
mFmtChunk->read(mStream);
} else if (tag == WavChunkHeader::RIFFID_DATA) {
chunk = mDataChunk = std::shared_ptr<WavChunkHeader>(new WavChunkHeader(tag));
chunk = mDataChunk = std::make_shared<WavChunkHeader>(WavChunkHeader(tag));
mDataChunk->read(mStream);
// We are now positioned at the start of the audio data.
mAudioDataStartPos = mStream->getPos();
mStream->advance(mDataChunk->mChunkSize);
} else {
chunk = std::shared_ptr<WavChunkHeader>(new WavChunkHeader(tag));
chunk = std::make_shared<WavChunkHeader>(WavChunkHeader(tag));
chunk->read(mStream);
mStream->advance(chunk->mChunkSize); // skip the body
}
Expand All @@ -110,48 +110,203 @@ void WavStreamReader::positionToAudio() {
}
}

int WavStreamReader::getDataFloat(float *buff, int numFrames) {
// __android_log_print(ANDROID_LOG_INFO, TAG, "getData(%d)", numFrames);
/**
* Read and convert samples in PCM8 format to float
*/
int WavStreamReader::getDataFloat_PCM8(float *buff, int numFrames) {
int numChans = mFmtChunk->mNumChannels;

if (mDataChunk == 0 || mFmtChunk == 0) {
return 0;
int buffOffset = 0;
int totalFramesRead = 0;

const static int SAMPLE_SIZE = sizeof(u_int8_t);
const static float SAMPLE_FULLSCALE = (float)0x7F;
android-usb marked this conversation as resolved.
Show resolved Hide resolved
const static int CONVERT_BUFFER_FRAMES = 128;
android-usb marked this conversation as resolved.
Show resolved Hide resolved

u_int8_t readBuff[CONVERT_BUFFER_FRAMES * numChans];
android-usb marked this conversation as resolved.
Show resolved Hide resolved
int framesLeft = numFrames;
while (framesLeft > 0) {
int framesThisRead = std::min(framesLeft, CONVERT_BUFFER_FRAMES);
//__android_log_print(ANDROID_LOG_INFO, TAG, "read(%d)", framesThisRead);
int numFramesRead =
mStream->read(readBuff, framesThisRead * SAMPLE_SIZE * numChans) /
(SAMPLE_SIZE * numChans);
totalFramesRead += numFramesRead;

// Convert & Scale
for (int offset = 0; offset < numFramesRead * numChans; offset++) {
// PCM8 is unsigned, so we need to make it signed before scaling/converting
buff[buffOffset++] = ((float) readBuff[offset] - SAMPLE_FULLSCALE)
/ (float) SAMPLE_FULLSCALE;
android-usb marked this conversation as resolved.
Show resolved Hide resolved
}

if (numFramesRead < framesThisRead) {
break; // none left
}

framesLeft -= framesThisRead;
}

return totalFramesRead;
}

/**
* Read and convert samples in PCM16 format to float
*/
int WavStreamReader::getDataFloat_PCM16(float *buff, int numFrames) {
int numChans = mFmtChunk->mNumChannels;

int buffOffset = 0;
int totalFramesRead = 0;

const static int SAMPLE_SIZE = sizeof(int16_t);
const static float SAMPLE_FULLSCALE = (float) 0x7FFF;
android-usb marked this conversation as resolved.
Show resolved Hide resolved
const static int CONVERT_BUFFER_FRAMES = 128;

int16_t readBuff[CONVERT_BUFFER_FRAMES * numChans];
int framesLeft = numFrames;
while (framesLeft > 0) {
int framesThisRead = std::min(framesLeft, 128);
//__android_log_print(ANDROID_LOG_INFO, TAG, "read(%d)", framesThisRead);
int numFramesRead =
mStream->read(readBuff, framesThisRead * SAMPLE_SIZE * numChans) /
(SAMPLE_SIZE * numChans);
totalFramesRead += numFramesRead;

// Convert & Scale
for (int offset = 0; offset < numFramesRead * numChans; offset++) {
buff[buffOffset++] = (float) readBuff[offset] / SAMPLE_FULLSCALE;
android-usb marked this conversation as resolved.
Show resolved Hide resolved
}

if (numFramesRead < framesThisRead) {
break; // none left
}

framesLeft -= framesThisRead;
}

return totalFramesRead;
}

/**
* Read and convert samples in PCM24 format to float
*/
int WavStreamReader::getDataFloat_PCM24(float *buff, int numFrames) {
int numChans = mFmtChunk->mNumChannels;
int numSamples = numFrames * numChans;

const static float SAMPLE_FULLSCALE = (float) 0x7FFFFFFF;

uint8_t buffer[3];
for(int sampleIndex = 0; sampleIndex < numSamples; sampleIndex++) {
mStream->read(buffer, 3);
int32_t sample = (buffer[0] << 8) | (buffer[1] << 16) | (buffer[2] << 24);
buff[sampleIndex] = (float)sample / SAMPLE_FULLSCALE;
}

return numFrames;
}

/**
* Read and convert samples in Float32 format to float
*/
int WavStreamReader::getDataFloat_Float32(float *buff, int numFrames) {
// Turns out that WAV Float32 is just Android floats
int numChans = mFmtChunk->mNumChannels;

return mStream->read(buff, numFrames * sizeof(float) * numChans) /
(sizeof(float) * numChans);
}

/**
* Read and convert samples in PCM32 format to float
*/
int WavStreamReader::getDataFloat_PCM32(float *buff, int numFrames) {
int numChans = mFmtChunk->mNumChannels;

int buffOffset = 0;
int totalFramesRead = 0;

const static int SAMPLE_SIZE = sizeof(int32_t);
const static float SAMPLE_FULLSCALE = (float) 0x7FFFFFFF;
const static int CONVERT_BUFFER_FRAMES = 128; // arbitrary

int32_t readBuff[CONVERT_BUFFER_FRAMES * numChans];
int framesLeft = numFrames;
while (framesLeft > 0) {
int framesThisRead = std::min(framesLeft, CONVERT_BUFFER_FRAMES);
//__android_log_print(ANDROID_LOG_INFO, TAG, "read(%d)", framesThisRead);
int numFramesRead =
mStream->read(readBuff, framesThisRead * SAMPLE_SIZE* numChans) /
(SAMPLE_SIZE * numChans);
totalFramesRead += numFramesRead;

// convert & Scale
for (int offset = 0; offset < numFramesRead * numChans; offset++) {
buff[buffOffset++] = (float) readBuff[offset] / SAMPLE_FULLSCALE;
}

// TODO - Manage other input formats
if (mFmtChunk->mSampleSize == 16) {
short *readBuff = new short[128 * numChans];
int framesLeft = numFrames;
while (framesLeft > 0) {
int framesThisRead = std::min(framesLeft, 128);
//__android_log_print(ANDROID_LOG_INFO, TAG, "read(%d)", framesThisRead);
int numFramesRead =
mStream->read(readBuff, framesThisRead * sizeof(short) * numChans) /
(sizeof(short) * numChans);
totalFramesRead += numFramesRead;

// convert
for (int offset = 0; offset < numFramesRead * numChans; offset++) {
buff[buffOffset++] = (float) readBuff[offset] / (float) 0x7FFF;
if (numFramesRead < framesThisRead) {
break; // none left
}

framesLeft -= framesThisRead;
}

return totalFramesRead;
}

int WavStreamReader::getDataFloat(float *buff, int numFrames) {
// __android_log_print(ANDROID_LOG_INFO, TAG, "getData(%d)", numFrames);

if (mDataChunk == nullptr || mFmtChunk == nullptr) {
return 0;
}

int numFramesRead = 0;
switch (mFmtChunk->mSampleSize) {
case 8:
numFramesRead = getDataFloat_PCM8(buff, numFrames);
break;

case 16:
numFramesRead = getDataFloat_PCM16(buff, numFrames);
break;

case 24:
if (mFmtChunk->mEncodingId == WavFmtChunkHeader::ENCODING_PCM) {
numFramesRead = getDataFloat_PCM24(buff, numFrames);
} else {
__android_log_print(ANDROID_LOG_INFO, TAG, "invalid encoding:%d mSampleSize:%d",
mFmtChunk->mEncodingId, mFmtChunk->mSampleSize);
}
break;

if (numFramesRead < framesThisRead) {
break; // none left
case 32:
if (mFmtChunk->mEncodingId == WavFmtChunkHeader::ENCODING_PCM) {
numFramesRead = getDataFloat_PCM32(buff, numFrames);
} else if (mFmtChunk->mEncodingId == WavFmtChunkHeader::ENCODING_IEEE_FLOAT) {
numFramesRead = getDataFloat_Float32(buff, numFrames);
} else {
__android_log_print(ANDROID_LOG_INFO, TAG, "invalid encoding:%d mSampleSize:%d",
mFmtChunk->mEncodingId, mFmtChunk->mSampleSize);
}
break;

framesLeft -= framesThisRead;
}
delete[] readBuff;
default:
__android_log_print(ANDROID_LOG_INFO, TAG, "invalid encoding:%d mSampleSize:%d",
mFmtChunk->mEncodingId, mFmtChunk->mSampleSize);
return ERR_INVALID_FORMAT;
}

// __android_log_print(ANDROID_LOG_INFO, TAG, " returns:%d", totalFramesRead);
return totalFramesRead;
// Zero out any unread frames
if (numFramesRead < numFrames) {
int numChannels = getNumChannels();
memset(buff + (numFramesRead * numChannels), 0,
(numFrames - numFramesRead) * mFmtChunk->mSampleSize/8 * numChannels);
android-usb marked this conversation as resolved.
Show resolved Hide resolved
}

return 0;
return numFramesRead;
}

} // namespace parselib
15 changes: 15 additions & 0 deletions samples/parselib/src/main/cpp/wav/WavStreamReader.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class WavStreamReader {
// Data access
void positionToAudio();

static constexpr int ERR_INVALID_FORMAT = -1;

int getDataFloat(float *buff, int numFrames);

// int getData16(short *buff, int numFramees);
Expand All @@ -66,6 +68,19 @@ class WavStreamReader {
long mAudioDataStartPos;

std::map<RiffID, std::shared_ptr<WavChunkHeader>> mChunkMap;

private:
/*
* Individual Format Readers/Converters
*/
int getDataFloat_PCM8(float *buff, int numFrames);

int getDataFloat_PCM16(float *buff, int numFrames);

int getDataFloat_PCM24(float *buff, int numFrames);

int getDataFloat_Float32(float *buff, int numFrames);
int getDataFloat_PCM32(float *buff, int numFrames);
};

} // namespace parselib
Expand Down