package org.herac.tuxguitar.io.tef;
import java.io.IOException;
import java.io.InputStream;
import org.apache.log4j.Logger;
import org.herac.tuxguitar.gui.editors.chord.ChordSelector;
import org.herac.tuxguitar.io.tef.base.TEChord;
import org.herac.tuxguitar.io.tef.base.TEComponentChord;
import org.herac.tuxguitar.io.tef.base.TEComponentNote;
import org.herac.tuxguitar.io.tef.base.TEInfo;
import org.herac.tuxguitar.io.tef.base.TEPercussion;
import org.herac.tuxguitar.io.tef.base.TERepeat;
import org.herac.tuxguitar.io.tef.base.TERhythm;
import org.herac.tuxguitar.io.tef.base.TESong;
import org.herac.tuxguitar.io.tef.base.TETempo;
import org.herac.tuxguitar.io.tef.base.TEText;
import org.herac.tuxguitar.io.tef.base.TETimeSignature;
import org.herac.tuxguitar.io.tef.base.TETimeSignatureChange;
import org.herac.tuxguitar.io.tef.base.TETrack;
public class TEInputStream {
/** The Logger for this class. */
public static final transient Logger LOG = Logger
.getLogger(TEInputStream.class);
private TESong song;
private InputStream stream;
public TEInputStream(InputStream stream) {
this.stream = stream;
}
protected void close() {
try {
this.stream.close();
} catch (IOException e) {
LOG.error(e);
}
}
protected int readByte() {
try {
return this.stream.read();
} catch (IOException e) {
LOG.error(e);
}
return 0;
}
// -----------------------------------------------------------------------------//
// -----------------------------------------------------------------------------//
// -----------------------------------------------------------------------------//
protected byte[] readBytes(int length) {
byte[] bytes = new byte[length];
try {
this.stream.read(bytes);
} catch (IOException e) {
LOG.error(e);
}
return bytes;
}
private void readChords() {
for (int i = 0; i < this.song.getChords().length; i++) {
byte[] strings = this.readBytes(14);
byte[] name = this.readBytes(16);
this.song.setChord(i, new TEChord(strings, new String(name)));
this.skip(2);
}
}
private void readComponents() {
int tsSize = ((256 * this.song.getTimeSignature().getNumerator()) / this.song
.getTimeSignature().getDenominator());
int tsMove = 0;
int mIndex = 0;
int mData = 0;
int count = this.readShort();
for (int i = 0; i < count; i++) {
byte[] data = this.readBytes(6);
int location = ((data[0] & 0xff) + (256 * (mData + (data[1] & 0xff))));
if ((location / (tsSize * this.song.getStrings())) < mIndex) {
mData += 256;
location = ((data[0] & 0xff) + (256 * (mData + (data[1] & 0xff))));
}
int position = (location % tsSize);
int string = ((location / tsSize) % this.song.getStrings());
int measure = (location / (tsSize * this.song.getStrings()));
tsMove = (mIndex == measure) ? tsMove : 0;
position -= tsMove;
if (((data[2] & 0xff) & 0x1f) > 0 && ((data[2] & 0xff) & 0x1f) <= 25) {
int duration = (data[3] & 0xf);
int dynamic = (data[3] >> 4);
int effect = data[4];
int fret = (((data[2] & 0xff) & 0x1f) - 1);
if ((((data[2] & 0xff) >> 5) & 0x01) != 0) {
fret += (data[5] & 0xff);
}
this.song.getComponents().add(
new TEComponentNote(position, measure, string, fret, duration,
dynamic, effect));
} else if (((data[2] & 0xff) & 0x1f) == 27) {
// TIME SIGNATURE CHANGE
tsMove = (4 * (data[3] & 0xff));
int denominator = (int) ((Math.pow(2, ((data[2] & 0xff) >> 5)) / 2));
int numerator = ((((tsSize / 4) - (data[3] & 0xff)) * denominator) / 64);
this.song.addTimeSignatureChange(new TETimeSignatureChange(measure,
new TETimeSignature(numerator, denominator)));
} else if (((data[2] & 0xff) & 0x1f) == 28 && (data[2] & 0x20) != 0) {
// SCALE DIAGRAM
} else if (((data[2] & 0xff) & 0x1f) == 28) {
// CHORD
this.song.getComponents().add(
new TEComponentChord(position, measure, string, data[3]));
} else if (((data[2] & 0xff) & 0x1f) == 29) {
// SCALE DIAGRAM | SPECIAL CHAR | SYNCOPATION CHANGE
} else if (((data[2] & 0xff) & 0x1f) == 30) {
// TEMPO CHANGE | VOICE CHANGE | DRUM EVENT | CRESCENDO ACCENT |
// REPEAT/ENDING
}
mIndex = measure;
}
}
private void readInfo() {
byte[] info = this.readBytes(200);
int offset = 0;
String strings[] = new String[3];
for (int i = 0; i < strings.length; i++) {
int length = 0;
while ((offset + length) < info.length && info[(offset + length)] != 0) {
length++;
}
strings[i] = new String(info, offset, length);
offset += length + 1;
}
this.song.setInfo(new TEInfo(strings[0], strings[1], strings[2]));
}
private void readNotes(boolean notes) {
if (notes) {
int length = this.readShort();
this.song.getInfo().setNotes(
new String(this.readBytes(length), 1, (length - 1)));
}
}
private void readPercussions() {
if (this.song.getPercussions().length > 0) {
for (int i = 0; i < this.song.getPercussions().length; i++) {
this.skip(96);
String name = new String(this.readBytes(8));
this.skip(1);
int volume = (this.readByte() & 0xff);
this.song.setPercussion(i, new TEPercussion(name, volume));
this.skip(2);
}
this.skip(this.song.getMeasures());
}
}
private void readRepeats() {
for (int i = 0; i < this.song.getRepeats().length; i++) {
int data1 = this.readByte();
int data2 = this.readByte();
this.song.setRepeat(i, new TERepeat(data1, data2));
}
}
private void readRhythms() {
if (this.song.getRhythms().length > 0) {
for (int i = 0; i < this.song.getRhythms().length; i++) {
this.skip(96);
String name = new String(this.readBytes(8));
this.skip(1);
int volume = (this.readByte() & 0xff);
int instrument = (this.readByte() & 0xff);
this.song.setRhythm(i, new TERhythm(name, volume, instrument));
this.skip(1);
}
this.skip(this.song.getMeasures());
}
}
protected int readShort() {
try {
byte[] b = new byte[2];
this.stream.read(b);
return ((b[1] & 0xff) << 8) | (b[0] & 0xff);
} catch (IOException e) {
LOG.error(e);
}
return 0;
}
public TESong readSong() {
this.song = new TESong();
this.readInfo();
this.song.setMeasures((this.readByte() & 0xff));
this.skip(1);
this.readTimeSignature();
this.skip(15);
this.readTempo();
this.song.setRepeats((this.readByte() & 0xff));
this.skip(5);
this.song.setTexts((this.readByte() & 0xff));
this.skip(5);
this.song.setPercussions((this.readByte() & 0xff));
this.song.setRhythms((this.readByte() & 0xff));
this.song.setChords((this.readByte() & 0xff));
this.skip(1);
boolean notes = ((this.readByte() & 0xff) > 0);
this.skip(1);
this.song.setStrings((this.readByte() & 0xff));
this.song.setTracks((this.readByte() & 0xff) + 1);
this.skip(14);
this.readComponents();
this.readRepeats();
this.readTexts();
this.readPercussions();
this.readChords();
this.readRhythms();
this.readNotes(notes);
this.readTracks();
this.close();
return this.song;
}
private void readTempo() {
int value = this.readShort();
this.song.setTempo(new TETempo(value));
}
private void readTexts() {
for (int i = 0; i < this.song.getTexts().length; i++) {
int length = this.readByte();
byte[] text = this.readBytes(length);
this.song.setText(i, new TEText(new String(text, 1, (length - 1))));
this.skip(1);
}
}
private void readTimeSignature() {
int numerator = this.readByte();
this.skip(1);
int denominator = this.readByte();
this.song.setTimeSignature(new TETimeSignature(numerator, denominator));
}
private void readTracks() {
for (int i = 0; i < this.song.getTracks().length; i++) {
int[] strings = new int[this.readByte()];
this.skip(5);
int type = this.readByte();
this.skip(1);
int instrument = this.readByte();
this.skip(3);
int capo = this.readByte();
this.skip(1);
int clefType = this.readByte();
int clefNumber = this.readByte();
this.skip(1);
int pan = this.readByte();
int volume = this.readByte();
int flags = this.readByte();
for (int string = 0; string < strings.length; string++) {
strings[string] = (this.readByte() & 0xff);
}
this.skip(12 - strings.length);
String name = new String(this.readBytes(16));
this.song.setTrack(i, new TETrack((type == 98), instrument, capo,
clefType, clefNumber, pan, volume, flags, strings, name));
this.skip(2);
}
}
protected void skip(int count) {
for (int i = 0; i < count; i++) {
readByte();
}
}
}