Skip to content

Commit

Permalink
looper works, we have to resample audio
Browse files Browse the repository at this point in the history
before playing it
i finally get how digital audio playback works
  • Loading branch information
Shaji Khan committed Feb 23, 2024
1 parent 1668cfd commit 9008428
Showing 1 changed file with 157 additions and 0 deletions.
157 changes: 157 additions & 0 deletions app/src/main/java/com/shajikhan/ladspa/amprack/AudioDecoder.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import android.media.MediaCodec;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.ParcelFileDescriptor;
import android.util.Log;
Expand All @@ -12,9 +13,11 @@
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.HashMap;

public class AudioDecoder {
MainActivity mainActivity ;
Expand Down Expand Up @@ -47,6 +50,8 @@ float[] decode (Uri uri) throws IOException {
float [] decoded = new float[0];
int decodedIdx = 0;

MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();

MediaCodec codec;
ByteBuffer[] codecInputBuffers;
ByteBuffer[] codecOutputBuffers;
Expand All @@ -56,7 +61,26 @@ float[] decode (Uri uri) throws IOException {
openFileDescriptor(uri, "r");

FileDescriptor fileDescriptor = pfd.getFileDescriptor();
metadataRetriever.setDataSource(fileDescriptor);

HashMap <Integer, String> metadata = new HashMap();
int dataKeys [] = {
MediaMetadataRetriever.METADATA_KEY_MIMETYPE,
MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
MediaMetadataRetriever.METADATA_KEY_BITS_PER_SAMPLE,
MediaMetadataRetriever.METADATA_KEY_BITRATE,
MediaMetadataRetriever.METADATA_KEY_SAMPLERATE
} ;

for (int key: dataKeys) {
metadata.put(key, metadataRetriever.extractMetadata(key));
Log.d(TAG, "decode: metadata" +
String.format("%d: %s", key, metadataRetriever.extractMetadata(key)));
}

sampleRate = Integer.parseInt(metadata.get(MediaMetadataRetriever.METADATA_KEY_SAMPLERATE));
extractor.setDataSource(pfd.getFileDescriptor());
float scaleFactor = 48000 / sampleRate ;
MediaFormat format = extractor.getTrackFormat(0);
String mime = format.getString(MediaFormat.KEY_MIME);

Expand Down Expand Up @@ -144,6 +168,139 @@ float[] decode (Uri uri) throws IOException {
Log.d(TAG, "output format has changed to " + oformat);
// codec.stop();
// codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
// codec.start();
} else {
Log.d(TAG, "dequeueOutputBuffer returned " + res);
}
}
codec.stop();
codec.release();
return decoded;
}

float [] resample (Uri uri) throws IOException {
MediaExtractor extractor;
float [] decoded = new float[0];
int decodedIdx = 0;

MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever();

MediaCodec codec;
ByteBuffer[] codecInputBuffers;
ByteBuffer[] codecOutputBuffers;
extractor = new MediaExtractor();
ParcelFileDescriptor pfd =
mainActivity.getContentResolver().
openFileDescriptor(uri, "r");

FileDescriptor fileDescriptor = pfd.getFileDescriptor();
metadataRetriever.setDataSource(fileDescriptor);

HashMap <Integer, String> metadata = new HashMap();
int dataKeys [] = {
MediaMetadataRetriever.METADATA_KEY_MIMETYPE,
MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS,
MediaMetadataRetriever.METADATA_KEY_BITS_PER_SAMPLE,
MediaMetadataRetriever.METADATA_KEY_BITRATE,
MediaMetadataRetriever.METADATA_KEY_SAMPLERATE
} ;

for (int key: dataKeys) {
metadata.put(key, metadataRetriever.extractMetadata(key));
Log.d(TAG, "decode: metadata" +
String.format("%d: %s", key, metadataRetriever.extractMetadata(key)));
}

sampleRate = Integer.parseInt(metadata.get(MediaMetadataRetriever.METADATA_KEY_SAMPLERATE));
extractor.setDataSource(pfd.getFileDescriptor());
float scaleFactor = 48000 / sampleRate ;
MediaFormat format = extractor.getTrackFormat(0);
String mime = format.getString(MediaFormat.KEY_MIME);

Log.i(TAG, "decode: detected format " + mime);
codec = MediaCodec.createEncoderByType(mime);
format.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate);

codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
extractor.selectTrack(0);
// start decoding
final long kTimeOutUs = 5000;
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
boolean sawInputEOS = false;
boolean sawOutputEOS = false;
int noOutputCounter = 0;
boolean reconfigure = true ;
while (!sawOutputEOS && noOutputCounter < 50) {
noOutputCounter++;
if (!sawInputEOS) {
int inputBufIndex = codec.dequeueInputBuffer(kTimeOutUs);
if (inputBufIndex >= 0) {
ByteBuffer dstBuf = codecInputBuffers[inputBufIndex];
int sampleSize =
extractor.readSampleData(dstBuf, 0 /* offset */);
long presentationTimeUs = 0;
if (sampleSize < 0) {
Log.d(TAG, "saw input EOS.");
sawInputEOS = true;
sampleSize = 0;
} else {
presentationTimeUs = extractor.getSampleTime();
}
codec.queueInputBuffer(
inputBufIndex,
0 /* offset */,
sampleSize,
presentationTimeUs,
sawInputEOS ? MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
if (!sawInputEOS) {
extractor.advance();
}
}
}
int res = codec.dequeueOutputBuffer(info, kTimeOutUs);
if (res >= 0) {
//Log.d(TAG, "got frame, size " + info.size + "/" + info.presentationTimeUs);
if (info.size > 0) {
noOutputCounter = 0;
}

if (info.size > 0 && reconfigure) {
// once we've gotten some data out of the decoder, reconfigure it again
reconfigure = false;
extractor.seekTo(0, MediaExtractor.SEEK_TO_NEXT_SYNC);
sawInputEOS = false;
codec.stop();
codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
codec.start();
codecInputBuffers = codec.getInputBuffers();
codecOutputBuffers = codec.getOutputBuffers();
continue;
}

int outputBufIndex = res;
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
if (decodedIdx + (info.size / 2) >= decoded.length) {
decoded = Arrays.copyOf(decoded, decodedIdx + (info.size / 2));
}
for (int i = 0; i < info.size; i += 2) {
decoded[decodedIdx++] = (float) (buf.getShort(i) / 32768.0);
}
codec.releaseOutputBuffer(outputBufIndex, false /* render */);
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d(TAG, "saw output EOS.");
sawOutputEOS = true;
}
} else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
codecOutputBuffers = codec.getOutputBuffers();
Log.d(TAG, "output buffers have changed.");
} else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat oformat = codec.getOutputFormat();
Log.d(TAG, "output format has changed to " + oformat);
// codec.stop();
// codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
// codec.start();
} else {
Log.d(TAG, "dequeueOutputBuffer returned " + res);
Expand Down

0 comments on commit 9008428

Please sign in to comment.