Sunday, March 2, 2014

Manually parsing a wave file in Java

In Java it is possible to get data directly from an audio device, audio file or URL (see examples here and here) through a standard package. In this article, we will manually parse a wave audio file to learn about its format which is rather simple: a part that states the format of the samples (e.g.: stereo 16bit 44100Hz) and a part with the samples themselves.

[Header]
00 "RIFF"
04 File size in bytes - 8
08 "WAVE"

[Format chunk]
12 "fmt " (format chunk mark)
16  Format chunk size - 8 (16 for PCM)
20  Format tag (1 for PCM)
22  Number of Channels (e.g.: 2)
24  SamplesPerSec (e.g.: 8000Hz)
28  AvgBytesPerSec = (Sample Rate * BytesPerFrame).
32  BlockAlign = BytesPerFrame = (BitsPerSample * Channels)/8 
34  BitsPerSample (e.g.: 8)

[Data chunk]
36 "data"
40 Data chunk size - 8
44 Frame_0: sample_channel0[0], sample_channel1[0], ..
   Frame_1: sample_channel0[1], sample_channel1[1], ..
   ...
   Frame_n: sample_channel0[n], sample_channel1[n], ..

If you don't believe me you can check it by yourself:

$ arecord -f U8 -c 1 -r 8000 -d 5 pepe.wav
Recording WAVE 'pepe.wav' : Unsigned 8 bit, Rate 8000 Hz, Mono
$ ls -l pepe.wav 
-rw-r--r-- 1 xxx xxx 40044 Mar  2 20:14 pepe.wav
$ od -A d -N 44 -w4 -v -t a pepe.wav 
0000000   R   I   F   F
0000008   W   A   V   E
0000012   f   m   t  sp
0000036   d   a   t   a
$ od -A d -N 44 -w4 -v -t u2 pepe.wav 
0000000 18770 17990   RIFF
0000004 40036     0   file size (40044) - 8)
0000008 16727 17750   WAVE
0000012 28006  8308   fmt
0000016    16     0   16 bytes of format data
0000020     1     1   1 channel
0000024  8000     0   8000 samples/sec
0000028  8000     0   8000 bytes/sec
0000032     1     8   8 bits/sample (1 byte/frame)
0000036 24932 24948   ata
0000040 40000     0   4000 samples

Now here is the point. Suppose that we just want to play with a wave file in a specific format. Then, we can skip the first 44 format bytes and go straight to the data. In particular, if the format of the wave file is "mono 8bit" things get as simple as this:

$ vi pepe.java
import java.io.*;
public class pepe {
  public static void main(String[] args) {
    int bytes, cursor, unsigned;
    try {
      FileInputStream s = new FileInputStream("./pepe.wav");
      BufferedInputStream b = new BufferedInputStream(s);
      byte[] data = new byte[128];
      b.skip(44);
      cursor = 0;
      while ((bytes = b.read(data)) > 0) {
        // do something
        for(int i=0; i<bytes; i++) {
                unsigned = data[i] & 0xFF; // Java..
                System.out.println(cursor + " " + unsigned);
                cursor++;
        }
      }
      b.read(data);
      b.close();
    } catch(Exception e) {
      e.printStackTrace();
    }
  }
}
$ javac pepe.java
$ java pepe > data.txt
$ gnuplot
gnuplot> set size ratio 0.3
gnuplot> plot "data.txt" with lines


Hope that's useful for you.

Ubuntu Spanish accents | Tildes en Ubuntu.

This is a method for writing Spanish accents on Ubuntu when you don't have a Spanish keyboard. I tested it on Ubuntu 12.0.4 LTS (classic desktop). I am using a Japanese keyboard with an English environment.

System tools -> System settings -> Keyboard layouts -> Layout ->
Options -> Compose key option -> Right Alt


Note: if you can't find "System tools" menu, execute the command 'gnome-control-center'

Then you can write Spanish accents as follows:


RightAlt-a + ' = á

RightAlt-e + ' = é
RightAlt-i + ' = í
RightAlt-o + ' = ó
RightAlt-u + ' = ú
RightAlt-n + - = ñ
RightAlt-? + ? = ¿

Note: RigthAlt is the Alt key on the right side of the keyboard.