package us.achromaticmetaphor.imcktg;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class MorseIMelody extends ToneGenerator {
private static final int defaultWordsPerMinute = 20;
private static final int defaultOctave = IMelodyFormat.defaultOctave;
private static final String defaultTone = "a";
public static void main(String [] argV) throws IOException {
(new MorseIMelody(0)).writeIMelody((OutputStream) System.out, argV[0]);
}
public void writeIMelody(OutputStream out, String s) throws IOException {
PrintStream pout = new PrintStream(out);
writeIMelody(pout, s);
if (pout.checkError())
throw new IOException();
}
public void writeIMelody(PrintStream out, String s) {
writeIMelodyHeader(out, s);
morseMelody(out, Morse.morse(s));
writeIMelodyFooter(out);
}
private void writeIMelodyHeader(PrintStream out, String s) {
IMelodyFormat.writeRequiredHeaders(out);
IMelodyFormat.writeNameHeaderMangled(out, s);
IMelodyFormat.writeBeatHeader(out, beat);
IMelodyFormat.writeStyleHeader(out, IMelodyFormat.styleContinuous);
IMelodyFormat.writeVolumeHeader(out, IMelodyFormat.volumeMax);
}
private static void writeIMelodyFooter(PrintStream out) {
IMelodyFormat.writeRequiredFooters(out);
}
private final Map<Character, String> tones;
private final int beat;
private final int repeatCount;
public MorseIMelody(int repeatCount) {
this(defaultWordsPerMinute, repeatCount);
}
public MorseIMelody(int wpm, int repeatCount) {
this(defaultOctave, defaultTone, wpm, repeatCount);
}
public MorseIMelody(int octave, String tone, int wpm, int repeatCount) {
if (wpm < 1 || wpm > 144)
throw new IllegalArgumentException("invalid wpm : " + wpm);
if (repeatCount < 0)
throw new IllegalArgumentException("invalid repeat count : " + repeatCount);
this.repeatCount = repeatCount;
final int duration = wpm <= 36 ? 3 : wpm <= 72 ? 4 : 5;
// The format defines BEAT as beats per minute, at common (4/4) time.
beat = wpm * Morse.unitsPerWord * 4 / (1 << duration);
final String note = IMelodyFormat.note(octave, tone);
final String rest = IMelodyFormat.rest;
final String dot_duration = IMelodyFormat.duration(duration);
final String dash_duration = IMelodyFormat.durationDotted(duration - 1);
final String pause_duration = dot_duration;
final String double_pause_duration = IMelodyFormat.duration(duration - 1);
final String dot = note + dot_duration;
final String dash = note + dash_duration;
final String pause = rest + pause_duration;
final String double_pause = rest + double_pause_duration;
Map<Character, String> m = new HashMap<Character, String>();
m.put(Morse.dotChar, dot + pause);
m.put(Morse.dashChar, dash + pause);
m.put(Morse.pauseChar, double_pause);
tones = Collections.unmodifiableMap(m);
}
private void morseMelody(PrintStream out, Iterable<String> mcs) {
IMelodyFormat.writeBeginMelody(out);
if (repeatCount > 0)
IMelodyFormat.beginRepeatBlock(out);
for (String s : mcs)
morseMelody(out, s);
if (repeatCount > 0)
IMelodyFormat.endRepeatBlock(out, repeatCount);
IMelodyFormat.writeEndMelody(out);
}
private void morseMelody(PrintStream out, String s) {
for (int i = 0; i < s.length(); i++)
out.print(tones.get(s.charAt(i)));
out.print(tones.get(Morse.pauseChar));
out.print(IMelodyFormat.lineContinuation);
}
@Override
public void writeTone(OutputStream out, String s) throws IOException {
writeIMelody(out, s);
}
@Override
public String filenameExt() {
return ".imy";
}
@Override
public String filenameTypePrefix() {
return "iMelody:" + beat + ":" + tones.get(Morse.dotChar) + ":" + repeatCount + ":";
}
}