I have been trying to get a print of an Image but I have not been successful so far.The printer is a locally manufactured 2" thermal printer having a printing resolution of 8dots/mm, 384dots/line, 203 dpi. The printer is based of a board having the "NXP 2388 ARM v7 Microproc." having a Memory FLASH size of 512 KB, RAM: 128 KB & a Receive Buffer Size of 16KB.
I followed this question till now.
Problem: The image I tried printing is of 576x95 res.
The image got printed(with some error LED lighting up and debug buzzer noise :D) but the orientation of the image was vertical instead of getting horizontally printed; that too at the very left side of the page and the top part of the image was cut-off
Assuming here that I din't passed some of the flags(while making the "packet") compatible with the printer that I have.
I have not worked on bluetooth printing before so any help is appreciable :)
My Existing Main Activity:
public class MainActivity extends Activity
{
// will show the statuses
TextView myLabel;
// will enable user to enter any text to be printed
EditText myTextbox;
EditText devName;
public TableLayout tl2;
String devid;
String[] pName;
String[] LODQTY;
String[] rte;
String[] stk;
String[] oQty;
String[] oVal;
String[] fQty;
BitSet dots;
int mWidth;
int mHeight;
String mStatus;
String TAG = "TAG";
public String msg;
// android built in classes for bluetooth operations
BluetoothAdapter mBluetoothAdapter;
BluetoothSocket mmSocket;
BluetoothDevice mmDevice;
OutputStream mmOutputStream;
InputStream mmInputStream;
Thread workerThread;
byte[] readBuffer;
int readBufferPosition;
int counter;
volatile boolean stopWorker;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
devName = (EditText) findViewById(R.id.etdevice);
devName.setText("BTprinter0377");
String[] product_info = new String[6];
product_info[0] = "CPL400^10^1^0^4^0.4^0";
product_info[1] = "CPL400^10^1^0^4^0.4^0";
product_info[2] = "CPL400^10^1^0^4^0.4^0";
product_info[3] = "CPL400^10^1^0^4^0.4^0";
product_info[4] = "CPL400^10^1^0^4^0.4^0";
product_info[5] = "CPL400^10^1^0^4^0.4^0";
tl2 = (TableLayout) findViewById(R.id.dynSummary);
LayoutInflater inflater = getLayoutInflater();
for (int current = 0; current <= (product_info.length - 1); current++) {
final TableRow row = (TableRow)inflater.inflate(R.layout.table_summary_row, tl2 , false);
TextView tv1 = (TextView)row.findViewById(R.id.tvSkuName);
TextView tv2 = (TextView)row.findViewById(R.id.tvOrderQty);
TextView tv3 = (TextView)row.findViewById(R.id.tvFreeQty);
TextView tv4 = (TextView)row.findViewById(R.id.tvSampleQty);
TextView tv5 = (TextView)row.findViewById(R.id.tvTotalOrderKg);
TextView tv6 = (TextView)row.findViewById(R.id.tvTotalFreeKg);
TextView tv7 = (TextView)row.findViewById(R.id.tvTotalSampleKg);
StringTokenizer tokens = new StringTokenizer(String.valueOf(product_info[current]), "^");
//System.out.println("tokens.nextToken().trim()"+tokens.nextToken().trim());
tv1.setText(tokens.nextToken().trim());
tv2.setText(tokens.nextToken().trim());
tv3.setText(tokens.nextToken().trim());
tv4.setText(tokens.nextToken().trim());
tv5.setText(tokens.nextToken().trim());
tv6.setText(tokens.nextToken().trim());
tv7.setText(tokens.nextToken().trim());
tl2.addView(row);
}
try {
// we have three buttons for specific functions
Button openButton = (Button) findViewById(R.id.open);
Button sendButton = (Button) findViewById(R.id.send);
Button closeButton = (Button) findViewById(R.id.close);
myLabel = (TextView) findViewById(R.id.label);
// open bluetooth connection
openButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
devid = devName.getText().toString().trim();
try {
findBT();
openBT();
} catch (IOException ex) {
}
}
});
// send data typed by the user to be printed
sendButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
sendData();
} catch (IOException ex) {
}
}
});
// close bluetooth connection
closeButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
try {
closeBT();
} catch (IOException ex) {
}
}
});
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* This will find a bluetooth printer device
*/
void findBT() {
try {
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
myLabel.setText("No bluetooth adapter available");
}
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBluetooth = new Intent(
BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBluetooth, 0);
}
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter
.getBondedDevices();
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
System.out.println("device.getName(): "+device.getName().toString());
if (device.getName().equals("BTprinter0377")) {
mmDevice = device;
break;
}
}
}
myLabel.setText("Bluetooth Device Found");
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Tries to open a connection to the bluetooth printer device
*/
void openBT() throws IOException {
try {
// Standard SerialPortService ID
UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
mmSocket = mmDevice.createRfcommSocketToServiceRecord(uuid);
mmSocket.connect();
mmOutputStream = mmSocket.getOutputStream();
mmInputStream = mmSocket.getInputStream();
beginListenForData();
myLabel.setText("Bluetooth Opened");
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* After opening a connection to bluetooth printer device,
* we have to listen and check if a data were sent to be printed.
*/
void beginListenForData() {
try {
final Handler handler = new Handler();
// This is the ASCII code for a newline character
final byte delimiter = 10;
stopWorker = false;
readBufferPosition = 0;
readBuffer = new byte[1024];
workerThread = new Thread(new Runnable() {
public void run() {
while (!Thread.currentThread().isInterrupted()
&& !stopWorker) {
try {
int bytesAvailable = mmInputStream.available();
if (bytesAvailable > 0) {
byte[] packetBytes = new byte[bytesAvailable];
mmInputStream.read(packetBytes);
for (int i = 0; i < bytesAvailable; i++) {
byte b = packetBytes[i];
if (b == delimiter) {
byte[] encodedBytes = new byte[readBufferPosition];
System.arraycopy(readBuffer, 0,
encodedBytes, 0,
encodedBytes.length);
final String data = new String(
encodedBytes, "US-ASCII");
readBufferPosition = 0;
handler.post(new Runnable() {
public void run() {
myLabel.setText(data);
}
});
} else {
readBuffer[readBufferPosition++] = b;
}
}
}
} catch (IOException ex) {
stopWorker = true;
}
}
}
});
workerThread.start();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* This will send data to be printed by the bluetooth printer
*/
void sendData() throws IOException {
System.out.println("tl2.getChildCount(): "+tl2.getChildCount());
try {
print_image("/sdcard/tryimg.png");
String msg22;
msg22 = "\n";
msg22 += "PN Or Fr Sa TOKg TFKg TSKg";
msg22 += "\n";
//mmOutputStream.write(msg22.getBytes());
// tell the user data were sent
myLabel.setText("Data Sent");
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
/*
* Close the connection to bluetooth printer.
*/
void closeBT() throws IOException {
try {
stopWorker = true;
mmOutputStream.close();
mmInputStream.close();
mmSocket.close();
myLabel.setText("Bluetooth Closed");
} catch (NullPointerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
public String convertBitmap(Bitmap inputBitmap) {
mWidth = inputBitmap.getWidth();
mHeight = inputBitmap.getHeight();
convertArgbToGrayscale(inputBitmap, mWidth, mHeight);
mStatus = "ok";
return mStatus;
}
private void convertArgbToGrayscale(Bitmap bmpOriginal, int width,
int height) {
int pixel;
int k = 0;
int B = 0, G = 0, R = 0;
dots = new BitSet();
try {
for (int x = 0; x < height; x++) {
for (int y = 0; y < width; y++) {
// get one pixel color
pixel = bmpOriginal.getPixel(y, x);
// retrieve color of all channels
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
// take conversion up to one single value by calculating
// pixel intensity.
R = G = B = (int) (0.299 * R + 0.587 * G + 0.114 * B);
// set bit into bitset, by calculating the pixel's luma
if (R < 55) {
dots.set(k);//this is the bitset that i'm printing
}
k++;
}
}
} catch (Exception e) {
// TODO: handle exception
Log.e(TAG, e.toString());
}
}
private void print_image(String file) throws IOException {
File fl = new File(file);
if (fl.exists()) {
Bitmap bmp = BitmapFactory.decodeFile(file);
convertBitmap(bmp);
mmOutputStream.write(PrinterCommands.SET_LINE_SPACING_24);
int offset = 0;
while (offset < bmp.getHeight()) {
mmOutputStream.write(PrinterCommands.SELECT_BIT_IMAGE_MODE);
for (int x = 0; x < bmp.getWidth(); ++x) {
for (int k = 0; k < 3; ++k) {
byte slice = 0;
for (int b = 0; b < 8; ++b) {
int y = (((offset / 8) + k) * 8) + b;
int i = (y * bmp.getWidth()) + x;
boolean v = false;
if (i < dots.length()) {
v = dots.get(i);
}
slice |= (byte) ((v ? 1 : 0) << (7 - b));
}
mmOutputStream.write(slice);
}
}
offset += 24;
mmOutputStream.write(PrinterCommands.FEED_LINE);
mmOutputStream.write(PrinterCommands.FEED_LINE);
mmOutputStream.write(PrinterCommands.FEED_LINE);
mmOutputStream.write(PrinterCommands.FEED_LINE);
mmOutputStream.write(PrinterCommands.FEED_LINE);
mmOutputStream.write(PrinterCommands.FEED_LINE);
}
mmOutputStream.write(PrinterCommands.SET_LINE_SPACING_30);
} else {
Toast.makeText(this, "file doesn't exists", Toast.LENGTH_SHORT).show();
}
}
}
The PrinterCommands Class:
public class PrinterCommands {
public static final byte[] INIT = {27, 64};
public static byte[] FEED_LINE = {10};
public static byte[] SELECT_FONT_A = {27, 33, 0};
public static byte[] SET_BAR_CODE_HEIGHT = {29, 104, 100};
public static byte[] PRINT_BAR_CODE_1 = {29, 107, 2};
public static byte[] SEND_NULL_BYTE = {0x00};
public static byte[] SELECT_PRINT_SHEET = {0x1B, 0x63, 0x30, 0x02};
public static byte[] FEED_PAPER_AND_CUT = {0x1D, 0x56, 66, 0x00};
public static byte[] SELECT_CYRILLIC_CHARACTER_CODE_TABLE = {0x1B, 0x74, 0x11};
public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 33, (byte) 255, 3};
//public static byte[] SELECT_BIT_IMAGE_MODE = {0x1B, 0x2A, 0x64, 0x63, 48, (byte) 255};
public static byte[] SET_LINE_SPACING_24 = {0x1B, 0x33, 24};
public static byte[] SET_LINE_SPACING_30 = {0x1B, 0x33, 30};
public static byte[] TRANSMIT_DLE_PRINTER_STATUS = {0x10, 0x04, 0x01};
public static byte[] TRANSMIT_DLE_OFFLINE_PRINTER_STATUS = {0x10, 0x04, 0x02};
public static byte[] TRANSMIT_DLE_ERROR_STATUS = {0x10, 0x04, 0x03};
public static byte[] TRANSMIT_DLE_ROLL_PAPER_SENSOR_STATUS = {0x10, 0x04, 0x04};
}
As mentioned in the dev manual of the printer(pdf):
Bit Map Image Print
1. Select the image either from PC or from mobile's SD card.
2. Convert the image into monochrome bmp.
3. Resize the image to fit into the printer paper area if it is exceeding
4. Now read the processed image through fileinputstream and save it into byte array.
5. Make the packet of image and then send it to printer over outputstream.
The required packet structure:
The packet fields chart:
Alignment table & other info:
private byte[] printbyte = {(byte)0x1B,(byte)0x2A,(byte)0x6F,(byte)0x63}
File file = new File(Environment.getExternalStorageDirectory + File.seprator()+"file_name");
FileInputStream fin = new FileInputStream(file);
byte imageContent[] = new byte[(int)file.length()];
fin.read(imageContent);
byte [] width = hexToBuffer(Integer.toHexString(your_width));
byte [] height = hexToBuffer(Integer.toHexString(your_height));
byte[] imageToPrint = new byte[printbyte.lenght()+imageContent.lenght()+width.lenght()+height.lenght()];
System.arraycopy(imagetoprint,0,printbyte,0,printbyte.lenght());
System.arraycopy(imagetoprint,printbyte.lenght(),width ,0,width.lenght());
System.arraycopy(imagetoprint,width.lenght(),height,0,height.lenght());
System.arraycopy(imagetoprint,height.lenght(),imageContent,0,imageContent.lenght());
mmOutputStream.write(imagetoprint);
Hex to Buffer method -
public static byte[] hexToBuffer(String hexString)
throws NumberFormatException {
int length = hexString.length();
byte[] buffer = new byte[(length + 1) / 2];
boolean evenByte = true;
byte nextByte = 0;
int bufferOffset = 0;
if ((length % 2) == 1) {
evenByte = false;
}
for (int i = 0; i < length; i++) {
char c = hexString.charAt(i);
int nibble; // A "nibble" is 4 bits: a decimal 0..15
if ((c >= '0') && (c <= '9')) {
nibble = c - '0';
} else if ((c >= 'A') && (c <= 'F')) {
nibble = c - 'A' + 0x0A;
} else if ((c >= 'a') && (c <= 'f')) {
nibble = c - 'a' + 0x0A;
} else {
throw new NumberFormatException("Invalid hex digit '" + c +
"'.");
}
if (evenByte) {
nextByte = (byte) (nibble << 4);
} else {
nextByte += (byte) nibble;
buffer[bufferOffset++] = nextByte;
}
evenByte = !evenByte;
}
return buffer;
}
I have a thermal printer with bluetooth and Usb connection, if your printer support ESC/POS command search for its commands on internet,
for print raster image you should send this:
[Name] Print raster bit image
[Format] ASCII GS v 0 m xL xH yL yH d1...dk
Hex 1D 76 30 m xL xH yL yH d1...dk
Decimal 29 118 48 m xL xH yL yH d1...dk
[Range] 0£ m£ 3, 48£ m £ 51
0£ xL£ 255
0£ xH£ 255
0£ yL£ 255
0£ d£ 255
k=(xL+ xH*256)*(yL+yH*256)
Follow your printer guidelines, it is may be different from others.
Related
The code below records, plays, and "decodes" a wav file. When I graph the byte array from the file, it looks like this:
The recording is of me saying "test", which should look like this:
Does anyone know why the graph of the byte array from the wav file does not look like real audiodata?
Here is the code for the entire activity:
package com.example.wesle.noisemachine;
import android.content.Intent;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Environment;
import android.widget.Toast;
import com.jjoe64.graphview.GraphView;
import com.jjoe64.graphview.series.DataPoint;
import com.jjoe64.graphview.series.LineGraphSeries;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.*;
public class ReceiveScreen extends AppCompatActivity {
private Button buttonStart, buttonStop, buttonDecode, buttonPlay;
private String filePath;
private static final int RECORDER_BPP = 16;
private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav";
private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder";
private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw";
private static final int RECORDER_SAMPLERATE = 44100;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
short[] audioData;
private AudioRecord recorder = null;
private int bufferSize = 0;
private Thread recordingThread = null;
private boolean isRecording = false;
Complex[] fftTempArray;
Complex[] fftArray;
int[] bufferData;
int bytesRecorded;
LineGraphSeries<DataPoint> series;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_receive_screen);
filePath = getFilename();
final File wavfile = new File(filePath);
buttonStart = (Button) findViewById(R.id.buttonStart);
buttonStop = (Button) findViewById(R.id.buttonStop);
buttonPlay = (Button) findViewById(R.id.buttonPlay);
buttonDecode = (Button) findViewById(R.id.buttonDecode);
buttonStop.setEnabled(false);
buttonDecode.setEnabled(false);
buttonPlay.setEnabled(false);
bufferSize = AudioRecord.getMinBufferSize
(RECORDER_SAMPLERATE,RECORDER_CHANNELS,RECORDER_AUDIO_ENCODING)*3;
audioData = new short [bufferSize];
buttonStart.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
buttonStart.setEnabled(false);
buttonDecode.setEnabled(false);
buttonPlay.setEnabled(false);
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE,
RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING,
bufferSize);
int i = recorder.getState();
if (i==1)
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
#Override
public void run() {
writeAudioDataToFile();
}
}, "AudioRecorder Thread");
recordingThread.start();
buttonStop.setEnabled(true);
Toast.makeText(getApplicationContext(), "Recording started", Toast.LENGTH_LONG).show();
}
});
buttonStop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
buttonStop.setEnabled(false);
if (null != recorder){
isRecording = false;
int i = recorder.getState();
if (i==1)
recorder.stop();
recorder.release();
recorder = null;
recordingThread = null;
}
copyWaveFile(getTempFilename(),filePath);
deleteTempFile();
Toast.makeText(getApplicationContext(), "Recording Completed", Toast.LENGTH_LONG).show();
buttonStart.setEnabled(true);
buttonPlay.setEnabled(true);
buttonDecode.setEnabled(true);
}
});
buttonPlay.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
buttonStart.setEnabled(false);
buttonDecode.setEnabled(false);
buttonPlay.setEnabled(false);
Toast.makeText(getApplicationContext(), "Recording Playing", Toast.LENGTH_LONG).show();
Uri myUri1 = Uri.fromFile(wavfile);
final MediaPlayer mPlayer = new MediaPlayer();
mPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
try {
mPlayer.setDataSource(getApplicationContext(), myUri1);
} catch (IllegalArgumentException e) {
Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (SecurityException e) {
Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
e.printStackTrace();
}
try {
mPlayer.prepare();
} catch (IllegalStateException e) {
Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "You might not set the URI correctly!", Toast.LENGTH_LONG).show();
}
mPlayer.start();
buttonStart.setEnabled(true);
buttonDecode.setEnabled(true);
buttonPlay.setEnabled(true);
}
});
buttonDecode.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
buttonStart.setEnabled(false);
buttonDecode.setEnabled(false);
buttonPlay.setEnabled(false);
GraphView thegraph = (GraphView) findViewById(R.id.thegraph);
series = new LineGraphSeries<DataPoint>();
double x,y;
x = 0;
try {
ByteArrayOutputStream outt = new ByteArrayOutputStream();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(wavfile));
int read;
byte[] buff = new byte[1024];
while ((read = in.read(buff)) > 0)
{
outt.write(buff, 0, read);
}
outt.flush();
byte[] audioBytes = outt.toByteArray();
//int[][] graphData = getUnscaledAmplitude(audioBytes, 1);
for(int i = 0; i < audioBytes.length;i++){
//System.out.println(audioBytes[i]);
byte curByte = audioBytes[i];
//int curByte = graphData[0][i];
y = (curByte);
series.appendData(new DataPoint(x,y), true, audioBytes.length);
x = x + 1;
//x = x + (1 / RECORDER_SAMPLERATE);
}
thegraph.addSeries(series);
} catch (IOException e) {
e.printStackTrace();
}
buttonStart.setEnabled(true);
buttonDecode.setEnabled(true);
buttonPlay.setEnabled(true);
}
});
//Code for the back button
Button backbuttonR = (Button) findViewById(R.id.backbuttonR);
backbuttonR.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(ReceiveScreen.this, MainActivity.class));
}
});
}
private String getFilename(){
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath,AUDIO_RECORDER_FOLDER);
System.out.println(file.getAbsolutePath() + "/" + System.currentTimeMillis() + AUDIO_RECORDER_FILE_EXT_WAV);
if (!file.exists()) {
file.mkdirs();
}
return (file.getAbsolutePath() + "/" + System.currentTimeMillis() + AUDIO_RECORDER_FILE_EXT_WAV);
}
private String getTempFilename() {
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath,AUDIO_RECORDER_FOLDER);
if (!file.exists()) {
file.mkdirs();
}
File tempFile = new File(filepath,AUDIO_RECORDER_TEMP_FILE);
if (tempFile.exists())
tempFile.delete();
return (file.getAbsolutePath() + "/" + AUDIO_RECORDER_TEMP_FILE);
}
private void writeAudioDataToFile() {
byte data[] = new byte[bufferSize];
String filename = getTempFilename();
FileOutputStream os = null;
try {
os = new FileOutputStream(filename);
} catch (FileNotFoundException e) {
//TODO Auto-generated catch block
e.printStackTrace();
}
int read = 0;
if (null != os) {
while(isRecording) {
read = recorder.read(data, 0, bufferSize);
if (read > 0){
}
if (AudioRecord.ERROR_INVALID_OPERATION != read) {
try {
os.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void deleteTempFile() {
File file = new File(getTempFilename());
file.delete();
}
private void copyWaveFile(String inFilename,String outFilename){
FileInputStream in = null;
FileOutputStream out = null;
long totalAudioLen = 0;
long totalDataLen = totalAudioLen + 36;
long longSampleRate = RECORDER_SAMPLERATE;
int channels = 2;
long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels/8;
byte[] data = new byte[bufferSize];
try {
in = new FileInputStream(inFilename);
out = new FileOutputStream(outFilename);
totalAudioLen = in.getChannel().size();
totalDataLen = totalAudioLen + 36;
System.out.println("File size: " + totalDataLen);
WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
while(in.read(data) != -1) {
out.write(data);
}
in.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void WriteWaveFileHeader(
FileOutputStream out, long totalAudioLen,
long totalDataLen, long longSampleRate, int channels,
long byteRate) throws IOException
{
byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (byte) channels;
header[23] = 0;
header[24] = (byte) (longSampleRate & 0xff);
header[25] = (byte) ((longSampleRate >> 8) & 0xff);
header[26] = (byte) ((longSampleRate >> 16) & 0xff);
header[27] = (byte) ((longSampleRate >> 24) & 0xff);
header[28] = (byte) (byteRate & 0xff);
header[29] = (byte) ((byteRate >> 8) & 0xff);
header[30] = (byte) ((byteRate >> 16) & 0xff);
header[31] = (byte) ((byteRate >> 24) & 0xff);
header[32] = (byte) (2 * 16 / 8); // block align
header[33] = 0;
header[34] = RECORDER_BPP; // bits per sample
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte) (totalAudioLen & 0xff);
header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
out.write(header, 0, 44);
}
public static final class Complex {
// The number stored is x+I*y.
final private double x, y;
// I don't want to allow anyone to access these numbers so I've labeled
// them private.
/** Construct a point from real and imaginary parts. */
public Complex(double real_part, double imaginary_part) {
x=real_part;
y=imaginary_part;
}
/** Construct a real number. */
public Complex(double real_part) {
x=real_part;
y=0;
}
// A static constructor.
/** Construct a complex number from the given polar coordinates. */
public static Complex fromPolar(double r, double theta) {
return new Complex(r*Math.cos(theta), r*Math.sin(theta));
}
// Basic operations on Complex numbers.
/** Return the real part. */
public double re(){
return x;
}
/** Return the imaginary part. */
public double im(){
return y;
}
/** Return the complex conjugate */
public Complex conj() {
return new Complex(x,-y);
}
/** Return the square of the absolute value. */
public double absSquared() {
return x*x+y*y;
}
/** Return the absolute value. */
public double abs() {
// The java.lang.Math package contains many useful mathematical functions,
// including the square root function.
return Math.sqrt(absSquared());
}
// ARITHMETIC
/** Add a complex number to this one.
*
* #param z The complex number to be added.
* #return A new complex number which is the sum.
*/
public Complex add(Complex z) {
return new Complex(x+z.x, y+z.y);
}
/** Subtract a complex number from this one.
*
* #param z The complex number to be subtracted.
* #return A new complex number which is the sum.
*/
public Complex minus(Complex z) {
return new Complex(x-z.x, y-z.y);
}
/** Negate this complex number.
*
* #return The negation.
*/
public Complex neg() {
return new Complex(-x, -y);
}
/** Compute the product of two complex numbers
*
* #param z The complex number to be multiplied.
* #return A new complex number which is the product.
*/
public Complex mult(Complex z) {
return new Complex(x*z.x-y*z.y, x*z.y+z.x*y);
}
/** Divide this complex number by a real number.
*
* #param q The number to divide by.
* #return A new complex number representing the quotient.
*/
public Complex div(double q) {
return new Complex(x/q,y/q);
}
/** Return the multiplicative inverse. */
public Complex inv() {
// find the square of the absolute value of this complex number.
double abs_squared=absSquared();
return new Complex(x/abs_squared, -y/abs_squared);
}
/** Compute the quotient of two complex numbers.
*
* #param z The complex number to divide this one by.
* #return A new complex number which is the quotient.
*/
public Complex div(Complex z) {
return mult(z.inv());
}
/** Return the complex exponential of this complex number. */
public Complex exp() {
return new Complex(Math.exp(x)*Math.cos(y),Math.exp(x)*Math.sin(y));
}
// FUNCTIONS WHICH KEEP JAVA HAPPY:
/** Returns this point as a string.
* The main purpose of this function is for printing the string out,
* so we return a string in a (fairly) human readable format.
*/
// The _optional_ override directive "#Override" below just says we are
// overriding a function defined in a parent class. In this case, the
// parent is java.lang.Object. All classes in Java have the Object class
// as a superclass.
#Override
public String toString() {
// Comments:
// 1) "" represents the empty string.
// 2) If you add something to a string, it converts the thing you
// are adding to a string, and then concatentates it with the string.
// We do some voodoo to make sure the number is displayed reasonably.
if (y==0) {
return ""+x;
}
if (y>0) {
return ""+x+"+"+y+"*I";
}
// otherwise y<0.
return ""+x+"-"+(-y)+"*I";
}
/** Return true if the object is a complex number which is equal to this complex number. */
#Override
public boolean equals(Object obj) {
// Return false if the object is null
if (obj == null) {
return false;
}
// Return false if the object is not a Complex number
if (!(obj instanceof Complex)) {
return false;
}
// Now the object must be a Complex number, so we can convert it to a
// Complex number.
Complex other = (Complex) obj;
// If the x-coordinates are not equal, then return false.
if (x != other.x) {
return false;
}
// If the y-coordinates are not equal, then return false.
if (y != other.y) {
return false;
}
// Both parts are equal, so return true.
return true;
}
#Override
public int hashCode() {
int hash = 3;
hash = 83 * hash + (int) (Double.doubleToLongBits(this.x) ^ (Double.doubleToLongBits(this.x) >>> 32));
hash = 83 * hash + (int) (Double.doubleToLongBits(this.y) ^ (Double.doubleToLongBits(this.y) >>> 32));
return hash;
}
}
public int[][] getUnscaledAmplitude(byte[] eightBitByteArray, int nbChannels)
{
int[][] toReturn = new int[nbChannels][eightBitByteArray.length / (2 * nbChannels)];
int index = 0;
for (int audioByte = 0; audioByte < eightBitByteArray.length;)
{
for (int channel = 0; channel < nbChannels; channel++)
{
// Do the byte to sample conversion.
int low = (int) eightBitByteArray[audioByte];
audioByte++;
int high = (int) eightBitByteArray[audioByte];
audioByte++;
int sample = (high << 8) + (low & 0x00ff);
toReturn[channel][index] = sample;
if (audioByte == 0) {
System.out.println("CHANNEL COUNT");
}
}
index++;
}
return toReturn;
}
}
If this is 16-bit audio then every other byte will be the least-significant data. Plotting these bytes will make it look very noisy (as you have above).
Think of it like this, in a phone book, people's names are ordered by LastName, FirstName. This is similar to how the two bytes are ordered for 16-bit audio. Let's say the names are:
Anders, Zoey
Anderson, Sally
Andrews, Craig
If you were to "plot" only the last names, they would have a very smooth progression from Anders to Anderson to Andrews. However, if you also included the first names in your plot, it would jump all around from "Anders" to "Zoey" then back down to "Anderson" then up to "Sally", and so on.
Because, seems, You read it from beginning and does not take into account .wav file header. You should read header, then read data according to header specifications, like in this or that or many other examples.
How do I implement an IIR bandpass filter in my current android code? I have an android app which could record audio (frequency actually) and save it in a .wav file.
I have managed to find a IIR Filter Library online but I am not sure how to implement it into my code.
https://github.com/ddf/Minim/blob/master/src/ddf/minim/effects/BandPass.java
https://github.com/DASAR/Minim-Android/blob/master/src/ddf/minim/effects/IIRFilter.java
I am supposed to add the 18k-20k bandpass filter to the code before outputting the received sound signal into a .wav file.
My current code
package com.example.audio;
import ddf.minim.effects.*;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import com.varma.samples.audiorecorder.R;
import android.app.Activity;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioRecord;
import android.media.AudioTrack;
import android.media.MediaRecorder;
import android.media.MediaScannerConnection;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.text.SpannableStringBuilder;
import android.text.style.RelativeSizeSpan;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
public class RecorderActivity extends Activity {
private static final int RECORDER_BPP = 16;
private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav";
private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder";
private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw";
private static final int RECORDER_SAMPLERATE = 44100;// 44100; //18000
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_STEREO; //AudioFormat.CHANNEL_IN_STEREO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
private static final int PLAY_CHANNELS = AudioFormat.CHANNEL_OUT_STEREO; //AudioFormat.CHANNEL_OUT_STEREO;
private static final int FREQUENCY_LEFT = 2000; //Original:18000 (16 Dec)
private static final int FREQUENCY_RIGHT = 2000; //Original:18000 (16 Dec)
private static final int AMPLITUDE_LEFT = 1;
private static final int AMPLITUDE_RIGHT = 1;
private static final int DURATION_SECOND = 10;
private static final int SAMPLE_RATE = 44100;
private static final float SWEEP_RANGE = 1000.0f;
String store;
private AudioRecord recorder = null;
private int bufferSize = 0;
private Thread recordingThread = null;
private boolean isRecording = false;
double time;
float[] buffer1;
float[] buffer2;
byte[] byteBuffer1;
byte[] byteBuffer2;
byte[] byteBufferFinal;
int bufferIndex;
short x;
short y;
AudioTrack audioTrack;
Button btnPlay, btnStart, btnStop;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setButtonHandlers();
enableButtons(false);
btnPlay = (Button) findViewById(R.id.btnPlay);
btnStop = (Button) findViewById(R.id.btnStop);
btnStart = (Button) findViewById(R.id.btnStart);
bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);
buffer1 = new float[(int) (DURATION_SECOND * SAMPLE_RATE)];
buffer2 = new float[(int) (DURATION_SECOND * SAMPLE_RATE)];
float f1 = 0.0f, f2 = 0.0f;
for (int sample = 0, step = 0; sample < buffer1.length; sample++) {
time = sample / (SAMPLE_RATE * 1.0);
//f1 = (float)(FREQUENCY_LEFT + ((sample / (buffer1.length * 1.0)) * SWEEP_RANGE)); // frequency sweep
//f2 = (float)(FREQUENCY_RIGHT + ((sample / (buffer1.length * 1.0)) * SWEEP_RANGE)); // frequency sweep
f1 = FREQUENCY_LEFT; // static frequency
f2 = FREQUENCY_RIGHT; // static frequency
buffer1[sample] = (float) (AMPLITUDE_LEFT * Math.sin(2 * Math.PI * f1 * time));
buffer2[sample] = (float) (AMPLITUDE_RIGHT * Math.sin(2 * Math.PI * f2 * time));
}
byteBuffer1 = new byte[buffer1.length * 2]; // two bytes per audio
// frame, 16 bits
for (int i = 0, bufferIndex = 0; i < byteBuffer1.length; i++) {
x = (short) (buffer1[bufferIndex++] * 32767.0); // [2^16 - 1]/2 =
// 32767.0
byteBuffer1[i] = (byte) x; // low byte
byteBuffer1[++i] = (byte) (x >>> 8); // high byte
}
byteBuffer2 = new byte[buffer2.length * 2];
for (int j = 0, bufferIndex = 0; j < byteBuffer2.length; j++) {
y = (short) (buffer2[bufferIndex++] * 32767.0);
byteBuffer2[j] = (byte) y; // low byte
byteBuffer2[++j] = (byte) (y >>> 8); // high byte
}
byteBufferFinal = new byte[byteBuffer1.length * 2];
// LL RR LL RR LL RR
for (int k = 0, index = 0; index < byteBufferFinal.length - 4; k = k + 2) {
byteBufferFinal[index] = byteBuffer1[k]; // LEFT
// {0,1/4,5/8,9/12,13;...}
byteBufferFinal[index + 1] = byteBuffer1[k + 1];
index = index + 2;
byteBufferFinal[index] = byteBuffer2[k]; // RIGHT
// {2,3/6,7/10,11;...}
byteBufferFinal[index + 1] = byteBuffer2[k + 1];
index = index + 2;
}
try {
FileOutputStream ss = new FileOutputStream(Environment.getExternalStorageDirectory().getPath() + "/" + AUDIO_RECORDER_FOLDER + "/source.txt");
ss.write(byteBufferFinal);
ss.flush();
ss.close();
}
catch (IOException ioe){
Log.e("IO Error","Write source error.");
}
}
private void setButtonHandlers() {
((Button) findViewById(R.id.btnStart)).setOnClickListener(startClick);
((Button) findViewById(R.id.btnStop)).setOnClickListener(stopClick);
((Button) findViewById(R.id.btnPlay)).setOnClickListener(playClick);
}
private void enableButton(int id, boolean isEnable) {
((Button) findViewById(id)).setEnabled(isEnable);
}
private void enableButtons(boolean isRecording) {
enableButton(R.id.btnStart, !isRecording);
enableButton(R.id.btnStop, isRecording);
enableButton(R.id.btnPlay, isRecording);
}
private String getFilename() {
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath, AUDIO_RECORDER_FOLDER);
if (!file.exists()) {
file.mkdirs();
}
MediaScannerConnection.scanFile(this, new String[]{filepath}, null, null);
store = file.getAbsolutePath() + "/" + "Audio"
+ AUDIO_RECORDER_FILE_EXT_WAV;
return store;
}
private String getTempFilename() {
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath, AUDIO_RECORDER_FOLDER);
if (!file.exists()) {
file.mkdirs();
}
File tempFile = new File(filepath, AUDIO_RECORDER_TEMP_FILE);
if (tempFile.exists())
tempFile.delete();
return (file.getAbsolutePath() + "/" + AUDIO_RECORDER_TEMP_FILE);
}
private void startRecording() {
//BandPass bandpass = new BandPass(19000,2000,44100);
/* BandPass bandpass = new BandPass(50,2,SAMPLE_RATE);
int [] freqR = {FREQUENCY_RIGHT};
int [] freqL = {FREQUENCY_LEFT};
float[] testL = shortToFloat(freqR);
float [] testR = shortToFloat(freqL);
bandpass.process(testL,testR);
bandpass.printCoeff();
*/
recorder = new AudioRecord(MediaRecorder.AudioSource.CAMCORDER,
RECORDER_SAMPLERATE, RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING, bufferSize);
AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
/*
* AudioTrack audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
* (int) RECORDER_SAMPLERATE,AudioFormat.CHANNEL_OUT_STEREO,
* AudioFormat.ENCODING_PCM_16BIT, bufferSize, AudioTrack.MODE_STREAM);
*/
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
(int) SAMPLE_RATE, PLAY_CHANNELS,
AudioFormat.ENCODING_PCM_16BIT, byteBufferFinal.length,
AudioTrack.MODE_STATIC);
audioTrack.write(byteBufferFinal, 0, byteBufferFinal.length);
audioTrack.play();
BandPass bandpass = new BandPass(50,2,SAMPLE_RATE);
int [] freqR = {FREQUENCY_RIGHT};
int [] freqL = {FREQUENCY_LEFT};
float[] testL = shortToFloat(freqR);
float [] testR = shortToFloat(freqL);
bandpass.process(testL,testR);
bandpass.printCoeff();
audioTrack.setPlaybackRate(RECORDER_SAMPLERATE);
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
#Override
public void run() {
try {
writeAudioDataToFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "AudioRecorder Thread");
recordingThread.start();
}
double[][] deinterleaveData(double[] samples, int numChannels) {
// assert(samples.length() % numChannels == 0);
int numFrames = samples.length / numChannels;
double[][] result = new double[numChannels][];
for (int ch = 0; ch < numChannels; ch++) {
result[ch] = new double[numFrames];
for (int i = 0; i < numFrames; i++) {
result[ch][i] = samples[numChannels * i + ch];
}
}
return result;
}
private void writeAudioDataToFile() throws IOException {
int read = 0;
byte data[] = new byte[bufferSize];
String filename = getTempFilename();
FileOutputStream os = null;
FileOutputStream rs = null;
try {
os = new FileOutputStream(filename);
rs = new FileOutputStream(getFilename().split(".wav")[0] + ".txt");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if (null != os) {
while (isRecording) {
read = recorder.read(data, 0, bufferSize);
if (AudioRecord.ERROR_INVALID_OPERATION != read) {
try {
os.write(data);
rs.write(data);
} catch (IOException e) {
e.printStackTrace();
}
}
}
try {
os.close();
rs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private void stopRecording() {
if (null != recorder) {
isRecording = false;
audioTrack.flush();
audioTrack.stop();
audioTrack.release();
recorder.stop();
recorder.release();
recorder = null;
recordingThread = null;
}
copyWaveFile(getTempFilename(), getFilename());
deleteTempFile();
MediaScannerConnection.scanFile(this, new String[]{getFilename()}, null, null);
AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_MUSIC, 0, 0);
}
private void deleteTempFile() {
File file = new File(getTempFilename());
file.delete();
}
private void copyWaveFile(String inFilename, String outFilename) {
FileInputStream in = null;
FileOutputStream out = null;
long totalAudioLen = 0;
long totalDataLen = totalAudioLen + 36;
long longSampleRate = RECORDER_SAMPLERATE;
int channels = 2;
long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels / 8;
byte[] data = new byte[bufferSize];
try {
in = new FileInputStream(inFilename);
out = new FileOutputStream(outFilename);
totalAudioLen = in.getChannel().size();
totalDataLen = totalAudioLen + 36;
WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
while (in.read(data) != -1) {
out.write(data);
}
in.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void playWaveFile() {
String filepath = store;
Log.d("PLAYWAVEFILE", "I AM INSIDE");
// define the buffer size for audio track
int minBufferSize = AudioTrack.getMinBufferSize(8000,
AudioFormat.CHANNEL_OUT_STEREO, AudioFormat.ENCODING_PCM_16BIT);
int bufferSize = 512;
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
(int) RECORDER_SAMPLERATE, AudioFormat.CHANNEL_OUT_STEREO,
AudioFormat.ENCODING_PCM_16BIT, minBufferSize,
AudioTrack.MODE_STREAM);
int count = 0;
byte[] data = new byte[bufferSize];
try {
FileInputStream fileInputStream = new FileInputStream(filepath);
DataInputStream dataInputStream = new DataInputStream(
fileInputStream);
audioTrack.play();
Toast.makeText(RecorderActivity.this, "this is my Toast message!!! =)",
Toast.LENGTH_LONG).show();
while ((count = dataInputStream.read(data, 0, bufferSize)) > -1) {
Log.d("PLAYWAVEFILE", "WHILE INSIDE");
audioTrack.write(data, 0, count);
//BandPass bandpass = new BandPass(19000,2000,44100); //Actual
//BandPass bandpass = new BandPass(5000,2000,44100); //Test
//int [] freqR = {FREQUENCY_RIGHT};
//int [] freqL = {FREQUENCY_LEFT};
//float[] testR = shortToFloat(freqR);
//float [] testL = shortToFloat(freqL);
//bandpass.process(testR,testL);
// BandPass bandpass = new BandPass(19000,2000,44100);
//float bw = bandpass.getBandWidth();
//float hello = bandpass.getBandWidth();
//float freq = bandpass.frequency();
//float[] test = {FREQUENCY_RIGHT,FREQUENCY_LEFT};
//shortToFloat(test);
//test [0] = FREQUENCY_RIGHT;
//test [1] = FREQUENCY_LEFT;
//bandpass.process(FREQUENCY_LEFT,FREQUENCY_RIGHT);
//Log.d("MyApp","I am here");
//Log.d("ADebugTag", "Valueeees: " + Float.toString(hello));
//Log.d("Bandwidth: " , "Bandwidth: " + Float.toString(bw));
//Log.d("Frequency: " , "Frequency is " + Float.toString(freq));
//bandpass.setBandWidth(20);
//bandpass.printCoeff();
}
audioTrack.stop();
audioTrack.release();
dataInputStream.close();
fileInputStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private void WriteWaveFileHeader(FileOutputStream out, long totalAudioLen,
long totalDataLen, long longSampleRate, int channels, long byteRate)
throws IOException {
byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (byte) channels;
header[23] = 0;
header[24] = (byte) (longSampleRate & 0xff);
header[25] = (byte) ((longSampleRate >> 8) & 0xff);
header[26] = (byte) ((longSampleRate >> 16) & 0xff);
header[27] = (byte) ((longSampleRate >> 24) & 0xff);
header[28] = (byte) (byteRate & 0xff);
header[29] = (byte) ((byteRate >> 8) & 0xff);
header[30] = (byte) ((byteRate >> 16) & 0xff);
header[31] = (byte) ((byteRate >> 24) & 0xff);
header[32] = (byte) (2 * 16 / 8); // block align
header[33] = 0;
header[34] = RECORDER_BPP; // bits per sample
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte) (totalAudioLen & 0xff);
header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
out.write(header, 0, 44);
}
private View.OnClickListener startClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
Thread recordThread = new Thread(new Runnable() {
#Override
public void run() {
isRecording = true;
startRecording();
}
});
recordThread.start();
btnStart.setEnabled(false);
btnStop.setEnabled(true);
btnPlay.setEnabled(false);
}
};
private View.OnClickListener stopClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
stopRecording();
enableButtons(false);
btnPlay.setEnabled(true);
// stop();
}
}, 100);
}
};
private View.OnClickListener playClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
playWaveFile();
btnPlay.setEnabled(true);
String filepath = store;
final String promptPlayRecord = "PlayWaveFile()\n" + filepath;
SpannableStringBuilder biggerText = new SpannableStringBuilder(promptPlayRecord);
biggerText.setSpan(new RelativeSizeSpan(2.05f), 0, promptPlayRecord.length(), 0);
Toast.makeText(RecorderActivity.this, biggerText, Toast.LENGTH_LONG).show();
}
};
}
The method below is to convert my 16-bit integer to float since the library uses float
/**
* Convert int[] audio to 32 bit float format.
* From [-32768,32768] to [-1,1]
* #param audio
*/
private float[] shortToFloat(int[] audio) {
Log.d("SHORTTOFLOAT","INSIDE SHORTTOFLOAT");
float[] converted = new float[audio.length];
for (int i = 0; i < converted.length; i++) {
// [-32768,32768] -> [-1,1]
converted[i] = audio[i] / 32768f; /* default range for Android PCM audio buffers) */
}
return converted;
}
Trying to implement bandpass filter under "SaveRecording" Method
//BandPass bandpass = new BandPass(19000,2000,44100);
Since I am trying to implement a range of 18k to 20k, I input the above values to the bandpass filter.
BandPass bandpass = new BandPass(50,2,44100); (This is just to test if the frequency has any changes since 18k-20k is not within human range)
int [] freqR = {FREQUENCY_RIGHT};
int [] freqL = {FREQUENCY_LEFT};
float[] testL = shortToFloat(freqR);
float [] testR = shortToFloat(freqL);
bandpass.process(testL,testR);
bandpass.printCoeff();
Since I am recording in STEREO, I am using the
public final synchronized void process(float[] sigLeft, float[] sigRight) {} found in the IIRFilter.java class.
However, I am not hearing any differences even though I implemented the above method. What am I doing wrong? Could anyone advise/help me?
Thank You so much! Terribly new in this signal processing. Any tips/hints on how to progress is much appreciated!!!
Updated
Since I have to output the .wav file with the filtered sound signal, I thought the way to do it is to put the BandPass filter under the "StartRecording" method, however, it is not working. Why is it that I am doing wrong?
private void startRecording() {
int count = 0;
recorder = new AudioRecord(MediaRecorder.AudioSource.CAMCORDER,
RECORDER_SAMPLERATE, RECORDER_CHANNELS,
RECORDER_AUDIO_ENCODING, bufferSize);
AudioManager am = (AudioManager)getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_MUSIC, am.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
audioTrack = new AudioTrack(AudioManager.STREAM_MUSIC,
(int) SAMPLE_RATE, PLAY_CHANNELS,
AudioFormat.ENCODING_PCM_16BIT, byteBufferFinal.length,
AudioTrack.MODE_STATIC);
BandPass bandpass = new BandPass(19000,2000,44100);
float[][] signals = deinterleaveData(byteToFloat(byteBufferFinal), 2);
bandpass.process(signals[0], signals[1]);
audioTrack.write(interleaveData(signals), 0, count, WRITE_NON_BLOCKING);
audioTrack.play();
//audioTrack.write(byteBufferFinal, 0, byteBufferFinal.length); //Original
audioTrack.setPlaybackRate(RECORDER_SAMPLERATE);
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
#Override
public void run() {
try {
writeAudioDataToFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}, "AudioRecorder Thread");
recordingThread.start();
}
Updated (14 March 2016)
This is the image of the output .wav file shown by Audacity:
May I ask if it is considered filtered?
What are the characteristics that I should look out for to ensure that it is filtered correctly.
The above image produce by press the black triangle
The above image graph produced by the Analyse->Plot Specturm
What about this graph? Does it implement the bandpass filter successfully? Thank
There is an issue with how you interface with the Bandpass.java source, probably resulting from what appears to be a bit of a misconception: IIR filters do not process frequencies, but they rather process time-domain data samples (which may exhibit oscillatory behavior).
As such you have to provide those time domain samples as inputs to Bandpass.process(). Since you are reading raw bytes from file, you will need to convert those bytes to float. You could do this with:
/**
* Convert byte[] raw audio to 16 bit int format.
* #param rawdata
*/
private int[] byteToShort(byte[] rawdata) {
int[] converted = new int[rawdata.length / 2];
for (int i = 0; i < converted.length; i++) {
// Wave file data are stored in little-endian order
int lo = rawdata[2*i];
int hi = rawdata[2*i+1];
converted[i] = ((hi&0xFF)<<8) | (lo&0xFF);
}
return converted;
}
private float[] byteToFloat(byte[] audio) {
return shortToFloat(byteToShort(audio));
}
Also for stereo wave files, you will get samples from the wave files which are interleaved. So you will also need to deinterleave the samples. This can be achieved in a similar fashion as you've done with deinterleaveData, except you will need a variant converting to float[][] instead of to double[][] since Bandpass.process expects float arrays.
You will of course also need to recombine the two channels back together after the filtering but before feeding the resulting filtered signals back to the audioTrack:
float[] interleaveData(float[][] data) {
int numChannels = data.length;
int numFrames = data[0].length;
float[] result = new float[numFrames*numChannels];
for (int i = 0; i < numFrames; i++) {
for (int ch = 0; ch < numChannels; ch++) {
result[numChannels * i + ch] = data[ch][i];
}
}
return result;
}
You should now have the required building blocks to filter your audio:
BandPass bandpass = new BandPass(19000,2000,44100);
while ((count = dataInputStream.read(data, 0, bufferSize)) > -1) {
// decode and deinterleave stereo 16-bit per sample data
float[][] signals = deinterleaveData(byteToFloat(data), 2);
// filter data samples, updating the buffers with the filtered samples.
bandpass.process(signals[0], signals[1]);
// recombine signals for playback
audioTrack.write(interleaveData(signals), 0, count, WRITE_NON_BLOCKING);
}
P.S.: as a final note, you are currently reading all the wave file as data samples, header included. This will result in a short noisy burst at the beginning. To avoid this, you should skip the header.
There could be a few problems...
The audio file you are trying to filter may not have much content that is noticeable to the ear in the bandpass range you are trying to filter. Try filtering a much larger range to verify the filter works. Try filtering most the song.
If you cannot get the above to work, then the filter is not being implemented properly. You likely are not implementing the filter correctly. For a really simple filter your could try Y[n] = X[n] - .5*X[n-1] which is a High Pass FIR filter with zero at 0 Hz.
Good Luck!
I am trying to record a wav file and read and save data of a wav file in android.Everything is working fine except differences in the values I am reading in Matlab with my saved data in android
here is my code
private static final int RECORDER_BPP = 16;
private static final String AUDIO_RECORDER_FILE_EXT_WAV = ".wav";
private static final String AUDIO_RECORDER_FOLDER = "AudioRecorder";
private static final String AUDIO_RECORDER_TEMP_FILE = "record_temp.raw";
private static final int RECORDER_SAMPLERATE = 44100;
private static final int RECORDER_CHANNELS = AudioFormat.CHANNEL_IN_MONO;
private static final int RECORDER_AUDIO_ENCODING = AudioFormat.ENCODING_PCM_16BIT;
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.main);
setButtonHandlers();
enableButtons(false);
bufferSize = AudioRecord.getMinBufferSize(RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING);
}
private void setButtonHandlers() {
((Button) findViewById(R.id.btnStart)).setOnClickListener(btnClick);
((Button) findViewById(R.id.btnStop)).setOnClickListener(btnClick);
}
private void enableButton(int id, boolean isEnable) {
((Button) findViewById(id)).setEnabled(isEnable);
}
private void enableButtons(boolean isRecording) {
enableButton(R.id.btnStart, !isRecording);
enableButton(R.id.btnStop, isRecording);
}
private String getFilename() {
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath, AUDIO_RECORDER_FOLDER);
if ( !file.exists()) {
file.mkdirs();
}
return (file.getAbsolutePath() + "/" + 11 + AUDIO_RECORDER_FILE_EXT_WAV);
}
private String getTempFilename() {
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath, AUDIO_RECORDER_FOLDER);
if ( !file.exists()) {
file.mkdirs();
}
File tempFile = new File(filepath, AUDIO_RECORDER_TEMP_FILE);
if (tempFile.exists())
tempFile.delete();
return (file.getAbsolutePath() + "/" + AUDIO_RECORDER_TEMP_FILE);
}
private String getfftFilename() {
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath, AUDIO_RECORDER_FOLDER);
if ( !file.exists()) {
file.mkdirs();
}
return (file.getAbsolutePath() + "/" + "fft" + ".txt");
}
private void startRecording() {
recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
RECORDER_SAMPLERATE, RECORDER_CHANNELS, RECORDER_AUDIO_ENCODING, bufferSize);
recorder.startRecording();
isRecording = true;
recordingThread = new Thread(new Runnable() {
#Override
public void run() {
writeAudioDataToFile();
}
}, "AudioRecorder Thread");
recordingThread.start();
}
private void writeAudioDataToFile() {
byte data[] = new byte[bufferSize];
String filename = getTempFilename();
FileOutputStream os = null;
try {
os = new FileOutputStream(filename);
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
int read = 0;
if (null != os) {
while (isRecording) {
read = recorder.read(data, 0, bufferSize);
if (AudioRecord.ERROR_INVALID_OPERATION != read) {
try {
os.write(data);
}
catch (IOException e) {
e.printStackTrace();
}
}
}
}
try {
os.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
private void stopRecording() {
if (null != recorder) {
isRecording = false;
recorder.stop();
recorder.release();
recorder = null;
recordingThread = null;
}
copyWaveFile(getTempFilename(), getFilename());
////coding(getTempFilename(), getrainroom(), getstegan());
////decoding(getstegan(), getdecodeFilename(), getrainroom());
fftbegir(getTempFilename(), getfftFilename());
deleteTempFile();
}
private void deleteTempFile() {
File file = new File(getTempFilename());
file.delete();
}
private void copyWaveFile(String inFilename, String outFilename) {
FileInputStream in = null;
FileOutputStream out = null;
long totalAudioLen = 0;
long totalDataLen = totalAudioLen + 36;
long longSampleRate = RECORDER_SAMPLERATE;
int channels = 1;
long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels / 8;
byte[] data = new byte[bufferSize];
try {
in = new FileInputStream(inFilename);
out = new FileOutputStream(outFilename);
totalAudioLen = in.getChannel().size();
totalDataLen = totalAudioLen + 36;
AppLog.logString("File size: " + totalDataLen);
WriteWaveFileHeader(out, totalAudioLen, totalDataLen,
longSampleRate, channels, byteRate);
while (in.read(data) != -1) {
out.write(data);
}
in.close();
out.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
private void fftbegir(String input, String output) {
FileInputStream in5 = null;
FileOutputStream out5 = null;
FileOutputStream stream = null;
byte[] data7 = new byte[10000];
double[] data8;
long totalAudioLen = 0;
long totalDataLen = totalAudioLen + 36;
long longSampleRate = RECORDER_SAMPLERATE;
int channels = 1;
int i = 0;
int r, k, l;
double b;
int m = 2;
long byteRate = RECORDER_BPP * RECORDER_SAMPLERATE * channels / 8;
String filepath = Environment.getExternalStorageDirectory().getPath();
File tempFile = new File(filepath, AUDIO_RECORDER_TEMP_FILE);
try {
in5 = new FileInputStream(input);
out5 = new FileOutputStream(output);
String strI = "nxkxaprojext;)";
out5.write(strI.getBytes());
AppLog.logString("File size: " + totalDataLen);
totalAudioLen = in5.getChannel().size();
strI = Long.toString(totalAudioLen);
out5.write(strI.getBytes());
out5.write(" ".getBytes());
data8 = SoundDataUtils.load16BitPCMRawDataFileAsDoubleArray();
l = data8.length;
strI = Integer.toString(l);
out5.write(strI.getBytes());
out5.write(" ".getBytes());
while (l > m) {
m = m * 2;
}
strI = Integer.toString(m);
out5.write(strI.getBytes());
out5.write(" ".getBytes());
strI = Double.toString(data8[50]);
out5.write(strI.getBytes());
Complex[] x = new Complex[m];
while (i < l) {
strI = Double.toString(data8[i]);
out5.write(strI.getBytes());
out5.write(" ".getBytes());
//x[i] = new Complex(data8[i], 0);
i++;
}
in5.close();
///i--;
///for (i = l; i < m; i++) {
/// x[i] = new Complex(0, 0);
/// }
/// FFT f = new FFT();
//// Complex[] y = f.fft(x);
/*try {
for (i = 0; i < m; i++) {
b = y[i].re();
strI = Double.toString(b);
out5.write(strI.getBytes());
out5.write(" ".getBytes());
b = y[i].im();
strI = Double.toString(b);
out5.write(strI.getBytes());
out5.write("j".getBytes());
out5.write(" ".getBytes());
}
}*/// finally {
/// out5.close();
////}
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
}
private void WriteWaveFileHeader(
FileOutputStream out, long totalAudioLen,
long totalDataLen, long longSampleRate, int channels,
long byteRate) throws IOException {
byte[] header = new byte[44];
header[0] = 'R'; // RIFF/WAVE header
header[1] = 'I';
header[2] = 'F';
header[3] = 'F';
header[4] = (byte) (totalDataLen & 0xff);
header[5] = (byte) ((totalDataLen >> 8) & 0xff);
header[6] = (byte) ((totalDataLen >> 16) & 0xff);
header[7] = (byte) ((totalDataLen >> 24) & 0xff);
header[8] = 'W';
header[9] = 'A';
header[10] = 'V';
header[11] = 'E';
header[12] = 'f'; // 'fmt ' chunk
header[13] = 'm';
header[14] = 't';
header[15] = ' ';
header[16] = 16; // 4 bytes: size of 'fmt ' chunk
header[17] = 0;
header[18] = 0;
header[19] = 0;
header[20] = 1; // format = 1
header[21] = 0;
header[22] = (byte) channels;
header[23] = 0;
header[24] = (byte) (longSampleRate & 0xff);
header[25] = (byte) ((longSampleRate >> 8) & 0xff);
header[26] = (byte) ((longSampleRate >> 16) & 0xff);
header[27] = (byte) ((longSampleRate >> 24) & 0xff);
header[28] = (byte) (byteRate & 0xff);
header[29] = (byte) ((byteRate >> 8) & 0xff);
header[30] = (byte) ((byteRate >> 16) & 0xff);
header[31] = (byte) ((byteRate >> 24) & 0xff);
header[32] = (byte) (1 * 16 / 8); // block align
header[33] = 0;
header[34] = RECORDER_BPP; // bits per sample
header[35] = 0;
header[36] = 'd';
header[37] = 'a';
header[38] = 't';
header[39] = 'a';
header[40] = (byte) (totalAudioLen & 0xff);
header[41] = (byte) ((totalAudioLen >> 8) & 0xff);
header[42] = (byte) ((totalAudioLen >> 16) & 0xff);
header[43] = (byte) ((totalAudioLen >> 24) & 0xff);
out.write(header, 0, 44);
}
private View.OnClickListener btnClick = new View.OnClickListener() {
#Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btnStart: {
AppLog.logString("Start Recording");
enableButtons(true);
startRecording();
break;
}
case R.id.btnStop: {
AppLog.logString("Start Recording");
enableButtons(false);
stopRecording();
break;
}
}
}
};
and SoundDataUtils class code is(in this class i I tried to convert 16bit to double)
public static double[] load16BitPCMRawDataFileAsDoubleArray() throws IOException {
String filepath = Environment.getExternalStorageDirectory().getPath();
File file = new File(filepath, "AudioRecorder");
if ( !file.exists()) {
file.mkdirs();
}
File tempFile = new File(filepath + "/AudioRecorder", "record_temp.raw");
InputStream in = null;
long size = tempFile.length();
try {
in = new FileInputStream(tempFile);
return readStreamAsDoubleArray(in, size);
}
catch (Exception e) {}
return null;
}
public static double[] readStreamAsDoubleArray(InputStream in, long size)
throws IOException {
int bufferSize = (int) (size / 2);
double[] result = new double[bufferSize];
DataInputStream is = new DataInputStream(in);
for (int i = 0; i < bufferSize; i++) {
result[i] = is.readShort() / 32768.0;
}
return result;
}
the first 20 values in android:
0.8359375 0.2265625 0.1171875 0.8359375 -1.0 -0.8359375 0.9375 0.71875 -0.5078125 -0.34375 -0.8359375 -0.71875 -0.8828125 0.4453125 -0.218780517578125 0.960906982421875 -0.710968017578125 -0.156280517578125 -0.7890625 0.7734375
the first 20 values in matlab:0.00326538085937500
0.000885009765625000
0.000457763671875000
0.00326538085937500
0.00390625000000000
0.00454711914062500
0.00366210937500000
0.00280761718750000
0.00582885742187500
0.00646972656250000
0.00454711914062500
0.00500488281250000
0.00436401367187500
0.00173950195312500
-0.000885009765625000
-0.00408935546875000
-0.00280761718750000
-0.000640869140625000
0.00473022460937500
0.00302124023437500
i am spending a lot of hours to finding problem.
Can someone help me? THANKS!
I have question about Android decode mp3, mix few audio and encode to m4a (aac). For that I use Jlayer for android to decode mp3, audiotrack to play song, and MediaCodec with mediaformat to encode pcm. The problem is my output after encode is too fast for example: I should have 5 sec audio mix but instead I got ~ 1,5 sec. I thinking that I lose somewhere audio frames, but I dont sure about that. Thanks for answer.
(output file is ~ 25% faster that should be)
Decode mp3 code:
public void decodeMP3toPCM(Resources res, int resource) throws BitstreamException, DecoderException, IOException {
InputStream inputStream = new BufferedInputStream(res.openRawResource(resource), 1152);
Bitstream bitstream = new Bitstream(inputStream);
Decoder decoder = new Decoder();
boolean done = false;
while (!done) {
Header frameHeader = bitstream.readFrame();
if (frameHeader == null) {
done = true;
} else {
SampleBuffer output = (SampleBuffer) decoder.decodeFrame(frameHeader, bitstream);
mTimeCount += frameHeader.ms_per_frame();
short[] pcm = output.getBuffer();
mDataBuffer.addFrame(mViewId, pcm);
mReadedFrames++;
mAudioTrack.write(pcm, 0, pcm.length);
}
bitstream.closeFrame();
}
inputStream.close();
}
encode:
public class AudioEncoder {
private MediaCodec mediaCodec;
private BufferedOutputStream outputStream;
private String mediaType = "audio/mp4a-latm";
public AudioEncoder(String filePath) throws IOException {
File f = new File(filePath);
touch(f);
try {
outputStream = new BufferedOutputStream(new FileOutputStream(f));
} catch (Exception e) {
e.printStackTrace();
}
try {
//mediaCodec = MediaCodec.createEncoderByType(mediaType);
mediaCodec = MediaCodec.createByCodecName("OMX.google.aac.encoder");
} catch (IOException e) {
e.printStackTrace();
}
mediaCodec = MediaCodec.createEncoderByType(mediaType);
final int kSampleRates[] = { 8000, 11025, 22050, 44100, 48000 };
final int kBitRates[] = { 64000, 128000 };
MediaFormat mediaFormat = MediaFormat.createAudioFormat(mediaType,kSampleRates[3],2);
mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC);
mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, 4608);
mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, kBitRates[1]);
mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mediaCodec.start();
}
public void close() {
try {
mediaCodec.stop();
mediaCodec.release();
outputStream.flush();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public synchronized void offerEncoder(byte[] input) {
Log.e("synchro ", input.length + " is coming");
try {
ByteBuffer[] inputBuffers = mediaCodec.getInputBuffers();
ByteBuffer[] outputBuffers = mediaCodec.getOutputBuffers();
int inputBufferIndex = mediaCodec.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(input);
mediaCodec.queueInputBuffer(inputBufferIndex, 0, input.length, 0, 0);
}
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
int outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
while (outputBufferIndex >= 0) {
int outBitsSize = bufferInfo.size;
int outPacketSize = outBitsSize + 7; // 7 is ADTS size
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
outputBuffer.position(bufferInfo.offset);
outputBuffer.limit(bufferInfo.offset + outBitsSize);
byte[] outData = new byte[outPacketSize];
addADTStoPacket(outData, outPacketSize);
outputBuffer.get(outData, 7, outBitsSize);
outputBuffer.position(bufferInfo.offset);
outputStream.write(outData, 0, outData.length);
mediaCodec.releaseOutputBuffer(outputBufferIndex, false);
outputBufferIndex = mediaCodec.dequeueOutputBuffer(bufferInfo, 0);
}
} catch (Throwable t) {
t.printStackTrace();
}
}
private void addADTStoPacket(byte[] packet, int packetLen) {
int profile = 2; //AAC LC
//39=MediaCodecInfo.CodecProfileLevel.AACObjectELD;
int freqIdx = 4; //44.1KHz
int chanCfg = 2; //CPE
// fill in ADTS data
packet[0] = (byte) 0xFF;
packet[1] = (byte) 0xF9;
packet[2] = (byte) (((profile - 1) << 6) + (freqIdx << 2) + (chanCfg >> 2));
packet[3] = (byte) (((chanCfg & 3) << 6) + (packetLen >> 11));
packet[4] = (byte) ((packetLen & 0x7FF) >> 3);
packet[5] = (byte) (((packetLen & 7) << 5) + 0x1F);
packet[6] = (byte) 0xFC;
}
public void touch(File f) {
try {
if (!f.exists())
f.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
}
My problem is that I need to control mobile robot E-puck via Bluetooth in Java, by sending it commands like "D,100,100" to set speed, "E" to get speed, and etc. I have some code:
String command = "D,100,100";
OutputStream mOutputToPort = serialPort.getOutputStream();
mOutputToPort.write(command.getBytes());
So with this method write I can only send byte[] data, but my robot won't understand that.
For example previously I have been using this commands on Matlab like that:
s = serial('COM45');
fopen(s);
fprintf(s,'D,100,100','async');
Or on program Putty type only:
D,100,100 `enter`
Additional info:
I've also figured out, that Matlab has another solution for same thing.
s = serial('COM45');
fopen(s);
data=[typecast(int8('-D'),'int8') typecast(int16(500),'int8') typecast(int16(500),'int8')];
In this case:
data = [ -68 -12 1 -12 1];
fwrite(s,data,'int8','async');
Wouldn't it be the same in Java:
byte data[] = new byte[5];
data[0] = -'D';
data[1] = (byte)(500 & 0xFF);
data[2] = (byte)(500 >> 8);
data[3] = (byte)(500 & 0xFF);
data[4] = (byte)(500>> 8);
And then:
OutputStream mOutputToPort = serialPort.getOutputStream();
mOutputToPort.write(data);
mOutputToPort.flush();
Main details in code comments. Now you can change wheel speed by typing in command window D,1000,-500 and hitting enter.
public class serialRobot {
public static void main(String[] s) {
SerialPort serialPort = null;
try {
CommPortIdentifier portIdentifier = CommPortIdentifier.getPortIdentifier("COM71");
if (portIdentifier.isCurrentlyOwned()) {
System.out.println("Port in use!");
} else {
System.out.println(portIdentifier.getName());
serialPort = (SerialPort) portIdentifier.open(
"ListPortClass", 300);
int b = serialPort.getBaudRate();
System.out.println(Integer.toString(b));
serialPort.setSerialPortParams(115200, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
serialPort.setInputBufferSize(65536);
serialPort.setOutputBufferSize(4096);
System.out.println("Opened " + portIdentifier.getName());
OutputStream mOutputToPort = serialPort.getOutputStream();
InputStream mInputFromPort = serialPort.getInputStream();
PerpetualThread t = readAndPrint(mInputFromPort);
inputAndSend(mOutputToPort);
t.stopRunning();
mOutputToPort.close();
mInputFromPort.close();
}
} catch (IOException ex) {
System.out.println("IOException : " + ex.getMessage());
} catch (UnsupportedCommOperationException ex) {
System.out.println("UnsupportedCommOperationException : " + ex.getMessage());
} catch (NoSuchPortException ex) {
System.out.println("NoSuchPortException : " + ex.getMessage());
} catch (PortInUseException ex) {
System.out.println("PortInUseException : " + ex.getMessage());
} finally {
if(serialPort != null) {
serialPort.close();
}
}
}
private static PerpetualThread readAndPrint(InputStream in) {
final BufferedInputStream b = new BufferedInputStream(in);
PerpetualThread thread = new PerpetualThread() {
#Override
public void run() {
byte[] data = new byte[16];
int len = 0;
for(;isRunning();) {
try {
len = b.read(data);
} catch (IOException e) {
e.printStackTrace();
}
if(len > 0) {
System.out.print(new String(data, 0, len));
}
}
}
};
thread.start();
return thread;
}
private static void inputAndSend(OutputStream out) {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
int k = 0;
for(;;) {
String komanda;
try {
komanda = in.readLine();
} catch (IOException e) {
e.printStackTrace();
return;
}
komanda = komanda.trim();
if(komanda.equalsIgnoreCase("end")) return;
byte komandaSiust[] = proces(komanda); //Command we send after first
//connection, it's byte array where 0 member is the letter that describes type of command, next two members
// is about left wheel speed, and the last two - right wheel speed.
try {
if(k == 0){
String siunc = "P,0,0\n"; // This command must be sent first time, when robot is connected, otherwise other commands won't work
ByteBuffer bb = ByteBuffer.wrap(siunc.getBytes("UTF-8"));
bb.order(ByteOrder.LITTLE_ENDIAN);
out.write(bb.array());
out.flush();
}else{
ByteBuffer bb = ByteBuffer.wrap(komandaSiust);
bb.order(ByteOrder.LITTLE_ENDIAN);
out.write(bb.array());
out.flush();
}
k++;
} catch (IOException e) {
e.printStackTrace();
return;
}
}
}
private static byte[] proces(String tekstas){
tekstas = tekstas.trim();
char[] charArray = tekstas.toCharArray();
byte kodas1[];
int fComa = tekstas.indexOf(',', 1);
int sComa = tekstas.indexOf(',', 2);
int matavimas = charArray.length;
int skir1 = sComa - fComa - 1;
int skir2 = matavimas - sComa -1;
char leftSpeed[] = new char[skir1];
for(int i = 0; i < skir1; i++){
leftSpeed[i] = charArray[fComa + i + 1];
}
char rightSpeed[] = new char[skir2];
for(int i = 0; i < skir2; i++){
rightSpeed[i] = charArray[sComa + i + 1];
}
String right = String.valueOf(rightSpeed);
String left = String.valueOf(leftSpeed);
int val1 = Integer.parseInt(left);
int val2 = Integer.parseInt(right);
kodas1 = new byte[5];
kodas1[0] = (byte)-charArray[0];
kodas1[1] = (byte)(val1 & 0xFF);
kodas1[2] = (byte)(val1 >> 8);
kodas1[3] = (byte)(val2 & 0xFF);
kodas1[4] = (byte)(val2 >> 8);
return kodas1;
}
private static class PerpetualThread extends Thread {
private boolean isRunning = true;
public boolean isRunning() { return isRunning; }
public void stopRunning() {
isRunning = false;
this.interrupt();
}
}
}
According to the documentation, you need to call setSerialPortParams(int baudrate, int dataBits, int stopBits, int parity) on your serial port.