296 lines
8.5 KiB
Java
296 lines
8.5 KiB
Java
package xyz.suruatoel.tuxguitar.drumsheets;
|
|
|
|
|
|
import java.io.File;
|
|
import java.io.FileInputStream;
|
|
import java.io.FileOutputStream;
|
|
import java.io.IOException;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.util.ArrayList;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.function.Consumer;
|
|
|
|
import org.herac.tuxguitar.graphics.control.TGFactoryImpl;
|
|
import org.herac.tuxguitar.io.base.TGSongReader;
|
|
import org.herac.tuxguitar.io.base.TGSongReaderHandle;
|
|
import org.herac.tuxguitar.io.base.TGSongWriter;
|
|
import org.herac.tuxguitar.io.base.TGSongWriterHandle;
|
|
import org.herac.tuxguitar.io.tg.TGSongReaderImpl;
|
|
import org.herac.tuxguitar.io.tg.TGSongWriterImpl;
|
|
import org.herac.tuxguitar.song.factory.TGFactory;
|
|
import org.herac.tuxguitar.song.models.TGBeat;
|
|
import org.herac.tuxguitar.song.models.TGMeasure;
|
|
import org.herac.tuxguitar.song.models.TGNote;
|
|
import org.herac.tuxguitar.song.models.TGSong;
|
|
import org.herac.tuxguitar.song.models.TGTrack;
|
|
import org.herac.tuxguitar.song.models.TGVoice;
|
|
|
|
|
|
|
|
/**
|
|
* Application to clean drumset tracks in TuxGuitar files.
|
|
*/
|
|
public class Drumsheets {
|
|
/**
|
|
* TuxGuitar factory
|
|
*/
|
|
private TGFactory factory;
|
|
/**
|
|
* TuxGuitar song reader
|
|
*/
|
|
private TGSongReader songReader;
|
|
/**
|
|
* TuxGuitar song writer
|
|
*/
|
|
private TGSongWriter songWriter;
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Create a new drumsheet instance.
|
|
*/
|
|
public Drumsheets() {
|
|
this.factory = new TGFactoryImpl();
|
|
this.songReader = new TGSongReaderImpl();
|
|
this.songWriter = new TGSongWriterImpl();
|
|
}
|
|
|
|
|
|
/**
|
|
* Read a tg file as TuxGuitar song.
|
|
*
|
|
* @param file TG file to read
|
|
* @return TuxGuitar song
|
|
* @throws IOException Failed to read file
|
|
*/
|
|
public TGSong readSong(File file) throws IOException {
|
|
System.out.println(String.format("Reading song file: %s", file.getAbsolutePath()));
|
|
try(InputStream is = new FileInputStream(file)) {
|
|
TGSongReaderHandle songHandle = new TGSongReaderHandle();
|
|
songHandle.setFactory(this.factory);
|
|
songHandle.setInputStream(is);
|
|
|
|
this.songReader.read(songHandle);
|
|
|
|
return songHandle.getSong();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Write a TuxGuitar song as tg file.
|
|
*
|
|
* @param song TuxGuitar song to write
|
|
* @param file File to write song to
|
|
* @throws IOException Failed to write file
|
|
*/
|
|
public void writeSong(TGSong song, File file) throws IOException {
|
|
System.out.println(String.format("Writing song file: %s", file.getAbsolutePath()));
|
|
try(OutputStream os = new FileOutputStream(file)) {
|
|
TGSongWriterHandle songHandle = new TGSongWriterHandle();
|
|
songHandle.setSong(song);
|
|
songHandle.setOutputStream(os);
|
|
|
|
this.songWriter.write(songHandle);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Get all drum tracks of a TuxGuitar song.
|
|
*
|
|
* @param song TuxGuitar song to get drum tracks of
|
|
* @return List of TuxGuitar tracks
|
|
*/
|
|
public List<TGTrack> getDrumTracks(TGSong song) {
|
|
List<TGTrack> drumTracks = new ArrayList<>();
|
|
Iterator<TGTrack> it = song.getTracks();
|
|
while(it.hasNext()) {
|
|
TGTrack track = it.next();
|
|
// TODO Use a more reliable way to detect drum track
|
|
if(track.getName().equals("Drumkit")) {
|
|
drumTracks.add(track);
|
|
}
|
|
}
|
|
|
|
return drumTracks;
|
|
}
|
|
|
|
|
|
/**
|
|
* Apply all (currently hard coded) fixes for all drum tracks of a song.
|
|
*
|
|
* @param song TuxGuitar song to fix drum tracks of
|
|
*/
|
|
public void fixDrums(TGSong song) {
|
|
System.out.println("Fix drums");
|
|
for(TGTrack drumTrack : getDrumTracks(song)) {
|
|
fixDrum(drumTrack);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Apply all (currently hard coded) fixes for a drum track.
|
|
*
|
|
* @param drumTrack TuxGuitar drum track to fix
|
|
*/
|
|
public void fixDrum(TGTrack drumTrack) {
|
|
System.out.println(String.format("Fix drum track: %s", drumTrack.getName()));
|
|
|
|
// Crash cymbals
|
|
changeNoteString(drumTrack, 57, 1);
|
|
changeNoteString(drumTrack, 49, 1);
|
|
// China cymbal
|
|
changeNoteString(drumTrack, 52, 1);
|
|
// Hi-Hat
|
|
changeNoteString(drumTrack, 46, 2);
|
|
changeNoteString(drumTrack, 42, 2);
|
|
// Ride cymbal
|
|
changeNoteString(drumTrack, 51, 2);
|
|
changeNoteString(drumTrack, 53, 2);
|
|
// Snare drum
|
|
fixDrumNote(drumTrack, 38, 40);
|
|
changeNoteString(drumTrack, 40, 3);
|
|
// Toms
|
|
fixDrumNote(drumTrack, 50, 48);
|
|
changeNoteString(drumTrack, 48, 4);
|
|
fixDrumNote(drumTrack, 47, 45);
|
|
changeNoteString(drumTrack, 45, 4);
|
|
changeNoteString(drumTrack, 43, 5);
|
|
changeNoteString(drumTrack, 41, 5);
|
|
// Bass drum
|
|
changeNoteString(drumTrack, 36, 6);
|
|
}
|
|
|
|
|
|
/**
|
|
* Move a note of a track to a string.
|
|
*
|
|
* @param track TuxGuitar track to change note of
|
|
* @param note Value of note to change
|
|
* @param string String to move note to
|
|
*/
|
|
public void changeNoteString(TGTrack track, int note, int string) {
|
|
// Check if target string exists
|
|
if(string > track.stringCount()) {
|
|
System.err.println(
|
|
String.format(
|
|
"Cannot move note %d to string %d, string doas not exist",
|
|
note,
|
|
string
|
|
)
|
|
);
|
|
}
|
|
|
|
eachNote(
|
|
track,
|
|
tgNote -> {
|
|
if(tgNote.getValue() == note && tgNote.getString() != string) {
|
|
System.out.println(
|
|
String.format(
|
|
"Move note %d from string %d to %d",
|
|
tgNote.getValue(),
|
|
tgNote.getString(),
|
|
string
|
|
)
|
|
);
|
|
tgNote.setString(string);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Change a note to another note.
|
|
*
|
|
* @param track TuxGuitar track to change note of
|
|
* @param sourceNote Value of note to change
|
|
* @param targetNote Value to change note to
|
|
*/
|
|
public void fixDrumNote(TGTrack track, int sourceNote, int targetNote) {
|
|
eachNote(
|
|
track,
|
|
note -> {
|
|
if(note.getValue() == sourceNote) {
|
|
System.out.println(String.format("Change note %d to %d", sourceNote, targetNote));
|
|
note.setValue(targetNote);
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
|
|
/**
|
|
* Call a consumer for each note of a track.
|
|
*
|
|
* @param track TuxGuitar track to traverse notes of
|
|
* @param consumer Consumer to call for each note
|
|
*/
|
|
private void eachNote(TGTrack track, Consumer<TGNote> consumer) {
|
|
// Traverse all measures
|
|
Iterator<TGMeasure> measureIt = track.getMeasures();
|
|
while(measureIt.hasNext()) {
|
|
TGMeasure measure = measureIt.next();
|
|
|
|
// Traverse all beats
|
|
for(TGBeat beat : measure.getBeats()) {
|
|
// Traverse all voices
|
|
for(int v=0; v<beat.countVoices(); v++) {
|
|
TGVoice voice = beat.getVoice(v);
|
|
// Traverse all notes
|
|
for(TGNote note : voice.getNotes()) {
|
|
consumer.accept(note);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* Run the application.
|
|
*
|
|
* @param args Commandline arguments.
|
|
*/
|
|
public static void main(String[] args) {
|
|
// Parse arguments
|
|
File sourceFile;
|
|
File targetFile;
|
|
if(args.length < 1) {
|
|
System.err.println("Please specify an input file");
|
|
System.exit(1);
|
|
}
|
|
sourceFile = new File(args[0]);
|
|
if(args.length > 1) {
|
|
targetFile = new File(args[1]);
|
|
}
|
|
else {
|
|
targetFile = sourceFile;
|
|
}
|
|
|
|
// Create application instance
|
|
Drumsheets sheet = new Drumsheets();
|
|
try {
|
|
// Read file
|
|
TGSong song = sheet.readSong(sourceFile);
|
|
|
|
// Fix drumset
|
|
sheet.fixDrums(song);
|
|
|
|
// Write file
|
|
sheet.writeSong(song, targetFile);
|
|
}
|
|
catch(IOException e) {
|
|
System.err.println(e.getMessage());
|
|
System.exit(1);
|
|
}
|
|
}
|
|
|
|
}
|