source: rtos_arduino/trunk/arduino_lib/libraries/ZumoShield/ZumoBuzzer.cpp@ 260

Last change on this file since 260 was 260, checked in by ertl-honda, 8 years ago

マクロ名を更新.
実行モデルを変更.

File size: 8.3 KB
Line 
1#include "ZumoBuzzer.h"
2#include <Arduino.h>
3
4#define BUZZER_PIN 6
5
6const char *buzzerSequence = 0;
7
8// declaring these globals as static means they won't conflict
9// with globals in other .cpp files that share the same name
10static volatile unsigned int buzzerTimeout = 0; // tracks buzzer time limit
11static char play_mode_setting = PLAY_AUTOMATIC;
12
13extern volatile unsigned char buzzerFinished; // flag: 0 while playing
14extern const char *buzzerSequence;
15
16
17static unsigned char use_program_space; // boolean: true if we should
18 // use program space
19
20// music settings and defaults
21static unsigned char octave = 4; // the current octave
22static unsigned int whole_note_duration = 2000; // the duration of a whole note
23static unsigned int note_type = 4; // 4 for quarter, etc
24static unsigned int duration = 500; // the duration of a note in ms
25static unsigned int volume = 15; // the note volume
26static unsigned char staccato = 0; // true if playing staccato
27
28// staccato handling
29static unsigned char staccato_rest_duration; // duration of a staccato
30 // rest, or zero if it is time
31 // to play a note
32
33static void nextNote();
34
35ZumoBuzzer::ZumoBuzzer()
36{
37}
38
39inline void ZumoBuzzer::init()
40{
41}
42
43void ZumoBuzzer::init2()
44{
45}
46
47void ZumoBuzzer::playFrequency(unsigned int freq, unsigned int dur,
48 unsigned char volume)
49{
50 tone(BUZZER_PIN, freq, dur);
51}
52
53void ZumoBuzzer::playNote(unsigned char note, unsigned int dur,
54 unsigned char volume)
55{
56 unsigned int freq = 0;
57 unsigned char offset_note = note - 16;
58
59 if (note == SILENT_NOTE || volume == 0)
60 {
61 freq = 1000; // silent notes => use 1kHz freq (for cycle counter)
62 playFrequency(freq, dur, 0);
63 return;
64 }
65
66 if (note <= 16)
67 offset_note = 0;
68 else if (offset_note > 95)
69 offset_note = 95;
70
71 unsigned char exponent = offset_note / 12;
72
73 // frequency table for the lowest 12 allowed notes
74 // frequencies are specified in tenths of a Hertz for added resolution
75 switch (offset_note - exponent * 12) // equivalent to (offset_note % 12)
76 {
77 case 0: // note E1 = 41.2 Hz
78 freq = 412;
79 break;
80 case 1: // note F1 = 43.7 Hz
81 freq = 437;
82 break;
83 case 2: // note F#1 = 46.3 Hz
84 freq = 463;
85 break;
86 case 3: // note G1 = 49.0 Hz
87 freq = 490;
88 break;
89 case 4: // note G#1 = 51.9 Hz
90 freq = 519;
91 break;
92 case 5: // note A1 = 55.0 Hz
93 freq = 550;
94 break;
95 case 6: // note A#1 = 58.3 Hz
96 freq = 583;
97 break;
98 case 7: // note B1 = 61.7 Hz
99 freq = 617;
100 break;
101 case 8: // note C2 = 65.4 Hz
102 freq = 654;
103 break;
104 case 9: // note C#2 = 69.3 Hz
105 freq = 693;
106 break;
107 case 10: // note D2 = 73.4 Hz
108 freq = 734;
109 break;
110 case 11: // note D#2 = 77.8 Hz
111 freq = 778;
112 break;
113 }
114
115 if (exponent < 7)
116 {
117 freq = freq << exponent; // frequency *= 2 ^ exponent
118 if (exponent > 1) // if the frequency is greater than 160 Hz
119 freq = (freq + 5) / 10; // we don't need the extra resolution
120 else
121 freq += DIV_BY_10; // else keep the added digit of resolution
122 }
123 else
124 freq = (freq * 64 + 2) / 5; // == freq * 2^7 / 10 without int overflow
125
126 if (volume > 15)
127 volume = 15;
128 playFrequency(freq, dur, volume); // set buzzer this freq/duration
129}
130
131// Returns 1 if the buzzer is currently playing, otherwise it returns 0
132unsigned char ZumoBuzzer::isPlaying()
133{
134 if(buzzerSequence) {
135 return 1;
136 }
137 else {
138 return 0;
139 }
140}
141
142#include "ZumoShield_cfg.h"
143#include "r2ca.h"
144
145void
146zumobuzzer_task(intptr_t exinf) {
147 while(buzzerSequence) {
148 nextNote();
149 }
150}
151
152void ZumoBuzzer::play(const char *notes)
153{
154 buzzerSequence = notes;
155 use_program_space = 0;
156 staccato_rest_duration = 0;
157 act_tsk(ZUMOBUZZER_TASK);
158}
159
160void ZumoBuzzer::playFromProgramSpace(const char *notes_p)
161{
162 buzzerSequence = notes_p;
163 use_program_space = 1;
164 staccato_rest_duration = 0;
165 act_tsk(ZUMOBUZZER_TASK);
166}
167
168void ZumoBuzzer::stopPlaying()
169{
170}
171
172// Gets the current character, converting to lower-case and skipping
173// spaces. For any spaces, this automatically increments sequence!
174static char currentCharacter()
175{
176 char c = 0;
177 do
178 {
179 if(use_program_space)
180 c = pgm_read_byte(buzzerSequence);
181 else
182 c = *buzzerSequence;
183
184 if(c >= 'A' && c <= 'Z')
185 c += 'a'-'A';
186 } while(c == ' ' && (buzzerSequence ++));
187
188 return c;
189}
190
191// Returns the numerical argument specified at buzzerSequence[0] and
192// increments sequence to point to the character immediately after the
193// argument.
194static unsigned int getNumber()
195{
196 unsigned int arg = 0;
197
198 // read all digits, one at a time
199 char c = currentCharacter();
200 while(c >= '0' && c <= '9')
201 {
202 arg *= 10;
203 arg += c-'0';
204 buzzerSequence ++;
205 c = currentCharacter();
206 }
207
208 return arg;
209}
210
211static void nextNote()
212{
213 unsigned char note = 0;
214 unsigned char rest = 0;
215 unsigned char tmp_octave = octave; // the octave for this note
216 unsigned int tmp_duration; // the duration of this note
217 unsigned int dot_add;
218
219 char c; // temporary variable
220
221 // if we are playing staccato, after every note we play a rest
222 if(staccato && staccato_rest_duration)
223 {
224 ZumoBuzzer::playNote(SILENT_NOTE, staccato_rest_duration, 0);
225 staccato_rest_duration = 0;
226 return;
227 }
228
229 parse_character:
230
231 // Get current character
232 c = currentCharacter();
233 buzzerSequence ++;
234
235 // Interpret the character.
236 switch(c)
237 {
238 case '>':
239 // shift the octave temporarily up
240 tmp_octave ++;
241 goto parse_character;
242 case '<':
243 // shift the octave temporarily down
244 tmp_octave --;
245 goto parse_character;
246 case 'a':
247 note = NOTE_A(0);
248 break;
249 case 'b':
250 note = NOTE_B(0);
251 break;
252 case 'c':
253 note = NOTE_C(0);
254 break;
255 case 'd':
256 note = NOTE_D(0);
257 break;
258 case 'e':
259 note = NOTE_E(0);
260 break;
261 case 'f':
262 note = NOTE_F(0);
263 break;
264 case 'g':
265 note = NOTE_G(0);
266 break;
267 case 'l':
268 // set the default note duration
269 note_type = getNumber();
270 duration = whole_note_duration/note_type;
271 goto parse_character;
272 case 'm':
273 // set music staccato or legato
274 if(currentCharacter() == 'l')
275 staccato = false;
276 else
277 {
278 staccato = true;
279 staccato_rest_duration = 0;
280 }
281 buzzerSequence ++;
282 goto parse_character;
283 case 'o':
284 // set the octave permanently
285 octave = getNumber();
286 tmp_octave = octave;
287 goto parse_character;
288 case 'r':
289 // Rest - the note value doesn't matter.
290 rest = 1;
291 break;
292 case 't':
293 // set the tempo
294 whole_note_duration = 60*400/getNumber()*10;
295 duration = whole_note_duration/note_type;
296 goto parse_character;
297 case 'v':
298 // set the volume
299 volume = getNumber();
300 goto parse_character;
301 case '!':
302 // reset to defaults
303 octave = 4;
304 whole_note_duration = 2000;
305 note_type = 4;
306 duration = 500;
307 volume = 15;
308 staccato = 0;
309 // reset temp variables that depend on the defaults
310 tmp_octave = octave;
311 tmp_duration = duration;
312 goto parse_character;
313 default:
314 buzzerSequence = 0;
315 return;
316 }
317
318 note += tmp_octave*12;
319
320 // handle sharps and flats
321 c = currentCharacter();
322 while(c == '+' || c == '#')
323 {
324 buzzerSequence ++;
325 note ++;
326 c = currentCharacter();
327 }
328 while(c == '-')
329 {
330 buzzerSequence ++;
331 note --;
332 c = currentCharacter();
333 }
334
335 // set the duration of just this note
336 tmp_duration = duration;
337
338 // If the input is 'c16', make it a 16th note, etc.
339 if(c > '0' && c < '9')
340 tmp_duration = whole_note_duration/getNumber();
341
342 // Handle dotted notes - the first dot adds 50%, and each
343 // additional dot adds 50% of the previous dot.
344 dot_add = tmp_duration/2;
345 while(currentCharacter() == '.')
346 {
347 buzzerSequence ++;
348 tmp_duration += dot_add;
349 dot_add /= 2;
350 }
351
352 if(staccato)
353 {
354 staccato_rest_duration = tmp_duration / 2;
355 tmp_duration -= staccato_rest_duration;
356 }
357
358 // this will re-enable the timer1 overflow interrupt
359 ZumoBuzzer::playNote(rest ? SILENT_NOTE : note, tmp_duration, volume);
360 delay(tmp_duration*1.5);
361}
362
363void ZumoBuzzer::playMode(unsigned char mode)
364{
365}
366
367unsigned char ZumoBuzzer::playCheck()
368{
369 return 0;
370}
Note: See TracBrowser for help on using the repository browser.