source: osm/applications/editors/josm/plugins/wms-turbo-challenge2/src/wmsturbochallenge/EngineSound.java

Last change on this file was 36483, checked in by stoecker, 8 months ago

set eol-style, fix checkstyle issues, add ignores

  • Property svn:eol-style set to native
File size: 4.8 KB
RevLine 
[36483]1// License: GPL. For details, see LICENSE file.
[19990]2package wmsturbochallenge;
3
4import java.util.Timer;
5import java.util.TimerTask;
6
[32322]7import javax.sound.sampled.AudioFormat;
[19990]8import javax.sound.sampled.AudioSystem;
9import javax.sound.sampled.DataLine;
10import javax.sound.sampled.SourceDataLine;
11
[33342]12/**
13 * This class simulates a car engine. What does a car engine do? It
14 * makes a pc-speaker-like buzz. The PC Speaker could only emit
15 * a (nearly) square wave and we simulate it here for maximum realism.
[36483]16 * @author Andrzej Zaborowski
[33342]17 */
[32322]18class EngineSound {
[33342]19 EngineSound() {
[23190]20 rpm = 0.0;
21 }
[19990]22
[23190]23 public void start() {
24 rpm = 0.3;
25 speed = 0.0;
26 n = 0;
[19990]27
[23190]28 if (output != null)
29 stop();
[19990]30
[23190]31 AudioFormat output_format =
[32914]32 new AudioFormat(S_RATE, 16, 1, true, true);
[23190]33 DataLine.Info info =
[32914]34 new DataLine.Info(SourceDataLine.class, output_format);
[19990]35
[23190]36 /* Get the data line, open it and initialise the device */
37 try {
38 output = (SourceDataLine) AudioSystem.getLine(info);
39 output.open(output_format);
40 output.start();
41 frames_written = 0;
42 reschedule(0);
43 } catch (Exception e) {
44 output = null;
45 System.out.println("Audio not available: " +
46 e.getClass().getSimpleName());
47 }
48 }
[19990]49
[23190]50 public void stop() {
51 rpm = 0.0;
52 n = 0;
[19990]53
[23190]54 if (output == null)
55 return;
[19990]56
[23190]57 tick.cancel();
58 tick.purge();
[19990]59
[23190]60 output.stop();
61 output.flush();
62 output.close();
63 output = null;
64 }
[19990]65
[23190]66 public void set_speed(double speed) {
67 /* This engine is equipped with an automatic gear box that
68 * switches gears when the RPM becomes too high or too low. */
69 double new_speed = Math.abs(speed);
70 double accel = new_speed - this.speed;
71 this.speed = new_speed;
[19990]72
[23190]73 if (accel > 0.05)
74 accel = 0.05;
75 else if (accel < -0.05)
76 accel = -0.05;
77 rpm += accel;
[19990]78
[23190]79 if (accel > 0.0 && rpm > 1.0 + n * 0.2 && speed > 0.0) {
80 rpm = 0.3 + n * 0.2;
[33342]81 n++;
[23190]82 } else if (accel < 0.0 && rpm < 0.3) {
83 if (n > 0) {
84 rpm = 0.7 + n * 0.1;
[33342]85 n--;
[23190]86 } else
87 rpm = 0.2;
88 }
89 if (speed < 2.0)
90 n = 0;
91 }
[19990]92
[23190]93 public boolean is_on() {
94 return output != null;
95 }
[19990]96
[23190]97 protected double speed;
98 protected double rpm;
99 protected int n;
[19990]100
[23190]101 protected SourceDataLine output = null;
102 protected long frames_written;
103 protected Timer tick = new Timer();
[19990]104
[23190]105 /* Audio parameters. */
106 protected static final int S_RATE = 44100;
107 protected static final int MIN_BUFFER = 4096;
108 protected static final double volume = 0.3;
[19990]109
[23190]110 protected class audio_task extends TimerTask {
[32914]111 @Override
[23190]112 public void run() {
113 if (output == null)
114 return;
[19990]115
[23190]116 /* If more than a two buffers left to play,
117 * reschedule and try to wake up closer to the
118 * end of already written data. */
119 long frames_current = output.getLongFramePosition();
120 if (frames_current < frames_written - MIN_BUFFER * 2) {
121 reschedule(frames_current);
122 return;
123 }
[19990]124
[23190]125 /* Build a new buffer */
126 /* double freq = 20 * Math.pow(1.3, rpm * 5.0); */
127 double freq = (rpm - 0.1) * 160.0;
128 int wavelen = (int) (S_RATE / freq);
129 int bufferlen = MIN_BUFFER - (MIN_BUFFER % wavelen) +
[32914]130 wavelen;
[23190]131 int value = (int) (0x7fff * volume);
[19990]132
[23190]133 bufferlen *= 2;
134 byte[] buffer = new byte[bufferlen];
[33342]135 for (int b = 0; b < bufferlen;) {
[23190]136 int j;
[33342]137 for (j = wavelen / 2; j > 0; j--) {
138 buffer[b++] = (byte) (value >> 8);
139 buffer[b++] = (byte) (value & 0xff);
[23190]140 }
141 value = 0x10000 - value;
[33342]142 for (j = wavelen - wavelen / 2; j > 0; j--) {
143 buffer[b++] = (byte) (value >> 8);
144 buffer[b++] = (byte) (value & 0xff);
[23190]145 }
146 value = 0x10000 - value;
147 }
[19990]148
[23190]149 frames_written +=
[32914]150 output.write(buffer, 0, bufferlen) / 2;
[19990]151
[23190]152 reschedule(frames_current);
153 }
154 }
[19990]155
[23190]156 protected void reschedule(long frames) {
157 /* Send a new buffer as close to the end of the
158 * currently playing buffer as possible (aim at
159 * about half into the last frame). */
160 long delay = (frames_written - frames - MIN_BUFFER / 2) *
[32914]161 1000 / S_RATE;
[23190]162 if (delay < 0)
163 delay = 0;
164 tick.schedule(new audio_task(), delay);
165 }
[19990]166}
Note: See TracBrowser for help on using the repository browser.