RosettaCodeData/Task/Morse-code/Java/morse-code-2.java

100 lines
3.9 KiB
Java

import java.util.Map;
import java.util.stream.IntStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.SourceDataLine;
public final class MorseCode {
public static void main(String[] args) {
Map<String, String> morseCode = Map.ofEntries(
// International Morse Code, ITU standard
Map.entry("A", ".-"), Map.entry("B", "-..."), Map.entry("C", "-.-."), Map.entry("D", "-.."),
Map.entry("E", "."), Map.entry("F", "..-."), Map.entry("G", "--."), Map.entry("H", "...."),
Map.entry("I", ".."), Map.entry("J", ".---"), Map.entry("K", "-.-"), Map.entry("L", ".-.."),
Map.entry("M", "--"), Map.entry("N", "-."), Map.entry("O", "---"), Map.entry("P", ".--."),
Map.entry("Q", "--.-"), Map.entry("R", ".-."), Map.entry("S", "..."), Map.entry("T", "-"),
Map.entry("U", "..-"), Map.entry("V", "...-"), Map.entry("W", ".--"), Map.entry("X", "-..-"),
Map.entry("Y", "-.--"), Map.entry("Z", "--.."),
Map.entry("1", ".----"), Map.entry("2", "..---"), Map.entry("3", "...--"), Map.entry("4", "....-"),
Map.entry("5", "....."), Map.entry("6", "-...."), Map.entry("7", "--..."), Map.entry("8", "---.."),
Map.entry("9", "----."), Map.entry("0", "-----"),
// Generally accepted additions
Map.entry("'", ".----."), Map.entry(":", "---..."), Map.entry(",", "--..--"), Map.entry("-", "-....-"),
Map.entry("(", "-.--.-"), Map.entry(".", ".-.-.-"), Map.entry("?", "..--.."), Map.entry(";", "-.-.-."),
Map.entry("/", "-..-."), Map.entry(")", "---.."), Map.entry("=", "-...-"), Map.entry("@", ".--.-."),
Map.entry("\"", ".-..-."), Map.entry("+", ".-.-.")
);
prepareSourceDataLine();
final int frequency = 1280; // Frequency of the sound tone in Hertz
final int time = 250; // Time unit in milliseconds
// Correct pacing of the sound transmission is essential for practical use
final int dot = 1; // Time units taken for one dot
final int dash = 3; // Time units taken for one dash
final int interval = 1; // Time units interval between dots and dashes
final int letterInterval = 1; // Time units interval between letters of a word
final int wordInterval = 7; // Time units interval between words
String message = "Hello World";
for ( String letter : message.toUpperCase().split("") ) {
switch ( letter ) {
case " " -> tone(0, time * wordInterval, 0);
default -> {
String code = morseCode.get(letter);
for ( String dotDash : code.split("") ) {
switch ( dotDash ) {
case "." -> { tone(frequency, time * dot, 1); tone(0, time * interval, 0); }
case "-" -> { tone(frequency, time * dash, 1); tone(0, time * interval, 0); }
}
}
}
}
tone(0, time * letterInterval, 0);
}
}
private static void tone(double frequency, int duration, int volume) {
sourceDataLine.start();
IntStream.range(0, 8 * duration).forEach( i -> {
final double angle = i / ( SAMPLE_RATE / frequency ) * 2 * Math.PI;
byte[] buffer = new byte[] { (byte) ( Math.sin(angle) * 127 * volume ) };
sourceDataLine.write(buffer, BYTE_OFFSET, buffer.length);
} );
sourceDataLine.drain();
sourceDataLine.stop();
}
private static void prepareSourceDataLine() {
final int sampleSizeInBits = 8;
final int numberChannels = 1;
final boolean signedData = true;
final boolean isBigEndian = false;
AudioFormat audioFormat = new AudioFormat(
SAMPLE_RATE, sampleSizeInBits, numberChannels, signedData, isBigEndian);
try {
sourceDataLine = AudioSystem.getSourceDataLine(audioFormat);
sourceDataLine.open(audioFormat);
} catch (LineUnavailableException lue) {
lue.printStackTrace();
}
}
private static SourceDataLine sourceDataLine;
private static float SAMPLE_RATE = 8_000.0F;
private static final int BYTE_OFFSET = 0;
}