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

Last change on this file since 21477 was 19990, checked in by balrog-kun, 15 years ago

Initial commit of the wms-turbo-challenge2 plugin.

This may not be an extremely useful plugin but it will still be great to
have it in the source tree so that it updated when upstream interfaces
change, and get nice versioning.

File size: 3.8 KB
Line 
1/*
2 * GPLv2 or 3, Copyright (c) 2010 Andrzej Zaborowski
3 *
4 * This class simulates a car engine. What does a car engine do? It
5 * makes a pc-speaker-like buzz. The PC Speaker could only emit
6 * a (nearly) square wave and we simulate it here for maximum realism.
7 */
8package wmsturbochallenge;
9
10import java.util.Timer;
11import java.util.TimerTask;
12
13import javax.sound.sampled.AudioSystem;
14import javax.sound.sampled.DataLine;
15import javax.sound.sampled.SourceDataLine;
16import javax.sound.sampled.AudioFormat;
17
18class engine {
19 public engine() {
20 rpm = 0.0;
21 }
22
23 public void start() {
24 rpm = 0.3;
25 speed = 0.0;
26 n = 0;
27
28 if (output != null)
29 stop();
30
31 AudioFormat output_format =
32 new AudioFormat(S_RATE, 16, 1, true, true);
33 DataLine.Info info =
34 new DataLine.Info(SourceDataLine.class, output_format);
35
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 }
49
50 public void stop() {
51 rpm = 0.0;
52 n = 0;
53
54 if (output == null)
55 return;
56
57 tick.cancel();
58 tick.purge();
59
60 output.stop();
61 output.flush();
62 output.close();
63 output = null;
64 }
65
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;
72
73 if (accel > 0.05)
74 accel = 0.05;
75 else if (accel < -0.05)
76 accel = -0.05;
77 rpm += accel;
78
79 if (accel > 0.0 && rpm > 1.0 + n * 0.2 && speed > 0.0) {
80 rpm = 0.3 + n * 0.2;
81 n ++;
82 } else if (accel < 0.0 && rpm < 0.3) {
83 if (n > 0) {
84 rpm = 0.7 + n * 0.1;
85 n --;
86 } else
87 rpm = 0.2;
88 }
89 if (speed < 2.0)
90 n = 0;
91 }
92
93 public boolean is_on() {
94 return output != null;
95 }
96
97 protected double speed;
98 protected double rpm;
99 protected int n;
100
101 protected SourceDataLine output = null;
102 protected long frames_written;
103 protected Timer tick = new Timer();
104
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;
109
110 protected class audio_task extends TimerTask {
111 public void run() {
112 if (output == null)
113 return;
114
115 /* If more than a two buffers left to play,
116 * reschedule and try to wake up closer to the
117 * end of already written data. */
118 long frames_current = output.getLongFramePosition();
119 if (frames_current < frames_written - MIN_BUFFER * 2) {
120 reschedule(frames_current);
121 return;
122 }
123
124 /* Build a new buffer */
125 /* double freq = 20 * Math.pow(1.3, rpm * 5.0); */
126 double freq = (rpm - 0.1) * 160.0;
127 int wavelen = (int) (S_RATE / freq);
128 int bufferlen = MIN_BUFFER - (MIN_BUFFER % wavelen) +
129 wavelen;
130 int value = (int) (0x7fff * volume);
131
132 bufferlen *= 2;
133 byte[] buffer = new byte[bufferlen];
134 for (int b = 0; b < bufferlen; ) {
135 int j;
136 for (j = wavelen / 2; j > 0; j --) {
137 buffer[b ++] = (byte) (value >> 8);
138 buffer[b ++] = (byte) (value & 0xff);
139 }
140 value = 0x10000 - value;
141 for (j = wavelen - wavelen / 2; j > 0; j --) {
142 buffer[b ++] = (byte) (value >> 8);
143 buffer[b ++] = (byte) (value & 0xff);
144 }
145 value = 0x10000 - value;
146 }
147
148 frames_written +=
149 output.write(buffer, 0, bufferlen) / 2;
150
151 reschedule(frames_current);
152 }
153 }
154
155 protected void reschedule(long frames) {
156 /* Send a new buffer as close to the end of the
157 * currently playing buffer as possible (aim at
158 * about half into the last frame). */
159 long delay = (frames_written - frames - MIN_BUFFER / 2) *
160 1000 / S_RATE;
161 if (delay < 0)
162 delay = 0;
163 tick.schedule(new audio_task(), delay);
164 }
165}
Note: See TracBrowser for help on using the repository browser.