jni - Lame encoded mp3 audio slowed down - Android -
i have been following this tutorial on using lame mp3 on android jni. recording seems working , getting output mp3 upon playback audio has been slowed down , pitched down.
i've tried put pertinent code below. guidance on why happening? in advance help.
edit: ok check imported raw data audacity , plays fine must issue @ encoding stage.
java class:
public class record extends activity implements onclicklistener { static { system.loadlibrary("mp3lame"); } private native void initencoder(int numchannels, int samplerate, int bitrate, int mode, int quality); private native void destroyencoder(); private native int encodefile(string sourcepath, string targetpath); private static final int recorder_bpp = 16; private static final string audio_recorder_file_ext_wav = ".wav"; private static final string audio_recorder_folder = "aberdeensoundsites"; private static final string audio_recorder_temp_file = "record_temp.raw"; private static final int[] recorder_samplerates = {44100, 22050, 11025, 8000}; private static final int recorder_channels = audioformat.channel_in_stereo; private static final int recorder_audio_encoding = audioformat.encoding_pcm_16bit; public static final int num_channels = 2; public static final int sample_rate = 44100; public static final int bitrate = 320; public static final int mode = 1; public static final int quality = 2; private short[] mbuffer; private file rawfile; private file encodedfile; private int samplerate; private string filename; private audiorecord recorder = null; private int buffersize = 0; private thread recordingthread = null; private boolean isrecording = false; @override public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.record); initencoder(num_channels, sample_rate, bitrate, mode, quality); stopbutton = (button) findviewbyid(r.id.stop_button); stopbutton.setonclicklistener(this); timer = (textview) findviewbyid(r.id.recording_time); buffersize = audiorecord.getminbuffersize(44100, recorder_channels, recorder_audio_encoding); } private void startrecording() { stopped = false; stopbutton.settext(r.string.stop_button_label); // set , start audio recording recorder = findaudiorecord(); recorder.startrecording(); isrecording = true; rawfile = getfile("raw"); mbuffer = new short[buffersize]; startbufferedwrite(rawfile); } private void stoprecording() { mhandler.removecallbacks(starttimer); stopped = true; if(recorder != null){ isrecording = false; recorder.stop(); recorder.release(); recorder = null; recordingthread = null; } encodedfile = getfile("mp3"); int result = encodefile(rawfile.getabsolutepath(), encodedfile.getabsolutepath()); if (result == 0) { toast.maketext(record.this, "encoded " + encodedfile.getname(), toast.length_short) .show(); } } private void startbufferedwrite(final file file) { new thread(new runnable() { @override public void run() { looper.prepare(); dataoutputstream output = null; try { output = new dataoutputstream(new bufferedoutputstream(new fileoutputstream(file))); while (isrecording) { int readsize = recorder.read(mbuffer, 0, mbuffer.length); (int = 0; < readsize; i++) { output.writeshort(mbuffer[i]); } } } catch (ioexception e) { toast.maketext(record.this, e.getmessage(), toast.length_short).show(); } { if (output != null) { try { output.flush(); } catch (ioexception e) { toast.maketext(record.this, e.getmessage(), toast.length_short).show(); } { try { output.close(); } catch (ioexception e) { toast.maketext(record.this, e.getmessage(), toast.length_short).show(); } } } } } }).start(); } private file getfile(final string suffix) { time time = new time(); time.settonow(); return new file(environment.getexternalstoragedirectory()+"/myappfolder", time.format("%y%m%d%h%m%s") + "." + suffix); } public audiorecord findaudiorecord() { (int rate : recorder_samplerates) { (short audioformat : new short[] { audioformat.encoding_pcm_16bit, audioformat.encoding_pcm_8bit }) { (short channelconfig : new short[] { audioformat.channel_in_stereo, audioformat.channel_in_mono }) { try { log.d("aberdeensoundsites", "attempting rate " + rate + "hz, bits: " + audioformat + ", channel: " + channelconfig); int buffersize = audiorecord.getminbuffersize(rate, channelconfig, audioformat); if (buffersize != audiorecord.error_bad_value) { // check if can instantiate , have success audiorecord recorder = new audiorecord(mediarecorder.audiosource.mic, rate, channelconfig, audioformat, buffersize); samplerate = rate; if (recorder.getstate() == audiorecord.state_initialized) return recorder; } } catch (exception e) { log.e("myapp", rate + "exception, keep trying.",e); } } } } log.e("myapp", "no settings worked :("); return null; }
c wrapper:
#include <stdio.h> #include <stdlib.h> #include <jni.h> #include <android/log.h> #include "libmp3lame/lame.h" #define log_tag "lame encoder" #define logd(format, args...) __android_log_print(android_log_debug, log_tag, format, ##args); #define buffer_size 8192 #define be_short(s) ((short) ((unsigned short) (s) << 8) | ((unsigned short) (s) >> 8)) lame_t lame; int read_samples(file *input_file, short *input) { int nb_read; nb_read = fread(input, 1, sizeof(short), input_file) / sizeof(short); int = 0; while (i < nb_read) { input[i] = be_short(input[i]); i++; } return nb_read; } void java_mypacakage_myapp_record_initencoder(jnienv *env, jobject jobj, jint in_num_channels, jint in_samplerate, jint in_brate, jint in_mode, jint in_quality) { lame = lame_init(); logd("init parameters:"); lame_set_num_channels(lame, in_num_channels); logd("number of channels: %d", in_num_channels); lame_set_in_samplerate(lame, in_samplerate); logd("sample rate: %d", in_samplerate); lame_set_brate(lame, in_brate); logd("bitrate: %d", in_brate); lame_set_mode(lame, in_mode); logd("mode: %d", in_mode); lame_set_quality(lame, in_quality); logd("quality: %d", in_quality); int res = lame_init_params(lame); logd("init returned: %d", res); } void java_mypacakage_myapp_record_destroyencoder( jnienv *env, jobject jobj) { int res = lame_close(lame); logd("deinit returned: %d", res); } void java_mypacakage_myapp_record_encodefile(jnienv *env, jobject jobj, jstring in_source_path, jstring in_target_path) { const char *source_path, *target_path; source_path = (*env)->getstringutfchars(env, in_source_path, null); target_path = (*env)->getstringutfchars(env, in_target_path, null); file *input_file, *output_file; input_file = fopen(source_path, "rb"); output_file = fopen(target_path, "wb"); short input[buffer_size]; char output[buffer_size]; int nb_read = 0; int nb_write = 0; int nb_total = 0; logd("encoding started"); while (nb_read = read_samples(input_file, input)) { nb_write = lame_encode_buffer(lame, input, input, nb_read, output, buffer_size); fwrite(output, nb_write, 1, output_file); nb_total += nb_write; } logd("encoded %d bytes", nb_total); nb_write = lame_encode_flush(lame, output, buffer_size); fwrite(output, nb_write, 1, output_file); logd("flushed %d bytes", nb_write); fclose(input_file); fclose(output_file); }
edit - ok out of interest downloaded apk tutorial provides phone , ran it. works fine. suggest problem less tutorial , more i've done. re-look on when have time available , see if can determine went wrong
you call initencoder 2 channels, , initialize audiorecord stereo , mono, wrapper.c can deal 1 channel:
nb_write = lame_encode_buffer(lame, input, input, nb_read, output, buffer_size);
the above codes require source audio mono 1 channel. if want support stereo, pay attention lame_encode_buffer method
int cdecl lame_encode_buffer ( lame_global_flags* gfp, /* global context handle */ const short int buffer_l [], /* pcm data left channel */ const short int buffer_r [], /* pcm data right channel */ const int nsamples, /* number of samples per channel */ unsigned char* mp3buf, /* pointer encoded mp3 stream */ const int mp3buf_size ); /* number of valid octets in stream */
Comments
Post a Comment