1 package fr.ifremer.tutti.ui.swing.util;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 import com.google.common.base.Optional;
26 import fr.ifremer.tutti.util.BeepFrequency;
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29
30 import javax.sound.sampled.AudioFormat;
31 import javax.sound.sampled.AudioInputStream;
32 import javax.sound.sampled.AudioSystem;
33 import javax.sound.sampled.DataLine;
34 import javax.sound.sampled.LineUnavailableException;
35 import javax.sound.sampled.SourceDataLine;
36 import javax.sound.sampled.UnsupportedAudioFileException;
37 import java.io.IOException;
38 import java.util.ArrayList;
39 import java.util.List;
40
41
42
43
44
45 public class SoundUtil {
46
47
48 private static final Log log = LogFactory.getLog(SoundUtil.class);
49
50 public static String SOUNDS_DIRECTORY = "/sounds";
51
52 public static float SAMPLE_RATE = 8000f;
53
54 public static void beep(BeepFrequency beepFrequency) {
55 beep(beepFrequency, 1);
56 }
57
58 public static void beep(BeepFrequency beepFrequency, int number) {
59
60 try {
61 for (int i = 0; i < number; i++) {
62 tone(beepFrequency.getFrequency(), 500, 1.0);
63 }
64
65 } catch (LineUnavailableException e) {
66 if (log.isErrorEnabled()) {
67 log.error("Error while playing a beep", e);
68 }
69 }
70 }
71
72 public static void tone(int hz, int msecs, double vol) throws LineUnavailableException {
73 byte[] buf = new byte[1];
74 AudioFormat af = new AudioFormat(SAMPLE_RATE,
75 8,
76 1,
77 true,
78 false);
79 try (SourceDataLine sdl = AudioSystem.getSourceDataLine(af)) {
80 sdl.open(af);
81 sdl.start();
82 for (int i = 0, end = msecs * 8; i < end; i++) {
83 double angle = i / (SAMPLE_RATE / hz) * 2.0 * Math.PI;
84 buf[0] = (byte) (Math.sin(angle) * 127.0 * vol);
85 sdl.write(buf, 0, 1);
86 }
87 sdl.drain();
88 sdl.stop();
89 }
90 }
91
92 public static void readNumber(double number, Optional<String> unit) {
93
94 try {
95
96 int thousands = (int) (number / 1000);
97 int hundreds = (int) (number % 1000) / 100;
98 int tensAndUnits = (int) number % 100;
99 int decimal = (int) (number * 10) % 10;
100
101 if (log.isDebugEnabled()) {
102 log.debug(thousands + " " + hundreds + " " + tensAndUnits + " " + decimal);
103 }
104
105 List<AudioInputStream> audioInputStreams = new ArrayList<>();
106
107 addSound(audioInputStreams, thousands, 1000);
108 addSound(audioInputStreams, hundreds, 100);
109 if (tensAndUnits != 0 || thousands == 0 && hundreds == 0) {
110 addSound(audioInputStreams, tensAndUnits);
111 }
112 if (decimal > 0) {
113 addSound(audioInputStreams, ",");
114 addSound(audioInputStreams, decimal);
115 }
116 if (unit.isPresent()) {
117 addSound(audioInputStreams, unit.get());
118 }
119
120 if (!audioInputStreams.isEmpty()) {
121
122 AudioFormat format = audioInputStreams.get(0).getFormat();
123 DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
124 try (SourceDataLine audioLine = (SourceDataLine) AudioSystem.getLine(info)) {
125 audioLine.open(format);
126 audioLine.start();
127
128 byte[] bytesBuffer = new byte[4096];
129
130 while (!audioInputStreams.isEmpty()) {
131 try (AudioInputStream audioInputStream = audioInputStreams.remove(0)) {
132 int bytesRead;
133 while ((bytesRead = audioInputStream.read(bytesBuffer)) != -1) {
134 audioLine.write(bytesBuffer, 0, bytesRead);
135 }
136 }
137 }
138
139 audioLine.drain();
140
141 }
142 }
143
144 } catch (Exception e) {
145 if (log.isErrorEnabled()) {
146 log.error("Error while reading " + number + " " + unit, e);
147 }
148 }
149
150 }
151
152 protected static long addSound(List<AudioInputStream> inputStreams, int number) throws IOException, UnsupportedAudioFileException {
153 return addSound(inputStreams, number, 1);
154 }
155
156 protected static long addSound(List<AudioInputStream> inputStreams, int number, int suffix) throws IOException, UnsupportedAudioFileException {
157 long length = 0;
158
159 if (number > 1 || suffix == 1) {
160 if (log.isDebugEnabled()) {
161 log.debug("-> add " + number + ".wav");
162 }
163 AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(SoundUtil.class.getResource(SOUNDS_DIRECTORY + "/" + number + ".wav"));
164 inputStreams.add(audioInputStream);
165 length += audioInputStream.getFrameLength();
166 }
167
168 if (number >= 1 && suffix > 1) {
169 if (log.isDebugEnabled()) {
170 log.debug("-> add " + suffix + ".wav");
171 }
172 AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(SoundUtil.class.getResource(SOUNDS_DIRECTORY + "/" + suffix + ".wav"));
173 inputStreams.add(audioInputStream);
174 length += audioInputStream.getFrameLength();
175 }
176
177 return length;
178 }
179
180 protected static long addSound(List<AudioInputStream> inputStreams, String name) throws IOException, UnsupportedAudioFileException {
181 if (log.isDebugEnabled()) {
182 log.debug("add " + name + ".wav");
183 }
184 AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(SoundUtil.class.getResource(SOUNDS_DIRECTORY + "/" + name + ".wav"));
185 inputStreams.add(audioInputStream);
186 return audioInputStream.getFrameLength();
187 }
188
189 }