Parse the osu! binary database in Java - java

As said in the title, I must read a binary file where specifications are written here :
https://osu.ppy.sh/wiki/Db_(file_format)#collection.db
It's written by a program written in C#. Except I don't have an idea on how to proceed to get the datas, an to store them into objects.
Any ideas or examples on the way to proceed ? Thanks a lot :)

According to specification:
import java.io.*;
import java.nio.*;
import java.util.*;
public class OsuReader
{
public static void main(String[] args) throws IOException
{
String kind = args[0];
OsuReader reader = new OsuReader(args[1]);
if (kind.equals("collection"))
{
CollectionDB db = reader.readCollectionDB();
System.out.printf("Version: %d\n", db.version);
for (CollectionItem item : db.collections)
{
System.out.println();
System.out.printf("Name: %s\n", item.name);
for (String hash : item.md5Hashes)
{
System.out.printf(" Hash: %s\n", hash);
}
}
}
else if (kind.equals("scores"))
{
ScoresDB db = reader.readScoresDB();
System.out.printf("Version: %d", db.version);
for (Beatmap beatmap : db.beatmaps)
{
System.out.println("---");
System.out.printf("Beatmap hash: %s\n", beatmaps.hash);
for (Score score : beatmaps.scores)
{
System.out.println(" ---");
System.out.printf(" Mode: %s (%d)\n", score.mode.name(), score.mode.byteValue);
System.out.printf(" Version: %d\n", score.version);
System.out.printf(" Beatmap MD5: %s\n", score.beatmapMd5Hash);
System.out.printf(" Player name: %s\n", score.playerName);
System.out.printf(" Replay MD5: %s\n", score.replayMd5Hash);
System.out.printf(" Scores: %d / %d / %d / %d / %d / %d\n",
score.numberOf300s, score.numberOf100s, score.numberOf50s, score.numberOfGekis,
score.numberOfKatus, score.numberOfMisses);
System.out.printf(" Replay score: %d\n", score.replayScore);
System.out.printf(" Max combo: %d\n", score.maxCombo);
System.out.printf(" Perfect combo: %s\n", score.perfectCombo ? "Yes" : "No");
System.out.printf(" Mods used: %s\n", score.modsUsed);
System.out.printf(" Timestamp: %s\n", score.timestamp);
}
}
}
}
private DataInputStream reader;
public OsuReader(String filename) throws IOException
{
this(new FileInputStream(filename));
}
public OsuReader(InputStream source)
{
this.reader = new DataInputStream(source);
}
// --- Primitive values ---
public byte readByte() throws IOException
{
// 1 byte
return this.reader.readByte();
}
public short readShort() throws IOException
{
// 2 bytes, little endian
byte[] bytes = new byte[2];
this.reader.readFully(bytes);
ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
return bb.getShort();
}
public int readInt() throws IOException
{
// 4 bytes, little endian
byte[] bytes = new byte[4];
this.reader.readFully(bytes);
ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
return bb.getInt();
}
public long readLong() throws IOException
{
// 8 bytes, little endian
byte[] bytes = new byte[8];
this.reader.readFully(bytes);
ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
return bb.getLong();
}
public int readULEB128() throws IOException
{
// variable bytes, little endian
// MSB says if there will be more bytes. If cleared,
// that byte is the last.
int value = 0;
for (int shift = 0; shift < 32; shift += 7)
{
byte b = this.reader.readByte();
value |= ((int) b & 0x7F) << shift;
if (b >= 0) return value; // MSB is zero. End of value.
}
throw new IOException("ULEB128 too large");
}
public float readSingle() throws IOException
{
// 4 bytes, little endian
byte[] bytes = new byte[4];
this.reader.readFully(bytes);
ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
return bb.getFloat();
}
public double readDouble() throws IOException
{
// 8 bytes little endian
byte[] bytes = new byte[8];
this.reader.readFully(bytes);
ByteBuffer bb = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN);
return bb.getDouble();
}
public boolean readBoolean() throws IOException
{
// 1 byte, zero = false, non-zero = true
return this.reader.readBoolean();
}
public String readString() throws IOException
{
// variable length
// 00 = empty string
// 0B <length> <char>* = normal string
// <length> is encoded as an LEB, and is the byte length of the rest.
// <char>* is encoded as UTF8, and is the string content.
byte kind = this.reader.readByte();
if (kind == 0) return "";
if (kind != 11)
{
throw new IOException(String.format("String format error: Expected 0x0B or 0x00, found 0x%02X", (int) kind & 0xFF));
}
int length = readULEB128();
if (length == 0) return "";
byte[] utf8bytes = new byte[length];
this.reader.readFully(utf8bytes);
return new String(utf8bytes, "UTF-8");
}
public Date readDate() throws IOException
{
long ticks = readLong();
long TICKS_AT_EPOCH = 621355968000000000L;
long TICKS_PER_MILLISECOND = 10000;
return new Date((ticks - TICKS_AT_EPOCH)/TICKS_PER_MILLISECOND);
}
// --- Composite structures ---
public CollectionDB readCollectionDB() throws IOException
{
CollectionDB result = new CollectionDB();
result.version = readInt();
int count = readInt();
result.collections = new ArrayList<CollectionItem>(count);
for (int i = 0; i < count; i++)
{
CollectionItem item = readCollectionItem();
result.collections.add(item);
}
return result;
}
public CollectionItem readCollectionItem() throws IOException
{
CollectionItem item = new CollectionItem();
item.name = readString();
int count = readInt();
item.md5Hashes = new ArrayList<String>(count);
for (int i = 0; i < count; i++)
{
String md5Hash = readString();
item.md5Hashes.add(md5Hash);
}
return item;
}
public ScoresDB readScoresDB() throws IOException
{
ScoresDB result = new ScoresDB();
result.version = readInt();
int count = readInt();
result.beatmaps = new ArrayList<Beatmap>(count);
for (int i = 0; i < count; i++)
{
Beatmap beatmap = readBeatmap();
result.beatmaps.add(beatmap);
}
return result;
}
public Beatmap readBeatmap() throws IOException
{
Beatmap result = new Beatmap();
result.md5Hash = readString();
int count = readInt();
result.scores = new ArrayList<Score>();
for (int i = 0; i < count; i++)
{
Score score = readScore();
result.scores.add(score);
}
return result;
}
public Score readScore() throws IOException
{
Score result = new Score();
result.mode = GameplayMode.valueOf(readByte());
result.version = readInt();
result.beatmapMd5Hash = readString();
result.playerName = readString();
result.replayMd5Hash = readString();
result.numberOf300s = readShort();
result.numberOf100s = readShort();
result.numberOf50s = readShort();
result.numberOfGekis = readShort();
result.numberOfKatus = readShort();
result.numberOfMisses = readShort();
result.replayScore = readInt();
result.maxCombo = readShort();
result.perfectCombo = readBoolean();
result.modsUsed = OsuMod.valueOf(readInt());
result.unknown1 = readString();
result.timestamp = readDate();
result.unknown2 = readInt();
result.unknown3 = readInt();
result.unknown4 = readInt();
return result;
}
public class CollectionDB
{
public int version; // 20150203
public List<CollectionItem> collections;
}
public class CollectionItem
{
public String name;
public List<String> md5Hashes;
}
public class ScoresDB
{
public int version; // 20150204
public List<Beatmap> beatmaps;
}
public class Beatmap
{
public String md5Hash;
public List<Score> scores;
}
public enum GameplayMode
{
OsuStandard((byte) 0),
Taiko((byte) 1),
CTB((byte) 2),
Mania((byte) 3);
public final byte byteValue;
private GameplayMode(byte byteValue)
{
this.byteValue = byteValue;
}
public static GameplayMode valueOf(byte byteValue)
{
for (GameplayMode item : values())
{
if (item.byteValue == byteValue) return item;
}
throw new IllegalArgumentException("byteValue");
}
}
public enum OsuMod
{
NoFail(1),
Easy(2),
NoVideo(4),
Hidden(8),
HardRock(16),
SuddenDeath(32),
DoubleTime(64),
Relax(128),
HalfTime(256),
Nightcore(512),
Flashlight(1024),
Autoplay(2048),
SpunOut(4096),
Relax2(8192),
Perfect(16384),
Key4(32768),
Key5(65536),
Key6(131072),
Key7(262144),
Key8(524288),
keyMod(1015808),
FadeIn(1048576),
Random(2097152),
LastMod(4194304);
public final int bit;
private OsuMod(int bit)
{
this.bit = bit;
}
public static EnumSet<OsuMod> valueOf(int bits)
{
EnumSet<OsuMod> result = EnumSet.noneOf(OsuMod.class);
for (OsuMod flag : OsuMod.values())
{
if ((bits & flag.bit) == flag.bit)
{
result.add(flag);
}
}
return result;
}
}
public class Score
{
public GameplayMode mode;
public int version; // 20150203
public String beatmapMd5Hash;
public String playerName;
public String replayMd5Hash;
public short numberOf300s;
public short numberOf100s;
public short numberOf50s;
public short numberOfGekis;
public short numberOfKatus;
public short numberOfMisses;
public int replayScore;
public short maxCombo;
public boolean perfectCombo;
public EnumSet<OsuMod> modsUsed;
public String unknown1;
public Date timestamp;
public int unknown2;
public int unknown3;
public int unknown4;
}
}

So ! Because the specifications are :
First : int -> number of version
Second : int -> number of collections
But ! All the integers are unsigned and little-endian. So I did this !
public static void main(String[] args) {
try {
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream("src/collection/collection.db")));
byte b1 = in.readByte();
byte b2 = in.readByte();
byte b3 = in.readByte();
byte b4 = in.readByte();
int s = 0;
s = s | (b4 & 0xff);
s = (s << 8);
s = s | (b3 & 0xff);
s = (s << 8);
s = s | (b2 & 0xff);
s = (s << 8);
s = s | (b1 & 0xff);
System.out.println("Version des collections : " + s);
b1 = in.readByte();
b2 = in.readByte();
b3 = in.readByte();
b4 = in.readByte();
s = 0;
s = s | (b4 & 0xff);
s = (s << 8);
s = s | (b3 & 0xff);
s = (s << 8);
s = s | (b2 & 0xff);
s = (s << 8);
s = s | (b1 & 0xff);
System.out.println("Nombre de collections : " +s);
} catch (Exception e) {
System.out.print("mdr fail");
}
}
I hope I helped people who are searching too.

Related

How to create an audio wave in JavaFX?

I would like to get an Audio wave plot using Chart Area in JavaFX. Unfortunately, I am not clear how to do, what are the values ​​to be extracted from the sound to assign to x-axis and y-axis?
I tried to read other posts, but I found nothing on javafx.
You can help me?
Sample Image:
Below is the code that extract the waveform .
I'm pulling out the right parameters for my scope?
How can I use it to print the graph with JavaFX?
public class SimpleWaveformExtractor implements WaveformExtractor {
private static final int DEFAULT_BUFFER_SIZE = 32768;
#Override
public double[] extract(File inputFile) {
AudioInputStream in = null;
try {
in = AudioSystem.getAudioInputStream(inputFile);
} catch (Exception e) {
System.out.println("Cannot read audio file");
return new double[0];
}
AudioFormat format = in.getFormat();
byte[] audioBytes = readBytes(in);
int[] result = null;
if (format.getSampleSizeInBits() == 16) {
int samplesLength = audioBytes.length / 2;
result = new int[samplesLength];
if (format.isBigEndian()) {
for (int i = 0; i < samplesLength; ++i) {
byte MSB = audioBytes[i * 2];
byte LSB = audioBytes[i * 2 + 1];
result[i] = MSB << 8 | (255 & LSB);
}
} else {
for (int i = 0; i < samplesLength; i += 2) {
byte LSB = audioBytes[i * 2];
byte MSB = audioBytes[i * 2 + 1];
result[i / 2] = MSB << 8 | (255 & LSB);
}
}
} else {
int samplesLength = audioBytes.length;
result = new int[samplesLength];
if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
for (int i = 0; i < samplesLength; ++i) {
result[i] = audioBytes[i];
}
} else {
for (int i = 0; i < samplesLength; ++i) {
result[i] = audioBytes[i] - 128;
}
}
}
return ArraysHelper.normalize(result);
}
private byte[] readBytes(AudioInputStream in) {
byte[] result = new byte[0];
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
try {
int bytesRead = 0;
do {
bytesRead = in.read(buffer);
result = ArrayUtils.addAll(result, buffer);
} while (bytesRead != -1);
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
this is the interface:
public interface WaveformExtractor {
double[] extract(File in);
}
This is the code that return the array of double:
private double[] extractWaveform(File file) throws IOException, UnsupportedAudioFileException {
return new WavFileExtractor().extract(file);
}

Potential use for data that contains its own hash?

I was writing some code to simulate the proof-of-work done by the Bitcoin network while generating blocks when I suddenly became curious: How can you create a datum that contains it's own hash?
Just for fun, I wrote a program that attempts to create data that contains it's own hash. 4 random bytes are generated, then a nonce is added at the end and the whole value is hashed with CRC32. The nonce in incremented and the process repeats until the program finds a hash that matches the original 4 bytes.
Note: The nonce can increase indefinitely.
Here's an example of the output after approx 1,980,000,000 attempts:
Found a match!
Data: 7a73a2d4ab833876
Original hash: 7a73a2d4 new hash: 7a73a2d4
Is there a potential use for this?
package selfhash;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
/**
*
* #author dylan
*/
public class SelfHash {
static byte[] data;
static byte[] hash = new byte[4];
public static void main(String[] args) {
// TODO code application logic here
SecureRandom random = new SecureRandom();
random.nextBytes(hash);
data = new byte[hash.length + 1];
System.arraycopy(hash, 0, data, 0, hash.length);
long c = 0;
while (true) {
recalculateData();
byte[] dataHash = crc32AsByteArray(data);
if (c % 10000000 == 0) {
System.out.println("Calculated " + c + " hashes");
System.out.println("Data: " + byteArrayToHex(data));
System.out.println("Original hash: " + byteArrayToHex(hash) + " new hash: " + byteArrayToHex(dataHash));
}
if (Arrays.equals(hash, dataHash)) {
System.out.println("Found a match!");
System.out.println("Data: " + byteArrayToHex(data));
System.out.println("Original hash: " + byteArrayToHex(hash) + " new hash: " + byteArrayToHex(dataHash));
break;
}
c++;
}
}
public static void recalculateData() {
int position = hash.length;
while (true) {
int valueAtPosition = unsignedToBytes(data[position]);
if (valueAtPosition == 255) {
//increase size of data
if (position == data.length-1) {
byte[] newData = new byte[data.length + 1];
System.arraycopy(data, 0, newData, 0, data.length);
data = newData;
}
data[position] = (byte) (0);
position++;
} else {
data[position] = (byte) (valueAtPosition + 1);
break;
}
}
}
public static byte[] hexToByteArray(String hexString) {
int len = hexString.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ Character.digit(hexString.charAt(i + 1), 16));
}
return data;
}
private static final char[] BYTE2HEX = ("000102030405060708090A0B0C0D0E0F"
+ "101112131415161718191A1B1C1D1E1F"
+ "202122232425262728292A2B2C2D2E2F"
+ "303132333435363738393A3B3C3D3E3F"
+ "404142434445464748494A4B4C4D4E4F"
+ "505152535455565758595A5B5C5D5E5F"
+ "606162636465666768696A6B6C6D6E6F"
+ "707172737475767778797A7B7C7D7E7F"
+ "808182838485868788898A8B8C8D8E8F"
+ "909192939495969798999A9B9C9D9E9F"
+ "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"
+ "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"
+ "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"
+ "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"
+ "E0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"
+ "F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF").toLowerCase().toCharArray();
;
public static String byteArrayToHex(byte[] bytes) {
final int len = bytes.length;
final char[] chars = new char[len << 1];
int hexIndex;
int idx = 0;
int ofs = 0;
while (ofs < len) {
hexIndex = (bytes[ofs++] & 0xFF) << 1;
chars[idx++] = BYTE2HEX[hexIndex++];
chars[idx++] = BYTE2HEX[hexIndex];
}
return new String(chars);
}
public static String sha256AsHexString(byte[] bytes) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return byteArrayToHex(digest.digest(bytes));
} catch (Exception e) {
throw new Error(e);
}
}
public static byte[] sha256AsByteArray(byte[] bytes) {
try {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
return digest.digest(bytes);
} catch (Exception e) {
throw new Error(e);
}
}
public static byte[] crc32AsByteArray(byte[] bytes) {
Checksum checksum = new CRC32();
checksum.update(bytes, 0, bytes.length);
long value = checksum.getValue();
byte[] resultExcess = ByteBuffer.allocate(8).putLong(value).array();
byte[] result = new byte[4];
System.arraycopy(resultExcess, 4, result, 0, 4);
return result;
}
public static int unsignedToBytes(byte b) {
return b & 0xFF;
}
}
I can't think of a use.
CRC's are linear, and so the equations can be solved very fast to get the second four bytes. You don't need two billion trials to find it. See spoof.c.

Finding time difference between two audio spikes? [duplicate]

How can I detect silence when recording operation is started in Java? What is PCM data? How can I calculate PCM data in Java?
I found the solution :
package bemukan.voiceRecognition.speechToText;
import javax.sound.sampled.*;
import java.io.*;
public class RecordAudio {
private File audioFile;
protected boolean running;
private ByteArrayOutputStream out;
private AudioInputStream inputStream;
final static float MAX_8_BITS_SIGNED = Byte.MAX_VALUE;
final static float MAX_8_BITS_UNSIGNED = 0xff;
final static float MAX_16_BITS_SIGNED = Short.MAX_VALUE;
final static float MAX_16_BITS_UNSIGNED = 0xffff;
private AudioFormat format;
private float level;
private int frameSize;
public RecordAudio(){
getFormat();
}
private AudioFormat getFormat() {
File file = new File("src/Facebook/1.wav");
AudioInputStream stream;
try {
stream = AudioSystem.getAudioInputStream(file);
format=stream.getFormat();
frameSize=stream.getFormat().getFrameSize();
return stream.getFormat();
} catch (UnsupportedAudioFileException e) {
} catch (IOException e) {
}
return null;
}
public void stopAudio() {
running = false;
}
public void recordAudio() {
try {
final AudioFormat format = getFormat();
DataLine.Info info = new DataLine.Info(
TargetDataLine.class, format);
final TargetDataLine line = (TargetDataLine)
AudioSystem.getLine(info);
line.open(format);
line.start();
Runnable runner = new Runnable() {
int bufferSize = (int) format.getSampleRate()
* format.getFrameSize();
byte buffer[] = new byte[bufferSize];
public void run() {
int readPoint = 0;
out = new ByteArrayOutputStream();
running = true;
int sum=0;
while (running) {
int count =
line.read(buffer, 0, buffer.length);
calculateLevel(buffer,0,0);
System.out.println(level);
if (count > 0) {
out.write(buffer, 0, count);
}
}
line.stop();
}
};
Thread captureThread = new Thread(runner);
captureThread.start();
} catch (LineUnavailableException e) {
System.err.println("Line unavailable: " + e);
System.exit(-2);
}
}
public File getAudioFile() {
byte[] audio = out.toByteArray();
InputStream input = new ByteArrayInputStream(audio);
try {
final AudioFormat format = getFormat();
final AudioInputStream ais =
new AudioInputStream(input, format,
audio.length / format.getFrameSize());
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("temp.wav"));
input.close();
System.out.println("New file created!");
} catch (IOException e) {
System.out.println(e.getMessage());
}
return new File("temp.wav");
}
private void calculateLevel (byte[] buffer,
int readPoint,
int leftOver) {
int max = 0;
boolean use16Bit = (format.getSampleSizeInBits() == 16);
boolean signed = (format.getEncoding() ==
AudioFormat.Encoding.PCM_SIGNED);
boolean bigEndian = (format.isBigEndian());
if (use16Bit) {
for (int i=readPoint; i<buffer.length-leftOver; i+=2) {
int value = 0;
// deal with endianness
int hiByte = (bigEndian ? buffer[i] : buffer[i+1]);
int loByte = (bigEndian ? buffer[i+1] : buffer [i]);
if (signed) {
short shortVal = (short) hiByte;
shortVal = (short) ((shortVal << 8) | (byte) loByte);
value = shortVal;
} else {
value = (hiByte << 8) | loByte;
}
max = Math.max(max, value);
} // for
} else {
// 8 bit - no endianness issues, just sign
for (int i=readPoint; i<buffer.length-leftOver; i++) {
int value = 0;
if (signed) {
value = buffer [i];
} else {
short shortVal = 0;
shortVal = (short) (shortVal | buffer [i]);
value = shortVal;
}
max = Math.max (max, value);
} // for
} // 8 bit
// express max as float of 0.0 to 1.0 of max value
// of 8 or 16 bits (signed or unsigned)
if (signed) {
if (use16Bit) { level = (float) max / MAX_16_BITS_SIGNED; }
else { level = (float) max / MAX_8_BITS_SIGNED; }
} else {
if (use16Bit) { level = (float) max / MAX_16_BITS_UNSIGNED; }
else { level = (float) max / MAX_8_BITS_UNSIGNED; }
}
} // calculateLevel
}
How can I detect silence when recording operation is started in Java?
Calculate the dB or RMS value for a group of sound frames and decide at what level it is considered to be 'silence'.
What is PCM data?
Data that is in Pulse-code modulation format.
How can I calculate PCM data in Java?
I do not understand that question. But guessing it has something to do with the speech-recognition tag, I have some bad news. This might theoretically be done using the Java Speech API. But there are apparently no 'speech to text' implementations available for the API (only 'text to speech').
I have to calculate rms for speech-recognition project. But I do not know how can I calculate in Java.
For a single channel that is represented by signal sizes in a double ranging from -1 to 1, you might use this method.
/** Computes the RMS volume of a group of signal sizes ranging from -1 to 1. */
public double volumeRMS(double[] raw) {
double sum = 0d;
if (raw.length==0) {
return sum;
} else {
for (int ii=0; ii<raw.length; ii++) {
sum += raw[ii];
}
}
double average = sum/raw.length;
double sumMeanSquare = 0d;
for (int ii=0; ii<raw.length; ii++) {
sumMeanSquare += Math.pow(raw[ii]-average,2d);
}
double averageMeanSquare = sumMeanSquare/raw.length;
double rootMeanSquare = Math.sqrt(averageMeanSquare);
return rootMeanSquare;
}
There is a byte buffer to save input values from the line, and what I should have to do with this buffer?
If using the volumeRMS(double[]) method, convert the byte values to an array of double values ranging from -1 to 1. ;)
You need to catch the value like a number silence is zero or near
Please adapt your code to your requirement!!!
In this case a variable named UMBRAL (Threshold in spanish)...
Suppose that you have access to WAV file like bytes ByteHeader...
private Integer Byte2PosIntBig(byte Byte24, byte Byte16, byte Byte08, byte Byte00) {
return new Integer (
((Byte24) << 24)|
((Byte16 & 0xFF) << 16)|
((Byte08 & 0xFF) << 8)|
((Byte00 & 0xFF) << 0));
}
Before ....
RandomAccessFile RAFSource = new RandomAccessFile("your old file wav", "r");
Begins here...
int PSData = 44;
byte[] Bytes = new byte[4];
byte[] ByteHeader = new byte[44];
RAFSource.seek(0);
RAFSource.read(ByteHeader);
int WavSize = Byte2PosIntBig(ByteHeader[43],ByteHeader[42],ByteHeader[41],ByteHeader[40]);
int NumBits = Byte2PosIntBig(ByteHeader[35],ByteHeader[34]);
int NumByte = NumBits/8;
for (int i = PSData;i < PSData+WavSize;i+=NumByte) {
int WavSample = 0;
int WavResultI =0;
int WavResultO = 0;
if (NumByte == 2) {
RAFSource.seek(i);
Bytes[0] = RAFSource.readByte();
Bytes[1] = RAFSource.readByte();
WavSample = (int)(((Bytes[1]) << 8)|((Bytes[0] & 0xFF) << 0));
if (Math.abs(WavSample) < UMBRAL) {
//SILENCE DETECTED!!!
}
} else {
RAFSource.seek(i);
WavSample = (short)(RAFSource.readByte() & 0xFF);
short sSamT = (short)WavSample;
sSamT += 128;
double dSamD = (double)sSamT*Multiplier;
if ((double)sSamT < UMBRAL) {
//SILENCE DETECTED!!!
}
}

google authenticator implementation java android

i building an Android application that must have an Google authenticator code(Password) to access to it.
the problem that i generate the serial code of 16 characters but when i try to write the validation code the application told me always that is wrong validation code... the time of the phone and the computer are the same so i donßt know why i does not work ...
here some code that i used :
`
//Base32.java
private static final Base32 INSTANCE =
new Base32("ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"); // RFC 4668/3548
static Base32 getInstance() {
return INSTANCE;
}
// 32 alpha-numeric characters.
private String ALPHABET;
private char[] DIGITS;
private int MASK;
private int SHIFT;
private HashMap<Character, Integer> CHAR_MAP;
static final String SEPARATOR = "-";
protected Base32(String alphabet) {
this.ALPHABET = alphabet;
DIGITS = ALPHABET.toCharArray();
MASK = DIGITS.length - 1;
SHIFT = Integer.numberOfTrailingZeros(DIGITS.length);
CHAR_MAP = new HashMap<Character, Integer>();
for (int i = 0; i < DIGITS.length; i++) {
CHAR_MAP.put(DIGITS[i], i);
}
}
public static byte[] decode(String encoded) throws DecodingException {
return getInstance().decodeInternal(encoded);
}
protected byte[] decodeInternal(String encoded) throws DecodingException {
// Remove whitespace and separators
encoded = encoded.trim().replaceAll(SEPARATOR, "").replaceAll(" ", "");
// Canonicalize to all upper case
encoded = encoded.toUpperCase();
if (encoded.length() == 0) {
return new byte[0];
}
int encodedLength = encoded.length();
int outLength = encodedLength * SHIFT / 8;
byte[] result = new byte[outLength];
int buffer = 0;
int next = 0;
int bitsLeft = 0;
for (char c : encoded.toCharArray()) {
if (!CHAR_MAP.containsKey(c)) {
throw new DecodingException("Illegal character: " + c);
}
buffer <<= SHIFT;
buffer |= CHAR_MAP.get(c) & MASK;
bitsLeft += SHIFT;
if (bitsLeft >= 8) {
result[next++] = (byte) (buffer >> (bitsLeft - 8));
bitsLeft -= 8;
}
}
// We'll ignore leftover bits for now.
//
// if (next != outLength || bitsLeft >= SHIFT) {
// throw new DecodingException("Bits left: " + bitsLeft);
// }
return result;
}
public static String encode(byte[] data) {
return getInstance().encodeInternal(data);
}
protected String encodeInternal(byte[] data) {
if (data.length == 0) {
return "";
}
// SHIFT is the number of bits per output character, so the length of the
// output is the length of the input multiplied by 8/SHIFT, rounded up.
if (data.length >= (1 << 28)) {
// The computation below will fail, so don't do it.
throw new IllegalArgumentException();
}
int outputLength = (data.length * 8 + SHIFT - 1) / SHIFT;
StringBuilder result = new StringBuilder(outputLength);
int buffer = data[0];
int next = 1;
int bitsLeft = 8;
while (bitsLeft > 0 || next < data.length) {
if (bitsLeft < SHIFT) {
if (next < data.length) {
buffer <<= 8;
buffer |= (data[next++] & 0xff);
bitsLeft += 8;
} else {
int pad = SHIFT - bitsLeft;
buffer <<= pad;
bitsLeft += pad;
}
}
int index = MASK & (buffer >> (bitsLeft - SHIFT));
bitsLeft -= SHIFT;
result.append(DIGITS[index]);
}
return result.toString();
}
#Override
// enforce that this class is a singleton
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
static class DecodingException extends Exception {
public DecodingException(String message) {
super(message);
}
}
}`
//CheckCode.java
...public void onClick(View v) {
String codeDigited=ed.getText().toString();
Log.d("codeDigited", codeDigited);
try {
if(check_code(codeDigited, 0, 0)==true){
Intent step = new Intent(this, GoogleAuthenticator.class);
startActivity(step);
}else{
info.setText("passwords doesn't match! oh noes!");
}
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (DecodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private static boolean check_code(String secret, long code, long t)
throws NoSuchAlgorithmException, InvalidKeyException, DecodingException {
//Base32 codec = new Base32(secret);
byte[] decodedKey = Base32.decode(secret);
// Window is used to check codes generated in the near past.
// You can use this value to tune how far you're willing to go.
int window = 30;
for (int i = -window; i <= window; ++i) {
long hash = verify_code(decodedKey, t + i);
if (hash == code) {
System.out.println("right");
return true;
}
}
System.out.println("OOOOOOOps codec.decode(secret): "+decodedKey.toString());
// The validation code is invalid.
return false;
}
private static int verify_code(byte[] key, long t)
throws NoSuchAlgorithmException, InvalidKeyException {
byte[] data = new byte[8];
long value = t;
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
SecretKeySpec signKey = new SecretKeySpec(key, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signKey);
byte[] hash = mac.doFinal(data);
int offset = hash[20 - 1] & 0xF;
// We're using a long because Java hasn't got unsigned int.
long truncatedHash = 0;
for (int i = 0; i < 4; ++i) {
truncatedHash <<= 8;
// We are dealing with signed bytes:
// we just keep the first byte.
truncatedHash |= (hash[offset + i] & 0xFF);
}
truncatedHash &= 0x7FFFFFFF;
truncatedHash %= 1000000;
return (int) truncatedHash;
}
the codeDigited is the validation code i took from Google authentificator App
but i don know why the code does not work

Detect silence when recording

How can I detect silence when recording operation is started in Java? What is PCM data? How can I calculate PCM data in Java?
I found the solution :
package bemukan.voiceRecognition.speechToText;
import javax.sound.sampled.*;
import java.io.*;
public class RecordAudio {
private File audioFile;
protected boolean running;
private ByteArrayOutputStream out;
private AudioInputStream inputStream;
final static float MAX_8_BITS_SIGNED = Byte.MAX_VALUE;
final static float MAX_8_BITS_UNSIGNED = 0xff;
final static float MAX_16_BITS_SIGNED = Short.MAX_VALUE;
final static float MAX_16_BITS_UNSIGNED = 0xffff;
private AudioFormat format;
private float level;
private int frameSize;
public RecordAudio(){
getFormat();
}
private AudioFormat getFormat() {
File file = new File("src/Facebook/1.wav");
AudioInputStream stream;
try {
stream = AudioSystem.getAudioInputStream(file);
format=stream.getFormat();
frameSize=stream.getFormat().getFrameSize();
return stream.getFormat();
} catch (UnsupportedAudioFileException e) {
} catch (IOException e) {
}
return null;
}
public void stopAudio() {
running = false;
}
public void recordAudio() {
try {
final AudioFormat format = getFormat();
DataLine.Info info = new DataLine.Info(
TargetDataLine.class, format);
final TargetDataLine line = (TargetDataLine)
AudioSystem.getLine(info);
line.open(format);
line.start();
Runnable runner = new Runnable() {
int bufferSize = (int) format.getSampleRate()
* format.getFrameSize();
byte buffer[] = new byte[bufferSize];
public void run() {
int readPoint = 0;
out = new ByteArrayOutputStream();
running = true;
int sum=0;
while (running) {
int count =
line.read(buffer, 0, buffer.length);
calculateLevel(buffer,0,0);
System.out.println(level);
if (count > 0) {
out.write(buffer, 0, count);
}
}
line.stop();
}
};
Thread captureThread = new Thread(runner);
captureThread.start();
} catch (LineUnavailableException e) {
System.err.println("Line unavailable: " + e);
System.exit(-2);
}
}
public File getAudioFile() {
byte[] audio = out.toByteArray();
InputStream input = new ByteArrayInputStream(audio);
try {
final AudioFormat format = getFormat();
final AudioInputStream ais =
new AudioInputStream(input, format,
audio.length / format.getFrameSize());
AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("temp.wav"));
input.close();
System.out.println("New file created!");
} catch (IOException e) {
System.out.println(e.getMessage());
}
return new File("temp.wav");
}
private void calculateLevel (byte[] buffer,
int readPoint,
int leftOver) {
int max = 0;
boolean use16Bit = (format.getSampleSizeInBits() == 16);
boolean signed = (format.getEncoding() ==
AudioFormat.Encoding.PCM_SIGNED);
boolean bigEndian = (format.isBigEndian());
if (use16Bit) {
for (int i=readPoint; i<buffer.length-leftOver; i+=2) {
int value = 0;
// deal with endianness
int hiByte = (bigEndian ? buffer[i] : buffer[i+1]);
int loByte = (bigEndian ? buffer[i+1] : buffer [i]);
if (signed) {
short shortVal = (short) hiByte;
shortVal = (short) ((shortVal << 8) | (byte) loByte);
value = shortVal;
} else {
value = (hiByte << 8) | loByte;
}
max = Math.max(max, value);
} // for
} else {
// 8 bit - no endianness issues, just sign
for (int i=readPoint; i<buffer.length-leftOver; i++) {
int value = 0;
if (signed) {
value = buffer [i];
} else {
short shortVal = 0;
shortVal = (short) (shortVal | buffer [i]);
value = shortVal;
}
max = Math.max (max, value);
} // for
} // 8 bit
// express max as float of 0.0 to 1.0 of max value
// of 8 or 16 bits (signed or unsigned)
if (signed) {
if (use16Bit) { level = (float) max / MAX_16_BITS_SIGNED; }
else { level = (float) max / MAX_8_BITS_SIGNED; }
} else {
if (use16Bit) { level = (float) max / MAX_16_BITS_UNSIGNED; }
else { level = (float) max / MAX_8_BITS_UNSIGNED; }
}
} // calculateLevel
}
How can I detect silence when recording operation is started in Java?
Calculate the dB or RMS value for a group of sound frames and decide at what level it is considered to be 'silence'.
What is PCM data?
Data that is in Pulse-code modulation format.
How can I calculate PCM data in Java?
I do not understand that question. But guessing it has something to do with the speech-recognition tag, I have some bad news. This might theoretically be done using the Java Speech API. But there are apparently no 'speech to text' implementations available for the API (only 'text to speech').
I have to calculate rms for speech-recognition project. But I do not know how can I calculate in Java.
For a single channel that is represented by signal sizes in a double ranging from -1 to 1, you might use this method.
/** Computes the RMS volume of a group of signal sizes ranging from -1 to 1. */
public double volumeRMS(double[] raw) {
double sum = 0d;
if (raw.length==0) {
return sum;
} else {
for (int ii=0; ii<raw.length; ii++) {
sum += raw[ii];
}
}
double average = sum/raw.length;
double sumMeanSquare = 0d;
for (int ii=0; ii<raw.length; ii++) {
sumMeanSquare += Math.pow(raw[ii]-average,2d);
}
double averageMeanSquare = sumMeanSquare/raw.length;
double rootMeanSquare = Math.sqrt(averageMeanSquare);
return rootMeanSquare;
}
There is a byte buffer to save input values from the line, and what I should have to do with this buffer?
If using the volumeRMS(double[]) method, convert the byte values to an array of double values ranging from -1 to 1. ;)
You need to catch the value like a number silence is zero or near
Please adapt your code to your requirement!!!
In this case a variable named UMBRAL (Threshold in spanish)...
Suppose that you have access to WAV file like bytes ByteHeader...
private Integer Byte2PosIntBig(byte Byte24, byte Byte16, byte Byte08, byte Byte00) {
return new Integer (
((Byte24) << 24)|
((Byte16 & 0xFF) << 16)|
((Byte08 & 0xFF) << 8)|
((Byte00 & 0xFF) << 0));
}
Before ....
RandomAccessFile RAFSource = new RandomAccessFile("your old file wav", "r");
Begins here...
int PSData = 44;
byte[] Bytes = new byte[4];
byte[] ByteHeader = new byte[44];
RAFSource.seek(0);
RAFSource.read(ByteHeader);
int WavSize = Byte2PosIntBig(ByteHeader[43],ByteHeader[42],ByteHeader[41],ByteHeader[40]);
int NumBits = Byte2PosIntBig(ByteHeader[35],ByteHeader[34]);
int NumByte = NumBits/8;
for (int i = PSData;i < PSData+WavSize;i+=NumByte) {
int WavSample = 0;
int WavResultI =0;
int WavResultO = 0;
if (NumByte == 2) {
RAFSource.seek(i);
Bytes[0] = RAFSource.readByte();
Bytes[1] = RAFSource.readByte();
WavSample = (int)(((Bytes[1]) << 8)|((Bytes[0] & 0xFF) << 0));
if (Math.abs(WavSample) < UMBRAL) {
//SILENCE DETECTED!!!
}
} else {
RAFSource.seek(i);
WavSample = (short)(RAFSource.readByte() & 0xFF);
short sSamT = (short)WavSample;
sSamT += 128;
double dSamD = (double)sSamT*Multiplier;
if ((double)sSamT < UMBRAL) {
//SILENCE DETECTED!!!
}
}

Categories

Resources