├── .gitignore
├── README.md
├── libraries
└── WaveHC
│ ├── ArduinoPins.h
│ ├── FatReader.cpp
│ ├── FatReader.h
│ ├── FatStructs.h
│ ├── SdInfo.h
│ ├── SdReader.cpp
│ ├── SdReader.h
│ ├── WaveHC.cpp
│ ├── WaveHC.h
│ ├── WavePinDefs.h
│ ├── WaveUtil.cpp
│ ├── WaveUtil.h
│ ├── Wavemainpage.h
│ ├── examples
│ ├── PiSpeakHC
│ │ └── PiSpeakHC.pde
│ ├── SampleRateHC
│ │ └── SampleRateHC.pde
│ ├── SdReadTest
│ │ └── SdReadTest.pde
│ ├── SoftVolumeHC
│ │ └── SoftVolumeHC.pde
│ ├── daphc
│ │ └── daphc.pde
│ └── openByIndex
│ │ └── openByIndex.pde
│ └── mcpDac.h
└── microGranny
├── HW_DEFINES.ino
├── HW_DEFINITION.ino
├── MIDI.ino
├── PresetStorage.ino
├── UI.ino
├── UI_display.ino
├── microGranny.ino
└── sampler.ino
/.gitignore:
--------------------------------------------------------------------------------
1 | # Compiled Object files
2 | *.slo
3 | *.lo
4 | *.o
5 |
6 | # Compiled Dynamic libraries
7 | *.so
8 | *.dylib
9 |
10 | # Compiled Static libraries
11 | *.lai
12 | *.la
13 | *.a
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #microGranny
2 | See more information on Standuino's microGranny [project page](http://www.standuino.eu/devices/instruments/microgranny/).
3 |
4 | ##Uploading the software
5 |
6 | * to upload software of microGranny you need to download and install [Arduino environment](http://arduino.cc/en/Main/Software)
7 | * if you are using FTDi usb connector to interface with Standuino you should have driver for FTDi installed. Find it [here](http://www.ftdichip.com/FTDrivers.htm)
8 | * install the modified version of WaveHC library to your Arduino provided in this repo here.
9 | * see the [arduino website](http://arduino.cc/en/Guide/Libraries) for how to install the library
10 |
11 | * open Arduino environment and open the `microGranny.ino` file - now you should see the source code of microGranny
12 | * in Arduino environment select - board>Arduino UNO (this refers to the bootloader of your chip)
13 | * select right serial port (see Arduino website for differences between different OS)
14 | * click upload button and wait until the software says DONE UPLOADING
15 | * if there is a problem uploading check your soldering and follow troubleshooting at Arduino website
16 |
17 | * to format EEPROM memory for proper use with the device hold down all 4 big trigger buttons while turning the device ON (on microGranny the display should say "CLR" fra/frau Angelico an led ADSR / PLAY should blink several times , pause and blink several times again)
18 |
19 | ##Preparing the microSD card and samples
20 |
21 | * Of course you can use your own sounds and you can use any microSD card you want. Before you use the card it is advised to format it with the official formater to make it work faster. The original SD formater can be found here with the instructions, [here](www.sdcard.org/downloads).
22 | * You can use any microSD card reader that shows the card in your computer as and external drive.
23 | * You can use the samples from the Samples folder
24 |
25 | * The samples for microGranny have to be wav files, Mono, 16 or 8 bit and with a sample rate of 22050 Hz
26 | * To convert your samples into such a format you can use the free software [Audacity](http://audacity.sourceforge.net)
27 | * In Audacity Open your file, when it is Stereo use Track > Stereo Track to Mono
28 |
29 | * Then change the Project Rate (bottom left corner) to 22050 and then go to File > Export
30 |
31 | * In the Format drop down choose “Wave (Microsoft) signed 16 bit PCM” and use a name which has two letters only, use A-Z and 0-9 letters.
32 |
33 | * Copy the file to the root directory on the SD card and everything should be ready to be played by the sampler.
34 |
35 | ##Circuit Board
36 | made with Fritzing
37 | to view go to http://fritzing.org/download/
38 | the second part of the device is Standuino 2.2 for more see: http://www.standuino.eu/devices/standuino/
39 |
40 | ##Schematics
41 | doesn`t exist yet, i have to draw it, but based on [WaveShield](http://www.ladyada.net/make/waveshield) by Adafruit
42 |
43 |
44 | And don't forget...don't make your money with it. Hack it modify it but don't steal it.
45 |
46 | I have no idea what the opensource hardware licence it is but you might know.
47 |
48 | If you want to get more involved, contact us!
49 | standuino@gmail.com
50 |
51 |
52 | So what is the difference between Sampling and Dumpling?
53 | find out more at www.standuino.eu
54 |
--------------------------------------------------------------------------------
/libraries/WaveHC/ArduinoPins.h:
--------------------------------------------------------------------------------
1 | // Map of Arduino pins to avr bit, ddr, port, pin
2 | // Credit Paul Stoffregen for idea
3 | #ifndef ArduinoPins_h
4 | #define ArduinoPins_h
5 |
6 | #define PIN_BITNUM(pin) (PIN ## pin ## _BITNUM)
7 | #define PIN_PORTREG(pin) (PIN ## pin ## _PORTREG)
8 | #define PIN_DDRREG(pin) (PIN ## pin ## _DDRREG)
9 | #define PIN_PINREG(pin) (PIN ## pin ## _PINREG)
10 | #ifndef _BV
11 | #define _BV(n) (1<<(n))
12 | #endif
13 |
14 | #if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
15 | // Mega Arduino
16 |
17 | // Two Wire (aka I2C) ports
18 | #define SDA_PIN 20
19 | #define SCL_PIN 21
20 |
21 | // SPI port
22 | #define SS_PIN 53
23 | #define MOSI_PIN 51
24 | #define MISO_PIN 50
25 | #define SCK_PIN 52
26 |
27 | // bit number for all digital pins
28 | #define PIN0_BITNUM 0
29 | #define PIN1_BITNUM 1
30 | #define PIN2_BITNUM 4
31 | #define PIN3_BITNUM 5
32 | #define PIN4_BITNUM 5
33 | #define PIN5_BITNUM 3
34 | #define PIN6_BITNUM 3
35 | #define PIN7_BITNUM 4
36 | #define PIN8_BITNUM 5
37 | #define PIN9_BITNUM 6
38 | #define PIN10_BITNUM 4
39 | #define PIN11_BITNUM 5
40 | #define PIN12_BITNUM 6
41 | #define PIN13_BITNUM 7
42 | #define PIN14_BITNUM 1
43 | #define PIN15_BITNUM 0
44 | #define PIN16_BITNUM 1
45 | #define PIN17_BITNUM 0
46 | #define PIN18_BITNUM 3
47 | #define PIN19_BITNUM 2
48 | #define PIN20_BITNUM 1
49 | #define PIN21_BITNUM 0
50 | #define PIN22_BITNUM 0
51 | #define PIN23_BITNUM 1
52 | #define PIN24_BITNUM 2
53 | #define PIN25_BITNUM 3
54 | #define PIN26_BITNUM 4
55 | #define PIN27_BITNUM 5
56 | #define PIN28_BITNUM 6
57 | #define PIN29_BITNUM 7
58 | #define PIN30_BITNUM 7
59 | #define PIN31_BITNUM 6
60 | #define PIN32_BITNUM 5
61 | #define PIN33_BITNUM 4
62 | #define PIN34_BITNUM 3
63 | #define PIN35_BITNUM 2
64 | #define PIN36_BITNUM 1
65 | #define PIN37_BITNUM 0
66 | #define PIN38_BITNUM 7
67 | #define PIN39_BITNUM 2
68 | #define PIN40_BITNUM 1
69 | #define PIN41_BITNUM 0
70 | #define PIN42_BITNUM 7
71 | #define PIN43_BITNUM 6
72 | #define PIN44_BITNUM 5
73 | #define PIN45_BITNUM 4
74 | #define PIN46_BITNUM 3
75 | #define PIN47_BITNUM 2
76 | #define PIN48_BITNUM 1
77 | #define PIN49_BITNUM 0
78 | #define PIN50_BITNUM 3
79 | #define PIN51_BITNUM 2
80 | #define PIN52_BITNUM 1
81 | #define PIN53_BITNUM 0
82 | #define PIN54_BITNUM 0
83 | #define PIN55_BITNUM 1
84 | #define PIN56_BITNUM 2
85 | #define PIN57_BITNUM 3
86 | #define PIN58_BITNUM 4
87 | #define PIN59_BITNUM 5
88 | #define PIN60_BITNUM 6
89 | #define PIN61_BITNUM 7
90 | #define PIN62_BITNUM 0
91 | #define PIN63_BITNUM 1
92 | #define PIN64_BITNUM 2
93 | #define PIN65_BITNUM 3
94 | #define PIN66_BITNUM 4
95 | #define PIN67_BITNUM 5
96 | #define PIN68_BITNUM 6
97 | #define PIN69_BITNUM 7
98 |
99 | // output register for digital pins
100 | #define PIN0_PORTREG PORTE
101 | #define PIN1_PORTREG PORTE
102 | #define PIN2_PORTREG PORTE
103 | #define PIN3_PORTREG PORTE
104 | #define PIN4_PORTREG PORTG
105 | #define PIN5_PORTREG PORTE
106 | #define PIN6_PORTREG PORTH
107 | #define PIN7_PORTREG PORTH
108 | #define PIN8_PORTREG PORTH
109 | #define PIN9_PORTREG PORTH
110 | #define PIN10_PORTREG PORTB
111 | #define PIN11_PORTREG PORTB
112 | #define PIN12_PORTREG PORTB
113 | #define PIN13_PORTREG PORTB
114 | #define PIN14_PORTREG PORTJ
115 | #define PIN15_PORTREG PORTJ
116 | #define PIN16_PORTREG PORTH
117 | #define PIN17_PORTREG PORTH
118 | #define PIN18_PORTREG PORTD
119 | #define PIN19_PORTREG PORTD
120 | #define PIN20_PORTREG PORTD
121 | #define PIN21_PORTREG PORTD
122 | #define PIN22_PORTREG PORTA
123 | #define PIN23_PORTREG PORTA
124 | #define PIN24_PORTREG PORTA
125 | #define PIN25_PORTREG PORTA
126 | #define PIN26_PORTREG PORTA
127 | #define PIN27_PORTREG PORTA
128 | #define PIN28_PORTREG PORTA
129 | #define PIN29_PORTREG PORTA
130 | #define PIN30_PORTREG PORTC
131 | #define PIN31_PORTREG PORTC
132 | #define PIN32_PORTREG PORTC
133 | #define PIN33_PORTREG PORTC
134 | #define PIN34_PORTREG PORTC
135 | #define PIN35_PORTREG PORTC
136 | #define PIN36_PORTREG PORTC
137 | #define PIN37_PORTREG PORTC
138 | #define PIN38_PORTREG PORTD
139 | #define PIN39_PORTREG PORTG
140 | #define PIN40_PORTREG PORTG
141 | #define PIN41_PORTREG PORTG
142 | #define PIN42_PORTREG PORTL
143 | #define PIN43_PORTREG PORTL
144 | #define PIN44_PORTREG PORTL
145 | #define PIN45_PORTREG PORTL
146 | #define PIN46_PORTREG PORTL
147 | #define PIN47_PORTREG PORTL
148 | #define PIN48_PORTREG PORTL
149 | #define PIN49_PORTREG PORTL
150 | #define PIN50_PORTREG PORTB
151 | #define PIN51_PORTREG PORTB
152 | #define PIN52_PORTREG PORTB
153 | #define PIN53_PORTREG PORTB
154 | #define PIN54_PORTREG PORTF
155 | #define PIN55_PORTREG PORTF
156 | #define PIN56_PORTREG PORTF
157 | #define PIN57_PORTREG PORTF
158 | #define PIN58_PORTREG PORTF
159 | #define PIN59_PORTREG PORTF
160 | #define PIN60_PORTREG PORTF
161 | #define PIN61_PORTREG PORTF
162 | #define PIN62_PORTREG PORTK
163 | #define PIN63_PORTREG PORTK
164 | #define PIN64_PORTREG PORTK
165 | #define PIN65_PORTREG PORTK
166 | #define PIN66_PORTREG PORTK
167 | #define PIN67_PORTREG PORTK
168 | #define PIN68_PORTREG PORTK
169 | #define PIN69_PORTREG PORTK
170 |
171 | // direction control register for digital pins
172 | #define PIN0_DDRREG DDRE
173 | #define PIN1_DDRREG DDRE
174 | #define PIN2_DDRREG DDRE
175 | #define PIN3_DDRREG DDRE
176 | #define PIN4_DDRREG DDRG
177 | #define PIN5_DDRREG DDRE
178 | #define PIN6_DDRREG DDRH
179 | #define PIN7_DDRREG DDRH
180 | #define PIN8_DDRREG DDRH
181 | #define PIN9_DDRREG DDRH
182 | #define PIN10_DDRREG DDRB
183 | #define PIN11_DDRREG DDRB
184 | #define PIN12_DDRREG DDRB
185 | #define PIN13_DDRREG DDRB
186 | #define PIN14_DDRREG DDRJ
187 | #define PIN15_DDRREG DDRJ
188 | #define PIN16_DDRREG DDRH
189 | #define PIN17_DDRREG DDRH
190 | #define PIN18_DDRREG DDRD
191 | #define PIN19_DDRREG DDRD
192 | #define PIN20_DDRREG DDRD
193 | #define PIN21_DDRREG DDRD
194 | #define PIN22_DDRREG DDRA
195 | #define PIN23_DDRREG DDRA
196 | #define PIN24_DDRREG DDRA
197 | #define PIN25_DDRREG DDRA
198 | #define PIN26_DDRREG DDRA
199 | #define PIN27_DDRREG DDRA
200 | #define PIN28_DDRREG DDRA
201 | #define PIN29_DDRREG DDRA
202 | #define PIN30_DDRREG DDRC
203 | #define PIN31_DDRREG DDRC
204 | #define PIN32_DDRREG DDRC
205 | #define PIN33_DDRREG DDRC
206 | #define PIN34_DDRREG DDRC
207 | #define PIN35_DDRREG DDRC
208 | #define PIN36_DDRREG DDRC
209 | #define PIN37_DDRREG DDRC
210 | #define PIN38_DDRREG DDRD
211 | #define PIN39_DDRREG DDRG
212 | #define PIN40_DDRREG DDRG
213 | #define PIN41_DDRREG DDRG
214 | #define PIN42_DDRREG DDRL
215 | #define PIN43_DDRREG DDRL
216 | #define PIN44_DDRREG DDRL
217 | #define PIN45_DDRREG DDRL
218 | #define PIN46_DDRREG DDRL
219 | #define PIN47_DDRREG DDRL
220 | #define PIN48_DDRREG DDRL
221 | #define PIN49_DDRREG DDRL
222 | #define PIN50_DDRREG DDRB
223 | #define PIN51_DDRREG DDRB
224 | #define PIN52_DDRREG DDRB
225 | #define PIN53_DDRREG DDRB
226 | #define PIN54_DDRREG DDRF
227 | #define PIN55_DDRREG DDRF
228 | #define PIN56_DDRREG DDRF
229 | #define PIN57_DDRREG DDRF
230 | #define PIN58_DDRREG DDRF
231 | #define PIN59_DDRREG DDRF
232 | #define PIN60_DDRREG DDRF
233 | #define PIN61_DDRREG DDRF
234 | #define PIN62_DDRREG DDRK
235 | #define PIN63_DDRREG DDRK
236 | #define PIN64_DDRREG DDRK
237 | #define PIN65_DDRREG DDRK
238 | #define PIN66_DDRREG DDRK
239 | #define PIN67_DDRREG DDRK
240 | #define PIN68_DDRREG DDRK
241 | #define PIN69_DDRREG DDRK
242 |
243 | // input register for digital pins
244 | #define PIN0_PINREG PINE
245 | #define PIN1_PINREG PINE
246 | #define PIN2_PINREG PINE
247 | #define PIN3_PINREG PINE
248 | #define PIN4_PINREG PING
249 | #define PIN5_PINREG PINE
250 | #define PIN6_PINREG PINH
251 | #define PIN7_PINREG PINH
252 | #define PIN8_PINREG PINH
253 | #define PIN9_PINREG PINH
254 | #define PIN10_PINREG PINB
255 | #define PIN11_PINREG PINB
256 | #define PIN12_PINREG PINB
257 | #define PIN13_PINREG PINB
258 | #define PIN14_PINREG PINJ
259 | #define PIN15_PINREG PINJ
260 | #define PIN16_PINREG PINH
261 | #define PIN17_PINREG PINH
262 | #define PIN18_PINREG PIND
263 | #define PIN19_PINREG PIND
264 | #define PIN20_PINREG PIND
265 | #define PIN21_PINREG PIND
266 | #define PIN22_PINREG PINA
267 | #define PIN23_PINREG PINA
268 | #define PIN24_PINREG PINA
269 | #define PIN25_PINREG PINA
270 | #define PIN26_PINREG PINA
271 | #define PIN27_PINREG PINA
272 | #define PIN28_PINREG PINA
273 | #define PIN29_PINREG PINA
274 | #define PIN30_PINREG PINC
275 | #define PIN31_PINREG PINC
276 | #define PIN32_PINREG PINC
277 | #define PIN33_PINREG PINC
278 | #define PIN34_PINREG PINC
279 | #define PIN35_PINREG PINC
280 | #define PIN36_PINREG PINC
281 | #define PIN37_PINREG PINC
282 | #define PIN38_PINREG PIND
283 | #define PIN39_PINREG PING
284 | #define PIN40_PINREG PING
285 | #define PIN41_PINREG PING
286 | #define PIN42_PINREG PINL
287 | #define PIN43_PINREG PINL
288 | #define PIN44_PINREG PINL
289 | #define PIN45_PINREG PINL
290 | #define PIN46_PINREG PINL
291 | #define PIN47_PINREG PINL
292 | #define PIN48_PINREG PINL
293 | #define PIN49_PINREG PINL
294 | #define PIN50_PINREG PINB
295 | #define PIN51_PINREG PINB
296 | #define PIN52_PINREG PINB
297 | #define PIN53_PINREG PINB
298 | #define PIN54_PINREG PINF
299 | #define PIN55_PINREG PINF
300 | #define PIN56_PINREG PINF
301 | #define PIN57_PINREG PINF
302 | #define PIN58_PINREG PINF
303 | #define PIN59_PINREG PINF
304 | #define PIN60_PINREG PINF
305 | #define PIN61_PINREG PINF
306 | #define PIN62_PINREG PINK
307 | #define PIN63_PINREG PINK
308 | #define PIN64_PINREG PINK
309 | #define PIN65_PINREG PINK
310 | #define PIN66_PINREG PINK
311 | #define PIN67_PINREG PINK
312 | #define PIN68_PINREG PINK
313 | #define PIN69_PINREG PINK
314 |
315 | #elif defined (__AVR_ATmega644P__)
316 | // Sanguino
317 |
318 | #error Sanguino not defined
319 |
320 | #else // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
321 | // 168 and 328 Arduinos
322 |
323 | // Two Wire (aka I2C) ports
324 | #define SDA_PIN 18
325 | #define SCL_PIN 19
326 |
327 | // SPI port
328 | #define SS_PIN 10
329 | #define MOSI_PIN 11
330 | #define MISO_PIN 12
331 | #define SCK_PIN 13
332 |
333 | // bit number for digital pins
334 | #define PIN0_BITNUM 0
335 | #define PIN1_BITNUM 1
336 | #define PIN2_BITNUM 2
337 | #define PIN3_BITNUM 3
338 | #define PIN4_BITNUM 4
339 | #define PIN5_BITNUM 5
340 | #define PIN6_BITNUM 6
341 | #define PIN7_BITNUM 7
342 | #define PIN8_BITNUM 0
343 | #define PIN9_BITNUM 1
344 | #define PIN10_BITNUM 2
345 | #define PIN11_BITNUM 3
346 | #define PIN12_BITNUM 4
347 | #define PIN13_BITNUM 5
348 | #define PIN14_BITNUM 0
349 | #define PIN15_BITNUM 1
350 | #define PIN16_BITNUM 2
351 | #define PIN17_BITNUM 3
352 | #define PIN18_BITNUM 4
353 | #define PIN19_BITNUM 5
354 |
355 | // output register for all pins
356 | #define PIN0_PORTREG PORTD
357 | #define PIN1_PORTREG PORTD
358 | #define PIN2_PORTREG PORTD
359 | #define PIN3_PORTREG PORTD
360 | #define PIN4_PORTREG PORTD
361 | #define PIN5_PORTREG PORTD
362 | #define PIN6_PORTREG PORTD
363 | #define PIN7_PORTREG PORTD
364 | #define PIN8_PORTREG PORTB
365 | #define PIN9_PORTREG PORTB
366 | #define PIN10_PORTREG PORTB
367 | #define PIN11_PORTREG PORTB
368 | #define PIN12_PORTREG PORTB
369 | #define PIN13_PORTREG PORTB
370 | #define PIN14_PORTREG PORTC
371 | #define PIN15_PORTREG PORTC
372 | #define PIN16_PORTREG PORTC
373 | #define PIN17_PORTREG PORTC
374 | #define PIN18_PORTREG PORTC
375 | #define PIN19_PORTREG PORTC
376 |
377 | // direction control register for digital pins
378 | #define PIN0_DDRREG DDRD
379 | #define PIN1_DDRREG DDRD
380 | #define PIN2_DDRREG DDRD
381 | #define PIN3_DDRREG DDRD
382 | #define PIN4_DDRREG DDRD
383 | #define PIN5_DDRREG DDRD
384 | #define PIN6_DDRREG DDRD
385 | #define PIN7_DDRREG DDRD
386 | #define PIN8_DDRREG DDRB
387 | #define PIN9_DDRREG DDRB
388 | #define PIN10_DDRREG DDRB
389 | #define PIN11_DDRREG DDRB
390 | #define PIN12_DDRREG DDRB
391 | #define PIN13_DDRREG DDRB
392 | #define PIN14_DDRREG DDRC
393 | #define PIN15_DDRREG DDRC
394 | #define PIN16_DDRREG DDRC
395 | #define PIN17_DDRREG DDRC
396 | #define PIN18_DDRREG DDRC
397 | #define PIN19_DDRREG DDRC
398 |
399 | // input register for digital pins
400 | #define PIN0_PINREG PIND
401 | #define PIN1_PINREG PIND
402 | #define PIN2_PINREG PIND
403 | #define PIN3_PINREG PIND
404 | #define PIN4_PINREG PIND
405 | #define PIN5_PINREG PIND
406 | #define PIN6_PINREG PIND
407 | #define PIN7_PINREG PIND
408 | #define PIN8_PINREG PINB
409 | #define PIN9_PINREG PINB
410 | #define PIN10_PINREG PINB
411 | #define PIN11_PINREG PINB
412 | #define PIN12_PINREG PINB
413 | #define PIN13_PINREG PINB
414 | #define PIN14_PINREG PINC
415 | #define PIN15_PINREG PINC
416 | #define PIN16_PINREG PINC
417 | #define PIN17_PINREG PINC
418 | #define PIN18_PINREG PINC
419 | #define PIN19_PINREG PINC
420 | #endif // defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
421 | #endif // ArduinoPins_h
422 |
--------------------------------------------------------------------------------
/libraries/WaveHC/FatReader.cpp:
--------------------------------------------------------------------------------
1 | /* Arduino FatReader Library
2 | * Copyright (C) 2009 by William Greiman
3 | *
4 | * This file is part of the Arduino FatReader Library
5 | *
6 | * This Library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This Library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with the Arduino FatReader Library. If not, see
18 | * .
19 | */
20 | #include
21 | #if ARDUINO < 100
22 | #include
23 | #else // ARDUINO
24 | #include
25 | #endif // ARDUINO
26 | #include
27 | //------------------------------------------------------------------------------
28 | /**
29 | * Format the name field of the dir_t struct \a dir into the 13 byte array
30 | * \a name in the standard 8.3 short name format.
31 | */
32 | void dirName(dir_t &dir, char name[]) {
33 | uint8_t j = 0;
34 | for (uint8_t i = 0; i < 11; i++) {
35 | if (dir.name[i] == ' ')continue;
36 | if (i == 8) name[j++] = '.';
37 | name[j++] = dir.name[i];
38 | }
39 | name[j] = 0;
40 | }
41 | //------------------------------------------------------------------------------
42 | /**
43 | * Print the name field of a dir_t structure in 8.3 format.
44 | * Append a '/' if it is a subdirectory.
45 | *
46 | */
47 | void printEntryName(dir_t &dir) {
48 | for (uint8_t i = 0; i < 11; i++) {
49 | if (dir.name[i] == ' ')continue;
50 | if (i == 8) Serial.write('.');
51 | Serial.write(dir.name[i]);
52 | }
53 | if (DIR_IS_SUBDIR(dir)) {
54 | // indicate subdirectory
55 | Serial.write('/');
56 | }
57 | }
58 | //------------------------------------------------------------------------------
59 | /**
60 | * List file in a directory
61 | *
62 | */
63 | void FatReader::ls(uint8_t flags) {
64 | dir_t d;
65 | if (isDir()) lsR(d, flags, 0);
66 | }
67 | //------------------------------------------------------------------------------
68 | // recursive part of ls()
69 | void FatReader::lsR(dir_t &d, uint8_t flags, uint8_t indent) {
70 | while (readDir(d) > 0) {
71 |
72 | // print any indent spaces
73 | for (int8_t i = 0; i < indent; i++) {
74 | Serial.write(' ');
75 | }
76 | printEntryName(d);
77 |
78 | if (DIR_IS_SUBDIR(d)) {
79 | Serial.println();
80 | // recursive call if LS_R
81 | if (flags & LS_R) {
82 | FatReader s;
83 | if (s.open(*vol_, d)) {
84 | s.lsR(d, flags, indent + 2);
85 | }
86 | }
87 | }
88 | else {
89 | if (flags & LS_FLAG_FRAGMENTED) {
90 | uint32_t c = (uint32_t)d.firstClusterHigh << 16;
91 | c |= d.firstClusterLow;
92 |
93 | // fragmented if has clusters and not contiguous
94 | char f = c && !vol_->chainIsContiguous(c) ? '*' : ' ';
95 | Serial.write(' ');
96 | Serial.write(f);
97 | }
98 | if (flags & LS_SIZE) {
99 | Serial.write(' ');
100 | Serial.print(d.fileSize);
101 | }
102 | Serial.println();
103 | }
104 | }
105 | }
106 | //------------------------------------------------------------------------------
107 | /** return the next cluster in a chain */
108 | uint32_t FatVolume::nextCluster(uint32_t cluster) {
109 | if (!validCluster(cluster)) {
110 | return 0;
111 | }
112 | if (fatType_ == 32) {
113 | uint32_t next;
114 | uint32_t block = fatStartBlock_ + (cluster >> 7);
115 | uint16_t offset = 0X1FF & (cluster << 2);
116 | if (!rawRead(block, offset, (uint8_t *)&next, 4)) {
117 | return 0;
118 | }
119 | return next;
120 | }
121 | if (fatType_ == 16) {
122 | uint16_t next;
123 | uint32_t block = fatStartBlock_ + (cluster >> 8);
124 | uint16_t offset = 0X1FF & (cluster << 1);
125 | if (!rawRead(block, offset, (uint8_t *)&next, 2)) {
126 | return 0;
127 | }
128 | return next;
129 | }
130 | return 0;
131 | }
132 | //------------------------------------------------------------------------------
133 | /**
134 | * Open a file or subdirectory by index.
135 | *
136 | * \param[in] dir An open FatReader instance for the directory.
137 | *
138 | * \param[in] index The \a index for a file or subdirectory in the
139 | * directory \a dir. \a index is the byte offset divided by 32 of
140 | * the directory entry for the file or subdirectory.
141 | *
142 | * To determine the index for a file open it by name. The index for the
143 | * file is then is: (dir.readPosition()/32 -1)
144 | *
145 | *
146 | * \return The value one, true, is returned for success and
147 | * the value zero, false, is returned for failure.
148 | * Reasons for failure include the FAT volume has not been initialized, \a dir
149 | * is not a directory, \a name is invalid, the file or subdirectory does not
150 | * exist, or an I/O error occurred.
151 | */
152 | uint8_t FatReader::open(FatReader &dir, uint16_t index) {
153 | dir_t d;
154 |
155 | // position directory file to entry
156 | if (!dir.seekSet(32UL*index)) return false;
157 |
158 | // read entry
159 | if (dir.read(&d, 32) != 32) return false;
160 |
161 | // must be a real file or directory
162 | if (!DIR_IS_FILE_OR_SUBDIR(d)
163 | || d.name[0] == DIR_NAME_FREE
164 | || d.name[0] == DIR_NAME_DELETED) {
165 | return false;
166 | }
167 | return open(*dir.volume(), d);
168 | }
169 | //------------------------------------------------------------------------------
170 | /**
171 | * Open a file or subdirectory by name.
172 | *
173 | * \note The file or subdirectory, \a name, must be in the specified
174 | * directory, \a dir, and must have a DOS 8.3 name.
175 | *
176 | * \param[in] dir An open FatReader instance for the directory.
177 | *
178 | * \param[in] name A valid 8.3 DOS name for a file or subdirectory in the
179 | * directory \a dir.
180 | *
181 | * \return The value one, true, is returned for success and
182 | * the value zero, false, is returned for failure.
183 | * Reasons for failure include the FAT volume has not been initialized, \a dir
184 | * is not a directory, \a name is invalid, the file or subdirectory does not
185 | * exist, or an I/O error occurred.
186 | */
187 | uint8_t FatReader::open(FatReader &dir, char *name) {
188 | dir_t entry;
189 | char dname[13];
190 |
191 | dir.rewind();
192 | while(dir.readDir(entry) > 0) {
193 | dirName(entry, dname);
194 | if (strcasecmp(dname, name)) continue;
195 | return open(*(dir.vol_), entry);
196 | }
197 | return false;
198 | }
199 | //------------------------------------------------------------------------------
200 | /**
201 | * Open a file or subdirectory by directory structure.
202 | *
203 | * \param[in] vol The FAT volume that contains the file or subdirectory.
204 | *
205 | * \param[in] dir The directory structure describing the file or subdirectory.
206 | *
207 | * \return The value one, true, is returned for success and
208 | * the value zero, false, is returned for failure.
209 | * Reasons for failure include the FAT volume, \a vol, has not been initialized,
210 | * \a vol is a FAT12 volume or \a dir is not a valid directory entry.
211 | */
212 | uint8_t FatReader::open(FatVolume &vol, dir_t &dir) {
213 | if (vol.fatType() < 16) return false;
214 | if (dir.name[0] == 0 || dir.name[0] == DIR_NAME_DELETED) {
215 | return false;
216 | }
217 | firstCluster_ = (uint32_t)dir.firstClusterHigh << 16;
218 | firstCluster_ |= dir.firstClusterLow;
219 | if (DIR_IS_FILE(dir)) {
220 | type_ = FILE_TYPE_NORMAL;
221 | fileSize_ = dir.fileSize;
222 | }
223 | else if (DIR_IS_SUBDIR(dir)) {
224 | type_ = FILE_TYPE_SUBDIR;
225 | fileSize_ = vol.chainSize(firstCluster_);
226 | }
227 | else {
228 | return false;
229 | }
230 | vol_ = &vol;
231 | rewind();
232 | return true;
233 | }
234 | //------------------------------------------------------------------------------
235 | /**
236 | * Open a volume's root directory.
237 | *
238 | * \param[in] vol The FAT volume containing the root directory to be opened.
239 | *
240 | * \return The value one, true, is returned for success and
241 | * the value zero, false, is returned for failure.
242 | * Reasons for failure include the FAT volume has not been initialized
243 | * or it a FAT12 volume.
244 | */
245 | uint8_t FatReader::openRoot(FatVolume &vol) {
246 | if(vol.fatType() == 16) {
247 | type_ = FILE_TYPE_ROOT16;
248 | firstCluster_ = 0;
249 | fileSize_ = 32*vol.rootDirEntryCount();
250 | }
251 | else if (vol.fatType() == 32) {
252 | type_ = FILE_TYPE_ROOT32;
253 | firstCluster_ = vol.rootDirStart();
254 | fileSize_ = vol.chainSize(firstCluster_);
255 | }
256 | else {
257 | return false;
258 | }
259 | vol_ = &vol;
260 | rewind();
261 | return true;
262 | }
263 | //------------------------------------------------------------------------------
264 | /**
265 | * Check for a contiguous file and enable optimized reads if the
266 | * file is contiguous.
267 | */
268 | void FatReader::optimizeContiguous(void) {
269 | if (isOpen() && firstCluster_) {
270 | if (vol_->chainIsContiguous(firstCluster_)) {
271 | type_ |= FILE_IS_CONTIGUOUS;
272 | }
273 | }
274 | }
275 | //------------------------------------------------------------------------------
276 | /**
277 | * Read data from a file at starting at the current read position.
278 | *
279 | * \param[out] buf Pointer to the location that will receive the data.
280 | *
281 | * \param[in] count Maximum number of bytes to read.
282 | *
283 | * \return For success read() returns the number of bytes read.
284 | * A value less than \a count, including zero, will be returned
285 | * if end of file is reached.
286 | * If an error occurs, read() returns -1. Possible errors include
287 | * read() called before a file has been opened, corrupt file system
288 | * or an I/O error occurred.
289 | */
290 | int16_t FatReader::read(void *buf, uint16_t count) {
291 | uint8_t *dst = (uint8_t *)buf;
292 | uint16_t nr = 0;
293 | int16_t n = 0;
294 | while (nr < count && (n = readBlockData(dst, count - nr)) > 0) {
295 | if (!seekCur(n)) return -1;
296 | dst += n;
297 | nr += n;
298 | }
299 | return n < 0 ? -1 : nr;
300 | }
301 | //------------------------------------------------------------------------------
302 | // read maximum amount possible from current physical block
303 | int16_t FatReader::readBlockData(uint8_t *dst, uint16_t count) {
304 | uint32_t block;
305 | uint16_t offset = readPosition_ & 0X1FF;
306 | if (count > (512 - offset)) count = 512 - offset;
307 | if (count > (fileSize_ - readPosition_)) count = fileSize_ - readPosition_;
308 | if (fileType() == FILE_TYPE_ROOT16) {
309 | block = vol_->rootDirStart() + (readPosition_ >> 9);
310 | }
311 | else {
312 | uint8_t bpc = vol_->blocksPerCluster();
313 | block = vol_->dataStartBlock() + (readCluster_ - 2)*bpc
314 | + ((readPosition_ >> 9) & (bpc -1));
315 | }
316 | return vol_->rawRead(block, offset, dst, count) ? count : -1;
317 | }
318 | //------------------------------------------------------------------------------
319 | /**
320 | * Read the next directory entry from a directory file.
321 | *
322 | * \param[out] dir The dir_t struct that will receive the data.
323 | *
324 | * \return For success readDir() returns the number of bytes read.
325 | * A value of zero will be returned if end of file is reached.
326 | * If an error occurs, readDir() returns -1. Possible errors include
327 | * readDir() called before a directory has been opened, this is not
328 | * a directory file or an I/O error occurred.
329 | */
330 | int8_t FatReader::readDir(dir_t &dir) {
331 | int8_t n;
332 | //if not a directory file return an error
333 | if (!isDir()) return -1;
334 | while ((n = read((uint8_t *)&dir, sizeof(dir_t))) == sizeof(dir_t)
335 | && dir.name[0] != DIR_NAME_FREE) {
336 | if (dir.name[0] == DIR_NAME_DELETED || dir.name[0] == '.') continue;
337 | if (DIR_IS_FILE(dir) || DIR_IS_SUBDIR(dir)) return n;
338 | }
339 | return n < 0 ? n : 0;
340 | }
341 | //------------------------------------------------------------------------------
342 | /** Set read position to start of file */
343 | void FatReader::rewind(void) {
344 | readCluster_ = firstCluster_;
345 | readPosition_ = 0;
346 | }
347 | /**
348 | * Set the read position for a file or directory to the current position plus
349 | * \a offset.
350 | *
351 | * \param[in] offset The amount to advance the read position.
352 | *
353 | * \return The value one, true, is returned for success and
354 | * the value zero, false, is returned for failure.
355 | */
356 | uint8_t FatReader::seekCur(uint32_t offset) {
357 |
358 | uint32_t newPos = readPosition_ + offset;
359 |
360 | // can't position beyond end of file
361 | if (newPos > fileSize_) return false;
362 |
363 | // number of clusters forward
364 | uint32_t nc = (newPos >> 9)/vol_->blocksPerCluster()
365 | - (readPosition_ >> 9)/vol_->blocksPerCluster();
366 |
367 | // set new position - only corrupt file system can cause error now
368 | readPosition_ = newPos;
369 |
370 | // no clusters if FAT16 root
371 | if (fileType() == FILE_TYPE_ROOT16) return true;
372 |
373 | // don't need to read FAT if contiguous
374 | if (isContiguous()) {
375 | readCluster_ += nc;
376 | return true;
377 | }
378 |
379 | // read FAT chain while nc != 0
380 | while (nc-- != 0) {
381 | if (!(readCluster_ = vol_->nextCluster(readCluster_))) {
382 | return false;
383 | }
384 | }
385 | return true;
386 | }
387 | //------------------------------------------------------------------------------
388 | /** check for contiguous chain */
389 | uint8_t FatVolume::chainIsContiguous(uint32_t cluster) {
390 | uint32_t next;
391 | while((next = nextCluster(cluster))) {
392 | if (next != (cluster + 1)) {
393 | return isEOC(next);
394 | }
395 | cluster = next;
396 | }
397 | return false;
398 | }
399 | //------------------------------------------------------------------------------
400 | /** return the number of bytes in a cluster chain */
401 | uint32_t FatVolume::chainSize(uint32_t cluster) {
402 | uint32_t size = 0;
403 | while ((cluster = nextCluster(cluster))) {
404 | size += 512*blocksPerCluster_;
405 | }
406 | return size;
407 | }
408 | //------------------------------------------------------------------------------
409 | /**
410 | * Initialize a FAT volume.
411 | *
412 | * \param[in] dev The SD card where the volume is located.
413 | *
414 | * \param[in] part The partition to be used. Legal values for \a part are
415 | * 1-4 to use the corresponding partition on a device formatted with
416 | * a MBR, Master Boot Record, or zero if the device is formatted as
417 | * a super floppy with the FAT boot sector in block zero.
418 | *
419 | * \return The value one, true, is returned for success and
420 | * the value zero, false, is returned for failure. Reasons for
421 | * failure include not finding a valid partition, not finding a valid
422 | * FAT file system in the specified partition or an I/O error.
423 | */
424 | uint8_t FatVolume::init(SdReader &dev, uint8_t part) {
425 | uint8_t buf[BPB_COUNT];
426 | uint32_t volumeStartBlock = 0;
427 | rawDevice_ = &dev;
428 | // if part == 0 assume super floppy with FAT boot sector in block zero
429 | // if part > 0 assume mbr volume with partition table
430 | if (part) {
431 | if (part > 4) return false;
432 |
433 | if (!rawRead(volumeStartBlock, PART_OFFSET + 16*(part-1), buf, 16)) {
434 | return false;
435 | }
436 | part_t *part = (part_t *)buf;
437 | if ((part->boot & 0X7F) !=0 ||
438 | part->totalSectors < 100 ||
439 | part->firstSector == 0) {
440 | //not a valid partition
441 | return false;
442 | }
443 | volumeStartBlock = part->firstSector;
444 | }
445 | if (!rawRead(volumeStartBlock, BPB_OFFSET, buf, BPB_COUNT)) {
446 | return false;
447 | }
448 | bpb_t *bpb = (bpb_t *)buf;
449 | if (bpb->bytesPerSector != 512 ||
450 | bpb->fatCount == 0 ||
451 | bpb->reservedSectorCount == 0 ||
452 | bpb->sectorsPerCluster == 0 ||
453 | (bpb->sectorsPerCluster & (bpb->sectorsPerCluster - 1)) != 0) {
454 | // not valid FAT volume
455 | return false;
456 | }
457 | fatCount_ = bpb->fatCount;
458 | blocksPerCluster_ = bpb->sectorsPerCluster;
459 | blocksPerFat_ = bpb->sectorsPerFat16 ? bpb->sectorsPerFat16 : bpb->sectorsPerFat32;
460 | rootDirEntryCount_ = bpb->rootDirEntryCount;
461 | fatStartBlock_ = volumeStartBlock + bpb->reservedSectorCount;
462 | rootDirStart_ = fatStartBlock_ + bpb->fatCount*blocksPerFat_;
463 | dataStartBlock_ = rootDirStart_ + ((32*bpb->rootDirEntryCount + 511)/512);
464 | totalBlocks_ = bpb->totalSectors16 ? bpb->totalSectors16 : bpb->totalSectors32;
465 | clusterCount_ = (totalBlocks_ - (dataStartBlock_ - volumeStartBlock))
466 | /bpb->sectorsPerCluster;
467 | if (clusterCount_ < 4085) {
468 | fatType_ = 12;
469 | }
470 | else if (clusterCount_ < 65525) {
471 | fatType_ = 16;
472 | }
473 | else {
474 | rootDirStart_ = bpb->fat32RootCluster;
475 | fatType_ = 32;
476 | }
477 | return true;
478 | }
479 |
--------------------------------------------------------------------------------
/libraries/WaveHC/FatReader.h:
--------------------------------------------------------------------------------
1 | /* Arduino FatReader Library
2 | * Copyright (C) 2009 by William Greiman
3 | *
4 | * This file is part of the Arduino FatReader Library
5 | *
6 | * This Library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This Library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with the Arduino FatReader Library. If not, see
18 | * .
19 | */
20 | #ifndef FatReader_h
21 | #define FatReader_h
22 | #include
23 | #include
24 |
25 | // flags for ls()
26 | /** ls() flag to print modify date */
27 | #define LS_FLAG_FRAGMENTED 1
28 | /** ls() flag to print file size */
29 | #define LS_SIZE 2
30 | /** ls() flag for recursive list of subdirectories */
31 | #define LS_R 4
32 |
33 | // offsets for structures used in volume init
34 | /** Offset to BIOS Parameter Block in FAT Boot Sector */
35 | #define BPB_OFFSET 11
36 | /** Byte count for part of BIOS Parameter Block to be read by init() */
37 | #define BPB_COUNT 37
38 | /** offset to partition table in mbr */
39 | #define PART_OFFSET (512-64-2)
40 |
41 | // format dir.name into name[13] as standard 8.3 string
42 | void dirName(dir_t &dir, char name[]);
43 | // Print name field of dir_t struct in 8.3 format
44 | void printEntryName(dir_t &dir);
45 | //------------------------------------------------------------------------------
46 | /** \class FatVolume
47 | * \brief FatVolume provides access to FAT volumes.
48 | */
49 | class FatVolume {
50 | /** Allow FatReader access to FatVolume private data. */
51 | friend class FatReader;
52 | uint8_t blocksPerCluster_;
53 | uint32_t blocksPerFat_;
54 | uint32_t clusterCount_;
55 | uint32_t dataStartBlock_;
56 | uint8_t fatCount_;
57 | uint32_t fatStartBlock_;
58 | uint8_t fatType_;
59 | SdReader *rawDevice_;
60 | uint16_t rootDirEntryCount_;
61 | uint32_t rootDirStart_;
62 | uint32_t totalBlocks_;
63 | uint8_t chainIsContiguous(uint32_t cluster);
64 | uint32_t chainSize(uint32_t cluster);
65 | uint8_t isEOC(uint32_t cluster)
66 | {return cluster >= (fatType_ == 16 ? FAT16EOC_MIN : FAT32EOC_MIN);}
67 | uint32_t nextCluster(uint32_t cluster);
68 | uint8_t rawRead(uint32_t block, uint16_t offset, uint8_t *dst, uint16_t count)
69 | {return rawDevice_->readData(block, offset, dst, count);}
70 | uint8_t validCluster(uint32_t cluster) {
71 | return (1 < cluster && cluster < (clusterCount_ + 2));}
72 | public:
73 | /** Create an instance of FatVolume */
74 | FatVolume(void) : fatType_(0){}
75 | /**
76 | * Initialize a FAT volume. Try partition one first then try super
77 | * floppy format.
78 | *
79 | * \param[in] dev The SdReader where the volume is located.
80 | *
81 | * \return The value one, true, is returned for success and
82 | * the value zero, false, is returned for failure. Reasons for
83 | * failure include not finding a valid partition, not finding a valid
84 | * FAT file system or an I/O error.
85 | */
86 | uint8_t init(SdReader &dev) { return init(dev, 1) ? 1 : init(dev, 0);}
87 | uint8_t init(SdReader &dev, uint8_t part);
88 |
89 | // inline functions that return volume info
90 | /** \return The volume's cluster size in blocks. */
91 | uint8_t blocksPerCluster(void) {return blocksPerCluster_;}
92 | /** \return The number of blocks in one FAT. */
93 | uint32_t blocksPerFat(void) {return blocksPerFat_;}
94 | /** \return The total number of clusters in the volume. */
95 | uint32_t clusterCount(void) {return clusterCount_;}
96 | /** \return The logical block number for the start of file data. */
97 | uint32_t dataStartBlock(void) {return dataStartBlock_;}
98 | /** \return The number of FAT structures on the volume. */
99 | uint8_t fatCount(void) {return fatCount_;}
100 | /** \return The logical block number for the start of the first FAT. */
101 | uint32_t fatStartBlock(void) {return fatStartBlock_;}
102 | /** \return The FAT type of the volume. Values are 12, 16 or 32. */
103 | uint8_t fatType(void) {return fatType_;}
104 | /** Raw device for this volume */
105 | SdReader *rawDevice(void) {return rawDevice_;}
106 | /** \return The number of entries in the root directory for FAT16 volumes. */
107 | uint32_t rootDirEntryCount(void) {return rootDirEntryCount_;}
108 | /** \return The logical block number for the start of the root directory
109 | on FAT16 volumes or the first cluster number on FAT32 volumes. */
110 | uint32_t rootDirStart(void) {return rootDirStart_;}
111 | /** \return The total number of blocks in the volume. */
112 | uint32_t totalBlocks(void) {return totalBlocks_;}
113 | };
114 | //------------------------------------------------------------------------------
115 | /** \class FatReader
116 | * \brief FatReader implements a minimal FAT16/FAT32 file reader class.
117 | */
118 | class FatReader {
119 | // values for type_
120 | /** File is contiguous file */
121 | #define FILE_IS_CONTIGUOUS 0X08
122 | /** File type mask */
123 | #define FILE_TYPE_MASK 0X07
124 | /** This FatReader has not been opened. */
125 | #define FILE_TYPE_CLOSED 0X00
126 | /** FatReader for a file */
127 | #define FILE_TYPE_NORMAL 0X01
128 | /** FatReader for a FAT16 root directory */
129 | #define FILE_TYPE_ROOT16 0X02
130 | /** FatReader for a FAT32 root directory */
131 | #define FILE_TYPE_ROOT32 0X03
132 | /** FatReader for a subdirectory */
133 | #define FILE_TYPE_SUBDIR 0X04
134 | /** Test value for directory type */
135 | #define FILE_TYPE_MIN_DIR FILE_TYPE_ROOT16
136 | uint8_t type_;
137 | uint32_t fileSize_;
138 | uint32_t readCluster_;
139 | uint32_t readPosition_;
140 | uint32_t firstCluster_;
141 | FatVolume *vol_;
142 | int16_t readBlockData(uint8_t *dst, uint16_t count);
143 | void lsR(dir_t &d, uint8_t flags, uint8_t indent);
144 | public:
145 | /** Create an instance of FatReader. */
146 | FatReader(void) : type_(FILE_TYPE_CLOSED) {}
147 | void ls(uint8_t flags = 0);
148 | uint8_t openRoot(FatVolume &vol);
149 | uint8_t open(FatVolume &vol, dir_t &dir);
150 | uint8_t open(FatReader &dir, char *name);
151 | uint8_t open(FatReader &dir, uint16_t index);
152 | void optimizeContiguous(void);
153 | int16_t read(void *buf, uint16_t count);
154 | int8_t readDir(dir_t &dir);
155 | void rewind(void);
156 | uint8_t seekCur(uint32_t pos);
157 | //inline functions
158 | /** Close this instance of FatReader. */
159 | void close(void) {type_ = FILE_TYPE_CLOSED;}
160 | /** \return The total number of bytes in a file or directory. */
161 | uint32_t fileSize(void) {return fileSize_;}
162 | /**
163 | * Type of this FatReader. You should use isFile() or isDir()
164 | * instead of type() if possible.
165 | *
166 | * \return The file or directory type.
167 | */
168 | uint8_t fileType(void) {return type_ & FILE_TYPE_MASK;}
169 | /** \return The first cluster number for a file or directory. */
170 | uint32_t firstCluster(void) {return firstCluster_;}
171 | /**
172 | * \return True if the bit for optimized reads is set.
173 | * See optimizeContiguous(). */
174 | uint8_t isContiguous(void) {return type_ & FILE_IS_CONTIGUOUS;}
175 | /** \return True if this is a FatReader for a directory else false */
176 | uint8_t isDir(void) {return fileType() >= FILE_TYPE_MIN_DIR;}
177 | /** \return True if this is a FatReader for a file else false */
178 | uint8_t isFile(void) {return fileType() == FILE_TYPE_NORMAL;}
179 | /** \return True if FatReader is for an open file/directory else false */
180 | uint8_t isOpen(void) {return fileType() != FILE_TYPE_CLOSED;}
181 | /** \return The current cluster number for a file or directory. */
182 | uint32_t readCluster(void) {return readCluster_;}
183 | /** \return The read position for a file or directory. */
184 | uint32_t readPosition(void) {return readPosition_;}
185 | /**
186 | * Set the read position for a file or directory to \a pos.
187 | *
188 | * \param[in] pos The new read position in bytes from the beginning
189 | * of the file.
190 | *
191 | * \return The value one, true, is returned for success and
192 | * the value zero, false, is returned for failure.
193 | */
194 | uint8_t seekSet(uint32_t pos) {
195 | if (pos >= readPosition_) return seekCur(pos - readPosition_);
196 | rewind(); return seekCur(pos);}
197 | /** Parent volume */
198 | FatVolume *volume(void) {return vol_;}
199 | };
200 | #endif//FatReader_h
201 |
--------------------------------------------------------------------------------
/libraries/WaveHC/FatStructs.h:
--------------------------------------------------------------------------------
1 | #ifndef FatStructs_h
2 | #define FatStructs_h
3 | /**
4 | * \file
5 | * FAT file structures
6 | */
7 | /*
8 | * mostly from Microsoft document fatgen103.doc
9 | * http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
10 | */
11 | //------------------------------------------------------------------------------
12 | /** Value for byte 510 of boot block or MBR */
13 | #define BOOTSIG0 0X55
14 | /** Value for byte 511 of boot block or MBR */
15 | #define BOOTSIG1 0XAA
16 | //------------------------------------------------------------------------------
17 | /**
18 | * \struct partitionTable
19 | * \brief MBR partition table entry
20 | *
21 | * A partition table entry for a MBR formatted storage device.
22 | * The MBR partition table has four entries.
23 | */
24 | struct partitionTable {
25 | /**
26 | * Boot Indicator . Indicates whether the volume is the active
27 | * partition. Legal values include: 0X00. Do not use for booting.
28 | * 0X80 Active partition.
29 | */
30 | uint8_t boot;
31 | /**
32 | * Head part of Cylinder-head-sector address of the first block in
33 | * the partition. Legal values are 0-255. Only used in old PC BIOS.
34 | */
35 | uint8_t beginHead;
36 | /**
37 | * Sector part of Cylinder-head-sector address of the first block in
38 | * the partition. Legal values are 1-63. Only used in old PC BIOS.
39 | */
40 | unsigned beginSector : 6;
41 | /** High bits cylinder for first block in partition. */
42 | unsigned beginCylinderHigh : 2;
43 | /**
44 | * Combine beginCylinderLow with beginCylinderHigh. Legal values
45 | * are 0-1023. Only used in old PC BIOS.
46 | */
47 | uint8_t beginCylinderLow;
48 | /**
49 | * Partition type. See defines that begin with PART_TYPE_ for
50 | * some Microsoft partition types.
51 | */
52 | uint8_t type;
53 | /**
54 | * head part of cylinder-head-sector address of the last sector in the
55 | * partition. Legal values are 0-255. Only used in old PC BIOS.
56 | */
57 | uint8_t endHead;
58 | /**
59 | * Sector part of cylinder-head-sector address of the last sector in
60 | * the partition. Legal values are 1-63. Only used in old PC BIOS.
61 | */
62 | unsigned endSector : 6;
63 | /** High bits of end cylinder */
64 | unsigned endCylinderHigh : 2;
65 | /**
66 | * Combine endCylinderLow with endCylinderHigh. Legal values
67 | * are 0-1023. Only used in old PC BIOS.
68 | */
69 | uint8_t endCylinderLow;
70 | /** Logical block address of the first block in the partition. */
71 | uint32_t firstSector;
72 | /** Length of the partition, in blocks. */
73 | uint32_t totalSectors;
74 | };
75 | /** Type name for partitionTable */
76 | typedef struct partitionTable part_t;
77 | //------------------------------------------------------------------------------
78 | /**
79 | * \struct masterBootRecord
80 | *
81 | * \brief Master Boot Record
82 | *
83 | * The first block of a storage device that is formatted with a MBR.
84 | */
85 | struct masterBootRecord {
86 | /** Code Area for master boot program. */
87 | uint8_t codeArea[440];
88 | /** Optional WindowsNT disk signature. May contain more boot code. */
89 | uint32_t diskSignature;
90 | /** Usually zero but may be more boot code. */
91 | uint16_t usuallyZero;
92 | /** Partition tables. */
93 | part_t part[4];
94 | /** First MBR signature byte. Must be 0X55 */
95 | uint8_t mbrSig0;
96 | /** Second MBR signature byte. Must be 0XAA */
97 | uint8_t mbrSig1;
98 | };
99 | /** Type name for masterBootRecord */
100 | typedef struct masterBootRecord mbr_t;
101 | //------------------------------------------------------------------------------
102 | /**
103 | * \struct biosParmBlock
104 | *
105 | * \brief BIOS parameter block
106 | *
107 | * The BIOS parameter block describes the physical layout of a FAT volume.
108 | */
109 | struct biosParmBlock{
110 | /**
111 | * Count of bytes per sector. This value may take on only the
112 | * following values: 512, 1024, 2048 or 4096
113 | */
114 | uint16_t bytesPerSector;
115 | /**
116 | * Number of sectors per allocation unit. This value must be a
117 | * power of 2 that is greater than 0. The legal values are
118 | * 1, 2, 4, 8, 16, 32, 64, and 128.
119 | */
120 | uint8_t sectorsPerCluster;
121 | /**
122 | * Number of sectors before the first FAT.
123 | * This value must not be zero.
124 | */
125 | uint16_t reservedSectorCount;
126 | /** The count of FAT data structures on the volume. This field should
127 | * always contain the value 2 for any FAT volume of any type.
128 | */
129 | uint8_t fatCount;
130 | /**
131 | * For FAT12 and FAT16 volumes, this field contains the count of
132 | * 32-byte directory entries in the root directory. For FAT32 volumes,
133 | * this field must be set to 0. For FAT12 and FAT16 volumes, this
134 | * value should always specify a count that when multiplied by 32
135 | * results in a multiple of bytesPerSector. FAT16 volumes should
136 | * use the value 512.
137 | */
138 | uint16_t rootDirEntryCount;
139 | /**
140 | * This field is the old 16-bit total count of sectors on the volume.
141 | * This count includes the count of all sectors in all four regions
142 | * of the volume. This field can be 0; if it is 0, then totalSectors32
143 | * must be nonzero. For FAT32 volumes, this field must be 0. For
144 | * FAT12 and FAT16 volumes, this field contains the sector count, and
145 | * totalSectors32 is 0 if the total sector count fits
146 | * (is less than 0x10000).
147 | */
148 | uint16_t totalSectors16;
149 | /**
150 | * This dates back to the old MS-DOS 1.x media determination and is
151 | * no longer usually used for anything. 0xF8 is the standard value
152 | * for fixed (nonremovable) media. For removable media, 0xF0 is
153 | * frequently used. Legal values are 0xF0 or 0xF8-0xFF.
154 | */
155 | uint8_t mediaType;
156 | /**
157 | * Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
158 | * On FAT32 volumes this field must be 0, and sectorsPerFat32
159 | * contains the FAT size count.
160 | */
161 | uint16_t sectorsPerFat16;
162 | /** Sectors per track for interrupt 0x13. Not used otherwise. */
163 | uint16_t sectorsPerTrtack;
164 | /** Number of heads for interrupt 0x13. Not used otherwise. */
165 | uint16_t headCount;
166 | /**
167 | * Count of hidden sectors preceding the partition that contains this
168 | * FAT volume. This field is generally only relevant for media
169 | * visible on interrupt 0x13.
170 | */
171 | uint32_t hidddenSectors;
172 | /**
173 | * This field is the new 32-bit total count of sectors on the volume.
174 | * This count includes the count of all sectors in all four regions
175 | * of the volume. This field can be 0; if it is 0, then
176 | * totalSectors16 must be nonzero.
177 | */
178 | uint32_t totalSectors32;
179 | /**
180 | * Count of sectors occupied by one FAT on FAT32 volumes.
181 | */
182 | uint32_t sectorsPerFat32;
183 | /**
184 | * This field is only defined for FAT32 media and does not exist on
185 | * FAT12 and FAT16 media.
186 | * Bits 0-3 -- Zero-based number of active FAT.
187 | * Only valid if mirroring is disabled.
188 | * Bits 4-6 -- Reserved.
189 | * Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
190 | * -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
191 | * Bits 8-15 -- Reserved.
192 | */
193 | uint16_t fat32Flags;
194 | /**
195 | * FAT32 version. High byte is major revision number.
196 | * Low byte is minor revision number. Only 0.0 define.
197 | */
198 | uint16_t fat32Version;
199 | /**
200 | * Cluster number of the first cluster of the root directory for FAT32.
201 | * This usually 2 but not required to be 2.
202 | */
203 | uint32_t fat32RootCluster;
204 | /**
205 | * Sector number of FSINFO structure in the reserved area of the
206 | * FAT32 volume. Usually 1.
207 | */
208 | uint16_t fat32FSInfo;
209 | /**
210 | * If nonzero, indicates the sector number in the reserved area
211 | * of the volume of a copy of the boot record. Usually 6.
212 | * No value other than 6 is recommended.
213 | */
214 | uint16_t fat32BackBootBlock;
215 | /**
216 | * Reserved for future expansion. Code that formats FAT32 volumes
217 | * should always set all of the bytes of this field to 0.
218 | */
219 | uint8_t fat32Reserved[12];
220 | };
221 | /** Type name for biosParmBlock */
222 | typedef struct biosParmBlock bpb_t;
223 | //------------------------------------------------------------------------------
224 | /**
225 | * \struct fat32BootSector
226 | *
227 | * \brief Boot sector for a FAT16 or FAT32 volume.
228 | *
229 | */
230 | struct fat32BootSector {
231 | /** X86 jmp to boot program */
232 | uint8_t jmpToBootCode[3];
233 | /** informational only - don't depend on it */
234 | char oemName[8];
235 | /** BIOS Parameter Block */
236 | bpb_t bpb;
237 | /** for int0x13 use value 0X80 for hard drive */
238 | uint8_t driveNumber;
239 | /**used by Windows NT - should be zero for FAT */
240 | uint8_t reserved1;
241 | /** 0X29 if next three fields are valid */
242 | uint8_t bootSignature;
243 | /** usually generated by combining date and time */
244 | uint32_t volumeSerialNumber;
245 | /** should match volume label in root dir */
246 | char volumeLabel[11];
247 | /** informational only - don't depend on it */
248 | char fileSystemType[8];
249 | /** X86 boot code */
250 | uint8_t bootCode[420];
251 | /** must be 0X55 */
252 | uint8_t bootSectorSig0;
253 | /** must be 0XAA */
254 | uint8_t bootSectorSig1;
255 | };
256 | //------------------------------------------------------------------------------
257 | // End Of Chain values for FAT entries
258 | /** Minimum value for FAT16 EOC. Use to test for EOC. */
259 | #define FAT16EOC_MIN 0XFFF8
260 | /** Minimum value for FAT32 EOC. Use to test for EOC. */
261 | #define FAT32EOC_MIN 0X0FFFFFF8
262 | /** FAT16 end of chain value used by Microsoft. */
263 | #define FAT16EOC 0XFFFF
264 | /** FAT32 end of chain value used by Microsoft. */
265 | #define FAT32EOC 0X0FFFFFFF
266 | /** Mask a for FAT32 entry. Entries are 28 bits. */
267 | #define FAT32MASK 0X0FFFFFFF
268 |
269 | /** Type name for fat32BootSector */
270 | typedef struct fat32BootSector fbs_t;
271 | //------------------------------------------------------------------------------
272 | /**
273 | * \struct directoryEntry
274 | * \brief FAT short directory entry
275 | *
276 | * Short means short 8.3 name, not the entry size.
277 | *
278 | * Date Format. A FAT directory entry date stamp is a 16-bit field that is
279 | * basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
280 | * format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
281 | * 16-bit word):
282 | *
283 | * Bits 9-15: Count of years from 1980, valid value range 0-127
284 | * inclusive (1980-2107).
285 | *
286 | * Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
287 | *
288 | * Bits 0-4: Day of month, valid value range 1-31 inclusive.
289 | *
290 | * Time Format. A FAT directory entry time stamp is a 16-bit field that has
291 | * a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
292 | * 16-bit word, bit 15 is the MSB of the 16-bit word).
293 | *
294 | * Bits 11-15: Hours, valid value range 0-23 inclusive.
295 | *
296 | * Bits 5-10: Minutes, valid value range 0-59 inclusive.
297 | *
298 | * Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
299 | *
300 | * The valid time range is from Midnight 00:00:00 to 23:59:58.
301 | */
302 | struct directoryEntry {
303 | /**
304 | * Short 8.3 name.
305 | * The first eight bytes contain the file name with blank fill.
306 | * The last three bytes contain the file extension with blank fill.
307 | */
308 | uint8_t name[11];
309 | /** Entry attributes.
310 | *
311 | * The upper two bits of the attribute byte are reserved and should
312 | * always be set to 0 when a file is created and never modified or
313 | * looked at after that. See defines that begin with DIR_ATT_.
314 | */
315 | uint8_t attributes;
316 | /**
317 | * Reserved for use by Windows NT. Set value to 0 when a file is
318 | * created and never modify or look at it after that.
319 | */
320 | uint8_t reservedNT;
321 | /**
322 | * The granularity of the seconds part of creationTime is 2 seconds
323 | * so this field is a count of tenths of a second and its valid
324 | * value range is 0-199 inclusive. (WHG note - seems to be hundredths)
325 | */
326 | uint8_t creationTimeTenths;
327 | /** Time file was created. */
328 | uint16_t creationTime;
329 | /** Date file was created. */
330 | uint16_t creationDate;
331 | /**
332 | * Last access date. Note that there is no last access time, only
333 | * a date. This is the date of last read or write. In the case of
334 | * a write, this should be set to the same date as lastWriteDate.
335 | */
336 | uint16_t lastAccessDate;
337 | /**
338 | * High word of this entry's first cluster number (always 0 for a
339 | * FAT12 or FAT16 volume).
340 | */
341 | uint16_t firstClusterHigh;
342 | /** Time of last write. File creation is considered a write. */
343 | uint16_t lastWriteTime;
344 | /** Date of last write. File creation is considered a write. */
345 | uint16_t lastWriteDate;
346 | /** Low word of this entry's first cluster number. */
347 | uint16_t firstClusterLow;
348 | /** 32-bit unsigned holding this file's size in bytes. */
349 | uint32_t fileSize;
350 | };
351 | //------------------------------------------------------------------------------
352 | // Macros for directory entries
353 | //
354 | /** Type name for directoryEntry */
355 | typedef struct directoryEntry dir_t;
356 | /** escape for name[0] = 0XE5 */
357 | #define DIR_NAME_0XE5 0X05
358 | /** name[0] value for entry that is free after being "deleted" */
359 | #define DIR_NAME_DELETED 0XE5
360 | /** name[0] value for entry that is free and no allocated entries follow */
361 | #define DIR_NAME_FREE 0X00
362 | /** file is read-only */
363 | #define DIR_ATT_READ_ONLY 0X01
364 | /** File should hidden in directory listings */
365 | #define DIR_ATT_HIDDEN 0X02
366 | /** Entry is for a system file */
367 | #define DIR_ATT_SYSTEM 0X04
368 | /** Directory entry contains the volume label */
369 | #define DIR_ATT_VOLUME_ID 0X08
370 | /** Entry is for a directory */
371 | #define DIR_ATT_DIRECTORY 0X10
372 | /** Old DOS archive bit for backup support */
373 | #define DIR_ATT_ARCHIVE 0X20
374 | /** Test value for long name entry. Test is
375 | d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
376 | #define DIR_ATT_LONG_NAME 0X0F
377 | /** Test mask for long name entry */
378 | #define DIR_ATT_LONG_NAME_MASK 0X3F
379 | /** defined attribute bits */
380 | #define DIR_ATT_DEFINED_BITS 0X3F
381 | /** Directory entry is part of a long name */
382 | #define DIR_IS_LONG_NAME(dir)\
383 | (((dir).attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME)
384 | /** Mask for file/subdirectory tests */
385 | #define DIR_ATT_FILE_TYPE_MASK (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY)
386 | /** Directory entry is for a file */
387 | #define DIR_IS_FILE(dir) (((dir).attributes & DIR_ATT_FILE_TYPE_MASK) == 0)
388 | /** Directory entry is for a subdirectory */
389 | #define DIR_IS_SUBDIR(dir)\
390 | (((dir).attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY)
391 | /** Directory entry is for a file or subdirectory */
392 | #define DIR_IS_FILE_OR_SUBDIR(dir) (((dir).attributes & DIR_ATT_VOLUME_ID) == 0)
393 | #endif //FatStructs_h
394 |
--------------------------------------------------------------------------------
/libraries/WaveHC/SdInfo.h:
--------------------------------------------------------------------------------
1 | /* Arduino Sd2Card Library
2 | * Copyright (C) 2009 by William Greiman
3 | *
4 | * This file is part of the Arduino Sd2Card Library
5 | *
6 | * This Library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This Library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with the Arduino Sd2Card Library. If not, see
18 | * .
19 | */
20 | #ifndef SdInfo_h
21 | #define SdInfo_h
22 | #include
23 | //Based on the document:
24 | //
25 | //SD Specifications
26 | //Part 1
27 | //Physical Layer
28 | //Simplified Specification
29 | //Version 2.00
30 | //September 25, 2006
31 | //
32 | //www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
33 | //------------------------------------------------------------------------------
34 | // SD card commands
35 | /** GO_IDLE_STATE - init card in spi mode if CS low */
36 | #define CMD0 0X00
37 | /** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
38 | #define CMD8 0X08
39 | /** SEND_CSD - read the Card Specific Data (CSD register) */
40 | #define CMD9 0X09
41 | /** SEND_CID - read the card identification information (CID register) */
42 | #define CMD10 0X0A
43 | /** SEND_STATUS - read the card status register */
44 | #define CMD13 0X0D
45 | /** READ_BLOCK - read a single data block from the card */
46 | #define CMD17 0X11
47 | /** WRITE_BLOCK - write a single data block to the card */
48 | #define CMD24 0X18
49 | /** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
50 | #define CMD25 0X19
51 | /** ERASE_WR_BLK_START - sets the address of the first block to be erased */
52 | #define CMD32 0X20
53 | /** ERASE_WR_BLK_END - sets the address of the last block of the continuous
54 | range to be erased*/
55 | #define CMD33 0X21
56 | /** ERASE - erase all previously selected blocks */
57 | #define CMD38 0X26
58 | /** APP_CMD - escape for application specific command */
59 | #define CMD55 0X37
60 | /** READ_OCR - read the OCR register of a card */
61 | #define CMD58 0X3A
62 | /** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
63 | pre-erased before writing */
64 | #define ACMD23 0X17
65 | /** SD_SEND_OP_COMD - Sends host capacity support information and
66 | activates the card's initialization process */
67 | #define ACMD41 0X29
68 | //------------------------------------------------------------------------------
69 | /** status for card in the ready state */
70 | #define R1_READY_STATE 0
71 | /** status for card in the idle state */
72 | #define R1_IDLE_STATE 1
73 | /** status bit for illegal command */
74 | #define R1_ILLEGAL_COMMAND 4
75 | /** start data token for read or write single block*/
76 | #define DATA_START_BLOCK 0XFE
77 | /** stop token for write multiple blocks*/
78 | #define STOP_TRAN_TOKEN 0XFD
79 | /** start data token for write multiple blocks*/
80 | #define WRITE_MULTIPLE_TOKEN 0XFC
81 | /** mask for data response tokens after a write block operation */
82 | #define DATA_RES_MASK 0X1F
83 | /** write data accepted token */
84 | #define DATA_RES_ACCEPTED 0X05
85 | //------------------------------------------------------------------------------
86 | typedef struct CID {
87 | //byte 0
88 | uint8_t mid;//Manufacturer ID
89 | //byte 1-2
90 | char oid[2];//OEM/Application ID
91 | //byte 3-7
92 | char pnm[5];//Product name
93 | //byte 8
94 | unsigned prv_m : 4;// Product revision n.m
95 | unsigned prv_n : 4;
96 | //byte 9-12
97 | uint32_t psn;//Product serial number
98 | //byte 13
99 | unsigned mdt_year_high : 4;//Manufacturing date
100 | unsigned reserved : 4;
101 | //byte 14
102 | unsigned mdt_month : 4;
103 | unsigned mdt_year_low :4;
104 | //byte 15
105 | unsigned always1 : 1;
106 | unsigned crc : 7;
107 | }cid_t;
108 | //------------------------------------------------------------------------------
109 | // CSD for version 1.00 cards
110 | typedef struct CSDV1 {
111 | //byte 0
112 | unsigned reserved1 : 6;
113 | unsigned csd_ver : 2;
114 | //byte 1
115 | uint8_t taac;
116 | //byte 2
117 | uint8_t nsac;
118 | //byte 3
119 | uint8_t tran_speed;
120 | //byte 4
121 | uint8_t ccc_high;
122 | //byte 5
123 | unsigned read_bl_len : 4;
124 | unsigned ccc_low : 4;
125 | // unsigned read_bl_len : 4;
126 | //byte 6
127 | unsigned c_size_high : 2;
128 | unsigned reserved2 : 2;
129 | unsigned dsr_imp : 1;
130 | unsigned read_blk_misalign :1;
131 | unsigned write_blk_misalign : 1;
132 | unsigned read_bl_partial : 1;
133 | //byte 7
134 | uint8_t c_size_mid;
135 | //byte 8
136 | unsigned vdd_r_curr_max : 3;
137 | unsigned vdd_r_curr_min : 3;
138 | unsigned c_size_low :2;
139 | //byte 9
140 | unsigned c_size_mult_high : 2;
141 | unsigned vdd_w_cur_max : 3;
142 | unsigned vdd_w_curr_min : 3;
143 | //byte 10
144 | unsigned sector_size_high : 6;
145 | unsigned erase_blk_en : 1;
146 | unsigned c_size_mult_low : 1;
147 | //byte 11
148 | unsigned wp_grp_size : 7;
149 | unsigned sector_size_low : 1;
150 | //byte 12
151 | unsigned write_bl_len_high : 2;
152 | unsigned r2w_factor : 3;
153 | unsigned reserved3 : 2;
154 | unsigned wp_grp_enable : 1;
155 | //byte 13
156 | unsigned reserved4 : 5;
157 | unsigned write_partial : 1;
158 | unsigned write_bl_len_low : 2;
159 | //byte 14
160 | unsigned reserved5: 2;
161 | unsigned file_format : 2;
162 | unsigned tmp_write_protect : 1;
163 | unsigned perm_write_protect : 1;
164 | unsigned copy : 1;
165 | unsigned file_format_grp : 1;
166 | //byte 15
167 | unsigned always1 : 1;
168 | unsigned crc : 7;
169 | }csd1_t;
170 | //------------------------------------------------------------------------------
171 | // CSD for version 2.00 cards
172 | typedef struct CSDV2 {
173 | //byte 0
174 | unsigned reserved1 : 6;
175 | unsigned csd_ver : 2;
176 | //byte 1
177 | uint8_t taac;
178 | //byte 2
179 | uint8_t nsac;
180 | //byte 3
181 | uint8_t tran_speed;
182 | //byte 4
183 | uint8_t ccc_high;
184 | //byte 5
185 | unsigned read_bl_len : 4;
186 | unsigned ccc_low : 4;
187 | //byte 6
188 | unsigned reserved2 : 4;
189 | unsigned dsr_imp : 1;
190 | unsigned read_blk_misalign :1;
191 | unsigned write_blk_misalign : 1;
192 | unsigned read_bl_partial : 1;
193 | //byte 7
194 | unsigned reserved3 : 2;
195 | unsigned c_size_high : 6;
196 | //byte 8
197 | uint8_t c_size_mid;
198 | //byte 9
199 | uint8_t c_size_low;
200 | //byte 10
201 | unsigned sector_size_high : 6;
202 | unsigned erase_blk_en : 1;
203 | unsigned reserved4 : 1;
204 | //byte 11
205 | unsigned wp_grp_size : 7;
206 | unsigned sector_size_low : 1;
207 | //byte 12
208 | unsigned write_bl_len_high : 2;
209 | unsigned r2w_factor : 3;
210 | unsigned reserved5 : 2;
211 | unsigned wp_grp_enable : 1;
212 | //byte 13
213 | unsigned reserved6 : 5;
214 | unsigned write_partial : 1;
215 | unsigned write_bl_len_low : 2;
216 | //byte 14
217 | unsigned reserved7: 2;
218 | unsigned file_format : 2;
219 | unsigned tmp_write_protect : 1;
220 | unsigned perm_write_protect : 1;
221 | unsigned copy : 1;
222 | unsigned file_format_grp : 1;
223 | //byte 15
224 | unsigned always1 : 1;
225 | unsigned crc : 7;
226 | }csd2_t;
227 | //------------------------------------------------------------------------------
228 | // union of old and new style CSD register
229 | union csd_t {
230 | csd1_t v1;
231 | csd2_t v2;
232 | };
233 | #endif //SdInfo_h
234 |
--------------------------------------------------------------------------------
/libraries/WaveHC/SdReader.cpp:
--------------------------------------------------------------------------------
1 | /* Arduino WaveHC Library
2 | * Copyright (C) 2008 by William Greiman
3 | *
4 | * This file is part of the Arduino WaveHC Library
5 | *
6 | * This Library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This Library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with the Arduino WaveHC Library. If not, see
18 | * .
19 | */
20 | #if ARDUINO < 100
21 | #include
22 | #else // ARDUINO < 100
23 | #include
24 | #endif // ARDUINO < 100
25 | #include
26 | #include
27 | //------------------------------------------------------------------------------
28 | // inline SPI functions
29 | /** Send a byte to the card */
30 | inline void spiSend(uint8_t b) {SPDR = b; while(!(SPSR & (1 << SPIF)));}
31 | /** Receive a byte from the card */
32 | inline uint8_t spiRec(void) {spiSend(0XFF); return SPDR;}
33 | /** Set Slave Select high */
34 | inline void spiSSHigh(void) {
35 | digitalWrite(SS, HIGH);
36 | // insure SD data out is high Z
37 | spiSend(0XFF);
38 | }
39 | /** Set Slave Select low */
40 | inline void spiSSLow(void) {digitalWrite(SS, LOW);}
41 | //------------------------------------------------------------------------------
42 | // card status
43 | /** status for card in the ready state */
44 | #define R1_READY_STATE 0
45 | /** status for card in the idle state */
46 | #define R1_IDLE_STATE 1
47 | /** start data token for read or write */
48 | #define DATA_START_BLOCK 0XFE
49 | /** mask for data response tokens after a write block operation */
50 | #define DATA_RES_MASK 0X1F
51 | /** write data accepted token */
52 | #define DATA_RES_ACCEPTED 0X05
53 | /** write data crc error token */
54 | #define DATA_RES_CRC_ERROR 0X0B
55 | /** write data programming error token */
56 | #define DATA_RES_WRITE_ERROR 0X0D
57 | //------------------------------------------------------------------------------
58 | // send command to card
59 | uint8_t SdReader::cardCommand(uint8_t cmd, uint32_t arg) {
60 | uint8_t r1;
61 |
62 | // end read if in partialBlockRead mode
63 | readEnd();
64 |
65 | // select card
66 | spiSSLow();
67 |
68 | // wait up to 300 ms if busy
69 | waitNotBusy(300);
70 |
71 | // send command
72 | spiSend(cmd | 0x40);
73 |
74 | // send argument
75 | for (int8_t s = 24; s >= 0; s -= 8) spiSend(arg >> s);
76 |
77 | // send CRC
78 | uint8_t crc = 0XFF;
79 | if (cmd == CMD0) crc = 0X95; // correct crc for CMD0 with arg 0
80 | if (cmd == CMD8) crc = 0X87; // correct crc for CMD8 with arg 0X1AA
81 | spiSend(crc);
82 |
83 | // wait for response
84 | for (uint8_t retry = 0; ((r1 = spiRec()) & 0X80) && retry != 0XFF; retry++);
85 |
86 | return r1;
87 | }
88 | //------------------------------------------------------------------------------
89 | /**
90 | * Determine the size of an SD flash memory card.
91 | * \return The number of 512 byte data blocks in the card
92 | */
93 | uint32_t SdReader::cardSize(void) {
94 | csd_t csd;
95 | if (!readCSD(csd)) return false;
96 | if (csd.v1.csd_ver == 0) {
97 | uint8_t read_bl_len = csd.v1.read_bl_len;
98 | uint16_t c_size = (csd.v1.c_size_high << 10)
99 | | (csd.v1.c_size_mid << 2) | csd.v1.c_size_low;
100 | uint8_t c_size_mult = (csd.v1.c_size_mult_high << 1)
101 | | csd.v1.c_size_mult_low;
102 | return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
103 | }
104 | else if (csd.v2.csd_ver == 1) {
105 | uint32_t c_size = ((uint32_t)csd.v2.c_size_high << 16)
106 | | (csd.v2.c_size_mid << 8) | csd.v2.c_size_low;
107 | return (c_size + 1) << 10;
108 | }
109 | else {
110 | error(SD_CARD_ERROR_BAD_CSD);
111 | return 0;
112 | }
113 | }
114 | //------------------------------------------------------------------------------
115 | /**
116 | * Initialize a SD flash memory card.
117 | *
118 | * \param[in] slow If \a slow is false (zero) the SPI bus will
119 | * be initialize at a speed of 8 Mhz. If \a slow is true (nonzero)
120 | * the SPI bus will be initialize a speed of 4 Mhz. This may be helpful
121 | * for some SD cards with Version 1.0 of the Adafruit Wave Shield.
122 | *
123 | * \return The value one, true, is returned for success and
124 | * the value zero, false, is returned for failure.
125 | *
126 | */
127 | uint8_t SdReader::init(uint8_t slow) {
128 | uint8_t ocr[4];
129 | uint8_t r;
130 |
131 | pinMode(SS, OUTPUT);
132 | digitalWrite(SS, HIGH);
133 | pinMode(MOSI, OUTPUT);
134 | pinMode(MISO_PIN, INPUT);
135 | pinMode(SCK, OUTPUT);
136 |
137 | #if SPI_INIT_SLOW
138 | // Enable SPI, Master, clock rate f_osc/128
139 | SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1) | (1 << SPR0);
140 | #else // SPI_INIT_SLOW
141 | // Enable SPI, Master, clock rate f_osc/64
142 | SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR1);
143 | #endif // SPI_INIT_SLOW
144 |
145 | // must supply min of 74 clock cycles with CS high.
146 | for (uint8_t i = 0; i < 10; i++) spiSend(0XFF);
147 |
148 | // next two lines prevent re-init hang by cards that were in partial read
149 | spiSSLow();
150 | for (uint16_t i = 0; i <= 512; i++) spiRec();
151 |
152 | // command to go idle in SPI mode
153 | for (uint8_t retry = 0; ; retry++) {
154 | if ((r = cardCommand(CMD0, 0)) == R1_IDLE_STATE) break;
155 | if (retry == 10) {
156 | error(SD_CARD_ERROR_CMD0, r);
157 | return false;
158 | }
159 | }
160 | // check SD version
161 | r = cardCommand(CMD8, 0x1AA);
162 | if (r == R1_IDLE_STATE) {
163 | for(uint8_t i = 0; i < 4; i++) {
164 | r = spiRec();
165 | }
166 | if (r != 0XAA) {
167 | error(SD_CARD_ERROR_CMD8_ECHO, r);
168 | return false;
169 | }
170 | type(SD_CARD_TYPE_SD2);
171 | }
172 | else if (r & R1_ILLEGAL_COMMAND) {
173 | type(SD_CARD_TYPE_SD1);
174 | }
175 | else {
176 | error(SD_CARD_ERROR_CMD8, r);
177 | }
178 | // initialize card and send host supports SDHC if SD2
179 | for (uint16_t t0 = millis();;) {
180 | cardCommand(CMD55, 0);
181 | r = cardCommand(ACMD41, type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0);
182 | if (r == R1_READY_STATE) break;
183 |
184 | // timeout after 2 seconds
185 | if (((uint16_t)millis() - t0) > 2000) {
186 | error(SD_CARD_ERROR_ACMD41);
187 | return false;
188 | }
189 | }
190 | // if SD2 read OCR register to check for SDHC card
191 | if (type() == SD_CARD_TYPE_SD2) {
192 | if(cardCommand(CMD58, 0)) {
193 | error(SD_CARD_ERROR_CMD58);
194 | return false;
195 | }
196 | if ((spiRec() & 0XC0) == 0XC0) type(SD_CARD_TYPE_SDHC);
197 |
198 | // discard rest of ocr
199 | for (uint8_t i = 0; i < 3; i++) spiRec();
200 | }
201 |
202 | // use max SPI frequency unless slow is true
203 | SPCR &= ~((1 << SPR1) | (1 << SPR0)); // f_OSC/4
204 |
205 | if (!slow) SPSR |= (1 << SPI2X); // Doubled Clock Frequency: f_OSC/2
206 | spiSSHigh();
207 | return true;
208 | }
209 | //------------------------------------------------------------------------------
210 | /**
211 | * Read part of a 512 byte block from a SD card.
212 | *
213 | * \param[in] block Logical block to be read.
214 | * \param[in] offset Number of bytes to skip at start of block
215 | * \param[out] dst Pointer to the location that will receive the data.
216 | * \param[in] count Number of bytes to read
217 | * \return The value one, true, is returned for success and
218 | * the value zero, false, is returned for failure.
219 | */
220 | uint8_t SdReader::readData(uint32_t block,
221 | uint16_t offset, uint8_t *dst, uint16_t count) {
222 | if (count == 0) return true;
223 | if ((count + offset) > 512) {
224 | return false;
225 | }
226 | if (!inBlock_ || block != block_ || offset < offset_) {
227 | block_ = block;
228 |
229 | // use address if not SDHC card
230 | if (type()!= SD_CARD_TYPE_SDHC) block <<= 9;
231 | if (cardCommand(CMD17, block)) {
232 | error(SD_CARD_ERROR_CMD17);
233 | return false;
234 | }
235 | if (!waitStartBlock()) {
236 | return false;
237 | }
238 | offset_ = 0;
239 | inBlock_ = 1;
240 | }
241 |
242 | // start first SPI transfer
243 | SPDR = 0XFF;
244 |
245 | // skip data before offset
246 | for (;offset_ < offset; offset_++) {
247 | while(!(SPSR & (1 << SPIF)));
248 | SPDR = 0XFF;
249 | }
250 |
251 | // transfer data
252 | uint16_t n = count - 1;
253 | for (uint16_t i = 0; i < n; i++) {
254 | while(!(SPSR & (1 << SPIF)));
255 | dst[i] = SPDR;
256 | SPDR = 0XFF;
257 | }
258 |
259 | // wait for last byte
260 | while(!(SPSR & (1 << SPIF)));
261 | dst[n] = SPDR;
262 | offset_ += count;
263 | if (!partialBlockRead_ || offset_ >= 512) readEnd();
264 | return true;
265 | }
266 | //------------------------------------------------------------------------------
267 | /** Skip remaining data in a block when in partial block read mode. */
268 | void SdReader::readEnd(void) {
269 | if (inBlock_) {
270 | // skip data and crc
271 | SPDR = 0XFF;
272 | while (offset_++ < 513) {
273 | while(!(SPSR & (1 << SPIF)));
274 | SPDR = 0XFF;
275 | }
276 | // wait for last crc byte
277 | while(!(SPSR & (1 << SPIF)));
278 | spiSSHigh();
279 | inBlock_ = 0;
280 | }
281 | }
282 | //------------------------------------------------------------------------------
283 | /** read CID or CSR register */
284 | uint8_t SdReader::readRegister(uint8_t cmd, uint8_t *dst) {
285 | if (cardCommand(cmd, 0)) {
286 | error(SD_CARD_ERROR_READ_REG);
287 | return false;
288 | }
289 | if(!waitStartBlock()) return false;
290 |
291 | //transfer data
292 | for (uint16_t i = 0; i < 16; i++) dst[i] = spiRec();
293 |
294 | spiRec();// get first crc byte
295 | spiRec();// get second crc byte
296 |
297 | spiSSHigh();
298 | return true;
299 | }
300 | //------------------------------------------------------------------------------
301 | // wait for card to go not busy
302 | uint8_t SdReader::waitNotBusy(uint16_t timeoutMillis) {
303 | uint16_t t0 = millis();
304 | while (spiRec() != 0XFF) {
305 | if (((uint16_t)millis() - t0) > timeoutMillis) return false;
306 | }
307 | return true;
308 | }
309 | //------------------------------------------------------------------------------
310 | /** Wait for start block token */
311 | uint8_t SdReader::waitStartBlock(void) {
312 | uint8_t r;
313 | uint16_t t0 = millis();
314 | while ((r = spiRec()) == 0XFF) {
315 | if (((uint16_t)millis() - t0) > SD_READ_TIMEOUT) {
316 | error(SD_CARD_ERROR_READ_TIMEOUT);
317 | return false;
318 | }
319 | }
320 | if (r == DATA_START_BLOCK) return true;
321 | error(SD_CARD_ERROR_READ, r);
322 | return false;
323 | }
324 |
--------------------------------------------------------------------------------
/libraries/WaveHC/SdReader.h:
--------------------------------------------------------------------------------
1 | /* Arduino WaveHC Library
2 | * Copyright (C) 2008 by William Greiman
3 | *
4 | * This file is part of the Arduino FAT16 Library
5 | *
6 | * This Library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This Library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 |
16 | * You should have received a copy of the GNU General Public License
17 | * along with the Arduino Fat16 Library. If not, see
18 | * .
19 | */
20 | #ifndef SdReader_h
21 | #define SdReader_h
22 | #include
23 | /**
24 | * \file
25 | * SdReader class
26 | */
27 | /**
28 | * Some SD card are very sensitive to the SPI bus speed for initialization.
29 | * Try setting SPI_INIT_SLOW nonzero if you have initialization problems.
30 | *
31 | * Set SPI_INIT_SLOW nonzero to reduce the SPI bus speed for SD initaizaton
32 | * to F_CPU/128. F_CPU/64 is used if
33 | */
34 | #define SPI_INIT_SLOW 0
35 | /**
36 | * Default card SPI speed. Change to true for Wave Shield V1.0
37 | * The SPI speed is 4 Mhz for 'true' and 8 Mhz for 'false'.
38 | */
39 | #define SPI_DEFAULT_HALF_SPEED false
40 |
41 | /** read timeout ms */
42 | #define SD_READ_TIMEOUT 300
43 |
44 | // SD card errors
45 | /** timeout error for command CMD0 */
46 | #define SD_CARD_ERROR_CMD0 0X1
47 | /** CMD8 was not accepted - not a valid SD card*/
48 | #define SD_CARD_ERROR_CMD8 0X2
49 | /** card returned an error response for CMD17 (read block) */
50 | #define SD_CARD_ERROR_CMD17 0X3
51 | /** card returned an error response for CMD24 (write block) */
52 | #define SD_CARD_ERROR_CMD24 0X4
53 | /** card returned an error response for CMD58 (read OCR) */
54 | #define SD_CARD_ERROR_CMD58 0X5
55 | /** card's ACMD41 initialization process timeout */
56 | #define SD_CARD_ERROR_ACMD41 0X6
57 | /** card returned a bad CSR version field */
58 | #define SD_CARD_ERROR_BAD_CSD 0X7
59 | /** read CID or CSD failed */
60 | #define SD_CARD_ERROR_READ_REG 0X8
61 | /** bad response echo from CMD8 */
62 | #define SD_CARD_ERROR_CMD8_ECHO 0X09
63 | /** timeout while waiting for start of read data */
64 | #define SD_CARD_ERROR_READ_TIMEOUT 0XD
65 | /** card returned an error token instead of read data */
66 | #define SD_CARD_ERROR_READ 0X10
67 | //
68 | // card types
69 | /** Standard capacity V1 SD card */
70 | #define SD_CARD_TYPE_SD1 1
71 | /** Standard capacity V2 SD card */
72 | #define SD_CARD_TYPE_SD2 2
73 | /** High Capacity SD card */
74 | #define SD_CARD_TYPE_SDHC 3
75 | //------------------------------------------------------------------------------
76 | /**
77 | * \class SdReader
78 | * \brief Hardware access class for SD flash cards
79 | *
80 | * Supports raw access to SD and SDHC flash memory cards.
81 | *
82 | */
83 | class SdReader {
84 | uint32_t block_;
85 | uint8_t errorCode_;
86 | uint8_t errorData_;
87 | uint8_t inBlock_;
88 | uint16_t offset_;
89 | uint8_t partialBlockRead_;
90 | uint8_t response_;
91 | uint8_t type_;
92 | uint8_t cardCommand(uint8_t cmd, uint32_t arg);
93 | void error(uint8_t code){errorCode_ = code;}
94 | void error(uint8_t code, uint8_t data) {errorCode_ = code; errorData_ = data;}
95 | uint8_t readRegister(uint8_t cmd, uint8_t *dst);
96 | void type(uint8_t value) {type_ = value;}
97 | uint8_t waitNotBusy(uint16_t timeoutMillis);
98 | uint8_t waitStartBlock(void);
99 | public:
100 | /** Construct an instance of SdReader. */
101 | SdReader(void) : errorCode_(0), inBlock_(0), partialBlockRead_(0), type_(0) {};
102 | uint32_t cardSize(void);
103 | /** \return error code for last error */
104 | uint8_t errorCode(void) {return errorCode_;}
105 | /** \return error data for last error */
106 | uint8_t errorData(void) {return errorData_;}
107 | uint8_t init(uint8_t slow = SPI_DEFAULT_HALF_SPEED);
108 | /**
109 | * Enable or disable partial block reads.
110 | *
111 | * Enabling partial block reads improves performance by allowing a block
112 | * to be read over the SPI bus as several sub-blocks. Errors will occur
113 | * if the time between reads is too long since the SD card will timeout.
114 | *
115 | * Use this for applications like the Adafruit Wave Shield.
116 | *
117 | * \param[in] value The value TRUE (non-zero) or FALSE (zero).)
118 | */
119 | void partialBlockRead(uint8_t value) {readEnd(); partialBlockRead_ = value;}
120 | /**
121 | * Read a 512 byte block from a SD card device.
122 | *
123 | * \param[in] block Logical block to be read.
124 | * \param[out] dst Pointer to the location that will receive the data.
125 | *
126 | * \return The value one, true, is returned for success and
127 | * the value zero, false, is returned for failure.
128 | */
129 | uint8_t readBlock(uint32_t block, uint8_t *dst) {
130 | return readData(block, 0, dst, 512);}
131 | uint8_t readData(uint32_t block, uint16_t offset, uint8_t *dst, uint16_t count);
132 | /**
133 | * Read a cards CID register. The CID contains card identification information
134 | * such as Manufacturer ID, Product name, Product serial number and
135 | * Manufacturing date. */
136 | uint8_t readCID(cid_t &cid) {return readRegister(CMD10, (uint8_t *)&cid);}
137 | /**
138 | * Read a cards CSD register. The CSD contains Card-Specific Data that
139 | * provides information regarding access to the card contents. */
140 | uint8_t readCSD(csd_t &csd) {return readRegister(CMD9, (uint8_t *)&csd);}
141 | void readEnd(void);
142 | /** Return the card type: SD V1, SD V2 or SDHC */
143 | uint8_t type() {return type_;}
144 | };
145 | #endif //SdReader_h
146 |
--------------------------------------------------------------------------------
/libraries/WaveHC/WaveHC.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | William Greiman's modified version of Ladyada's wave shield library
3 | I have made many changes that may have introduced bugs. Major changes are:
4 | optimized DAC macros to allow 44.1 k 16-bit files
5 | use of FatReader to read FAT32 and FAT16 files
6 | modified readwavhack to be readWaveData
7 | use standard SD and SDHC flash cards.
8 | skip non-data chunks after fmt chunk
9 | allow 18 byte format chunk if no compression
10 | play stereo as mono by interleaving channels
11 | change method of reading fmt chunk - use union of structs
12 | */
13 |
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 | // verify program assumptions
21 | #if PLAYBUFFLEN != 256 && PLAYBUFFLEN != 512
22 | #error PLAYBUFFLEN must be 256 or 512
23 | #endif // PLAYBUFFLEN
24 |
25 | WaveHC *playing = 0;
26 |
27 | uint8_t buffer1[PLAYBUFFLEN];
28 | uint8_t buffer2[PLAYBUFFLEN];
29 | uint8_t *playend; // end position for current buffer
30 | uint8_t *playpos; // position of next sample
31 | uint8_t *sdbuff; // SD fill buffer
32 | uint8_t *sdend; // end of data in sd buffer
33 |
34 | // status of sd
35 | #define SD_READY 1 // buffer is ready to be played
36 | #define SD_FILLING 2 // buffer is being filled from DS
37 | #define SD_END_FILE 3 // reached end of file
38 | uint8_t sdstatus = 0;
39 |
40 |
41 | //------------------------------------------------------------------------------
42 | // timer interrupt for DAC
43 | ISR(TIMER1_COMPA_vect) {
44 |
45 | if (!playing) return;
46 |
47 | if (playpos >= playend) {
48 | if (sdstatus == SD_READY) {
49 |
50 | // swap double buffers
51 | playpos = sdbuff;
52 | playend = sdend;
53 | sdbuff = sdbuff != buffer1 ? buffer1 : buffer2;
54 |
55 | sdstatus = SD_FILLING;
56 | // interrupt to call SD reader
57 | TIMSK1 |= _BV(OCIE1B);
58 | }
59 | else if (sdstatus == SD_END_FILE) {
60 | playing->stop();
61 | return;
62 | }
63 | else {
64 | // count overrun error if not at end of file
65 | if (playing->remainingBytesInChunk) {
66 | playing->errors++;
67 | }
68 | return;
69 | }
70 | }
71 |
72 | uint8_t dh, dl;
73 | if (playing->BitsPerSample == 16) {
74 |
75 | // 16-bit is signed
76 | dh = 0X80 ^ playpos[1];
77 | dl = playpos[0];
78 | playpos += 2;
79 | }
80 | else {
81 |
82 | // 8-bit is unsigned
83 | dh = playpos[0];
84 | dl = 0;
85 | playpos++;
86 | }
87 |
88 | #if DVOLUME
89 | uint16_t tmp = (dh << 8) | dl;
90 | tmp >>= playing->volume;
91 |
92 | dh = (tmp >> 8);
93 | dl = tmp;
94 |
95 | #endif //DVOLUME
96 |
97 | uint8_t tempCrush;
98 | tempCrush=playing->crush;
99 | dh=dh|tempCrush;
100 | dl=dl|tempCrush;
101 |
102 | // dac chip select low
103 | mcpDacCsLow();
104 |
105 | // send DAC config bits
106 | mcpDacSdiLow();
107 | mcpDacSckPulse(); // DAC A
108 | mcpDacSckPulse(); // unbuffered
109 | mcpDacSdiHigh();
110 | mcpDacSckPulse(); // 1X gain
111 | mcpDacSckPulse(); // no SHDN
112 |
113 | // send high 8 bits
114 | mcpDacSendBit(dh, 7);
115 | mcpDacSendBit(dh, 6);
116 | mcpDacSendBit(dh, 5);
117 | mcpDacSendBit(dh, 4);
118 | mcpDacSendBit(dh, 3);
119 | mcpDacSendBit(dh, 2);
120 | mcpDacSendBit(dh, 1);
121 | mcpDacSendBit(dh, 0);
122 |
123 | // send low 4 bits
124 | mcpDacSendBit(dl, 7);
125 | mcpDacSendBit(dl, 6);
126 | mcpDacSendBit(dl, 5);
127 | mcpDacSendBit(dl, 4);
128 |
129 | // chip select high - done
130 | mcpDacCsHigh();
131 |
132 | }
133 | //------------------------------------------------------------------------------
134 | // this is the interrupt that fills the playbuffer
135 |
136 | ISR(TIMER1_COMPB_vect) {
137 |
138 | // turn off calling interrupt
139 | TIMSK1 &= ~_BV(OCIE1B);
140 |
141 | if (sdstatus != SD_FILLING) return;
142 |
143 | // enable interrupts while reading the SD
144 | sei();
145 |
146 | int16_t read = playing->readWaveData(sdbuff, PLAYBUFFLEN);
147 |
148 | cli();
149 | if (read > 0) {
150 | sdend = sdbuff + read;
151 | sdstatus = SD_READY;
152 | }
153 | else {
154 | sdend = sdbuff;
155 | sdstatus = SD_END_FILE;
156 | }
157 | }
158 | //------------------------------------------------------------------------------
159 | /** create an instance of WaveHC. */
160 | WaveHC::WaveHC(void) {
161 | fd = 0;
162 | }
163 | //------------------------------------------------------------------------------
164 | /**
165 | * Read a wave file's metadata and initialize member variables.
166 | *
167 | * \param[in] f A open FatReader instance for the wave file.
168 | *
169 | * \return The value one, true, is returned for success and
170 | * the value zero, false, is returned for failure. Reasons
171 | * for failure include I/O error, an invalid wave file or a wave
172 | * file with features that WaveHC does not support.
173 | */
174 | uint8_t WaveHC::create(FatReader &f) {
175 | // 18 byte buffer
176 | // can use this since Arduino and RIFF are Little Endian
177 | union {
178 | struct {
179 | char id[4];
180 | uint32_t size;
181 | char data[4];
182 | } riff; // riff chunk
183 | struct {
184 | uint16_t compress;
185 | uint16_t channels;
186 | uint32_t sampleRate;
187 | uint32_t bytesPerSecond;
188 | uint16_t blockAlign;
189 | uint16_t bitsPerSample;
190 | uint16_t extraBytes;
191 | } fmt; // fmt data
192 | } buf;
193 |
194 | #if OPTIMIZE_CONTIGUOUS
195 | // set optimized read for contiguous files
196 | f.optimizeContiguous();
197 | #endif // OPTIMIZE_CONTIGUOUS
198 |
199 | // must start with WAVE header
200 | if (f.read(&buf, 12) != 12
201 | || strncmp(buf.riff.id, "RIFF", 4)
202 | || strncmp(buf.riff.data, "WAVE", 4)) {
203 | return false;
204 | }
205 |
206 | // next chunk must be fmt
207 | if (f.read(&buf, 8) != 8
208 | || strncmp(buf.riff.id, "fmt ", 4)) {
209 | return false;
210 | }
211 |
212 | // fmt chunk size must be 16 or 18
213 | uint16_t size = buf.riff.size;
214 | if (size == 16 || size == 18) {
215 | if (f.read(&buf, size) != (int16_t)size) {
216 | return false;
217 | }
218 | }
219 | else {
220 | // compressed data - force error
221 | buf.fmt.compress = 0;
222 | }
223 |
224 | if (buf.fmt.compress != 1 || (size == 18 && buf.fmt.extraBytes != 0)) {
225 | putstring_nl("Compression not supported");
226 | return false;
227 | }
228 |
229 | Channels = buf.fmt.channels;
230 | if (Channels > 2) {
231 | putstring_nl("Not mono/stereo!");
232 | return false;
233 | }
234 | else if (Channels > 1) {
235 | putstring_nl(" Warning stereo file!");
236 | }
237 |
238 | BitsPerSample = buf.fmt.bitsPerSample;
239 | if (BitsPerSample > 16) {
240 | putstring_nl("More than 16 bits per sample!");
241 | return false;
242 | }
243 |
244 | dwSamplesPerSec = buf.fmt.sampleRate;
245 | uint32_t clockRate = dwSamplesPerSec*Channels;
246 | uint32_t byteRate = clockRate*BitsPerSample/8;
247 |
248 | #if RATE_ERROR_LEVEL > 0
249 | if (clockRate > MAX_CLOCK_RATE
250 | || byteRate > MAX_BYTE_RATE) {
251 | putstring_nl("Sample rate too high!");
252 | if (RATE_ERROR_LEVEL > 1) {
253 | return false;
254 | }
255 | }
256 | else if (byteRate > 44100 && !f.isContiguous()) {
257 | putstring_nl("High rate fragmented file!");
258 | if (RATE_ERROR_LEVEL > 1) {
259 | return false;
260 | }
261 | }
262 | #endif // RATE_ERROR_LEVEL > 0
263 |
264 | fd = &f;
265 |
266 | errors = 0;
267 | isplaying = 0;
268 | remainingBytesInChunk = 0;
269 |
270 | #if DVOLUME
271 | volume = 0;
272 | #endif //DVOLUME
273 | // position to data
274 | return readWaveData(0, 0) < 0 ? false: true;
275 | }
276 | //------------------------------------------------------------------------------
277 | /**
278 | * Returns true if the player is paused else false.
279 | */
280 | uint8_t WaveHC::isPaused(void) {
281 | cli();
282 | uint8_t rtn = isplaying && !(TIMSK1 & _BV(OCIE1A));
283 | sei();
284 | return rtn;
285 | }
286 | //------------------------------------------------------------------------------
287 | /**
288 | * Pause the player.
289 | */
290 | void WaveHC::pause(void) {
291 | cli();
292 | TIMSK1 &= ~_BV(OCIE1A); //disable DAC interrupt
293 | sei();
294 | fd->volume()->rawDevice()->readEnd(); // redo any partial read on resume
295 | }
296 | //------------------------------------------------------------------------------
297 | /**
298 | * Play a wave file.
299 | *
300 | * WaveHC::create() must be called before a file can be played.
301 | *
302 | * Check the member variable WaveHC::isplaying to monitor the status
303 | * of the player.
304 | */
305 | void WaveHC::play(void) {
306 | // setup the interrupt as necessary
307 |
308 | int16_t read;
309 |
310 | playing = this;
311 |
312 | // fill the play buffer
313 | read = readWaveData(buffer1, PLAYBUFFLEN);
314 | if (read <= 0) return;
315 | playpos = buffer1;
316 | playend = buffer1 + read;
317 |
318 | // fill the second buffer
319 | read = readWaveData(buffer2, PLAYBUFFLEN);
320 | if (read < 0) return;
321 | sdbuff = buffer2;
322 | sdend = sdbuff + read;
323 | sdstatus = SD_READY;
324 |
325 | // its official!
326 | isplaying = 1;
327 |
328 | // Setup mode for DAC ports
329 | mcpDacInit();
330 |
331 | // Set up timer one
332 | // Normal operation - no pwm not connected to pins
333 | TCCR1A = 0;
334 | // no prescaling, CTC mode
335 | TCCR1B = _BV(WGM12) | _BV(CS10);
336 | // Sample rate - play stereo interleaved
337 | OCR1A = F_CPU / (dwSamplesPerSec*Channels);
338 | // SD fill interrupt happens at TCNT1 == 1
339 | OCR1B = 1;
340 | // Enable timer interrupt for DAC ISR
341 | TIMSK1 |= _BV(OCIE1A);
342 | }
343 | //------------------------------------------------------------------------------
344 | /** Read wave data.
345 | *
346 | * Not for use in applications. Must be public so SD read ISR can access it.
347 | * Insures SD sectors are aligned with buffers.
348 | */
349 | int16_t WaveHC::readWaveData(uint8_t *buff, uint16_t len) {
350 |
351 | if (remainingBytesInChunk == 0) {
352 | struct {
353 | char id[4];
354 | uint32_t size;
355 | } header;
356 | while (1) {
357 | if (fd->read(&header, 8) != 8) return -1;
358 | if (!strncmp(header.id, "data", 4)) {
359 | remainingBytesInChunk = header.size;
360 | break;
361 | }
362 |
363 | // if not "data" then skip it!
364 | if (!fd->seekCur(header.size)) {
365 | return -1;
366 | }
367 | }
368 | }
369 |
370 | // make sure buffers are aligned on SD sectors
371 | uint16_t maxLen = PLAYBUFFLEN - fd->readPosition() % PLAYBUFFLEN;
372 | if (len > maxLen) len = maxLen;
373 |
374 | if (len > remainingBytesInChunk) {
375 | len = remainingBytesInChunk;
376 | }
377 |
378 | int16_t ret = fd->read(buff, len);
379 | if (ret > 0) remainingBytesInChunk -= ret;
380 | return ret;
381 | }
382 | //------------------------------------------------------------------------------
383 | /** Resume a paused player. */
384 | void WaveHC::resume(void) {
385 | cli();
386 | // enable DAC interrupt
387 | if(isplaying) TIMSK1 |= _BV(OCIE1A);
388 | sei();
389 | }
390 | //------------------------------------------------------------------------------
391 | /**
392 | * Reposition a wave file.
393 | *
394 | * \param[in] pos seek will attempt to position the file near \a pos.
395 | * \a pos is the byte number from the beginning of file.
396 | */
397 | void WaveHC::seek(uint32_t pos) {
398 | // make sure buffer fill interrupt doesn't happen
399 | cli();
400 | if (fd) {
401 | pos -= pos % PLAYBUFFLEN;
402 | if (pos < PLAYBUFFLEN) pos = PLAYBUFFLEN; //don't play metadata
403 | uint32_t maxPos = fd->readPosition() + remainingBytesInChunk;
404 | if (maxPos > fd->fileSize()) maxPos = fd->fileSize();
405 | if (pos > maxPos) pos = maxPos;
406 | if (fd->seekSet(pos)) {
407 | // assumes a lot about the wave file
408 | remainingBytesInChunk = maxPos - pos;
409 | }
410 | }
411 | sei();
412 | }
413 | uint32_t WaveHC::readPositionNow(void){
414 | uint32_t val = fd->readPosition();
415 | return val;
416 | }
417 | //------------------------------------------------------------------------------
418 | /** Set the player's sample rate.
419 | *
420 | * \param[in] samplerate The new sample rate in samples per second.
421 | * No checks are done on the input parameter.
422 | */
423 | void WaveHC::setSampleRate(uint32_t samplerate) {
424 | if (samplerate < 500) samplerate = 500;
425 | if (samplerate > 50000) samplerate = 50000;
426 | // from ladayada's library.
427 | cli();
428 | while (TCNT0 != 0);
429 |
430 | OCR1A = F_CPU / samplerate;
431 | sei();
432 | }
433 | //------------------------------------------------------------------------------
434 | /** Stop the player. */
435 | void WaveHC::stop(void) {
436 | TIMSK1 &= ~_BV(OCIE1A); // turn off interrupt
437 | playing->isplaying = 0;
438 | playing = 0;
439 | }
440 |
--------------------------------------------------------------------------------
/libraries/WaveHC/WaveHC.h:
--------------------------------------------------------------------------------
1 | /*
2 | This library is a highly modified version of Ladyada's Wave Shield library.
3 | I have made many changes that may have introduced bugs.
4 | */
5 | #ifndef WaveHC_h
6 | #define WaveHC_h
7 | #include
8 | /**
9 | * \file
10 | * WaveHC class
11 | */
12 | /**
13 | * If nonzero, optimize the player for contiguous files. It takes
14 | * longer to open a file but can play contiguous files at higher rates.
15 | * Disable if you need minimum latency for open. Also see open by index.
16 | */
17 | #define OPTIMIZE_CONTIGUOUS 1
18 | /**
19 | * Software volume control should be compatible with Ladyada's library.
20 | * Uses shift to decrease volume by 6 dB per step. See DAC ISR in WaveHC.cpp.
21 | * Must be set after call to WaveHC::create().
22 | * Decreases MAX_CLOCK_RATE to 22050.
23 | */
24 | #define DVOLUME 1
25 | /**
26 | * Set behavior for files that exceed MAX_CLOCK_RATE or MAX_BYTE_RATE.
27 | * If RATE_ERROR_LEVEL = 2, rate too high errors are fatal.
28 | * If RATE_ERROR_LEVEL = 1, rate too high errors are warnings.
29 | * If RATE_ERROR_LEVEL = 0, rate too high errors are ignored.
30 | */
31 | #define RATE_ERROR_LEVEL 2
32 | //------------------------------------------------------------------------------
33 | // Set the size for wave data buffers. Must be 256 or 512.
34 | #if defined(__AVR_ATmega168P__) || defined(__AVR_ATmega168__)
35 |
36 | /** Buffer length for for 168 Arduino. */
37 | #define PLAYBUFFLEN 256UL
38 | #else // __AVR_ATmega168P__
39 |
40 | /** Buffer length for Arduinos other than 168. */
41 | #define PLAYBUFFLEN 512UL
42 | #endif //__AVR_ATmega168P__
43 |
44 | // Define max allowed SD read rate in bytes/sec.
45 | #if PLAYBUFFLEN == 512UL && OPTIMIZE_CONTIGUOUS
46 | /** Maximum SD read rate for 512 byte buffer and contiguous file */
47 | #define MAX_BYTE_RATE 88200
48 | #else // MAX_BYTE_RATE
49 | /** Maximum SD read rate for 256 byte buffer or fragmented file */
50 | #define MAX_BYTE_RATE 44100
51 | #endif // MAX_BYTE_RATE
52 |
53 | // Define maximum clock rate for DAC.
54 | #if !DVOLUME
55 | /** maximum DAC clock rate */
56 | #define MAX_CLOCK_RATE 44100
57 | #else // DVOLUME
58 | /** Decreased clock rate if volume control is used */
59 | #define MAX_CLOCK_RATE 22050
60 | #endif //DVOLUME
61 |
62 | //------------------------------------------------------------------------------
63 | /**
64 | * \class WaveHC
65 | * \brief Wave file player.
66 | *
67 | * Play wave files from FAT16 and FAT32 file systems
68 | * on SD and SDHC flash memory cards.
69 | *
70 | */
71 | class WaveHC {
72 | public:
73 | /** Wave file number of channels. Mono = 1, Stereo = 2 */
74 | uint8_t Channels;
75 | /** Wave file sample rate. Must be not greater than 44100/sec. */
76 | uint32_t dwSamplesPerSec;
77 | /** Wave file bits per sample. Must be 8 or 16. */
78 | uint8_t BitsPerSample;
79 | /** Remaining bytes to be played in Wave file data chunk. */
80 | uint32_t remainingBytesInChunk;
81 | /** Has the value true if a wave file is playing else false. */
82 | volatile uint8_t isplaying;
83 | /** Number of times data was not available from the SD in the DAC ISR */
84 | uint32_t errors;
85 |
86 | uint8_t crush;
87 |
88 | #if DVOLUME
89 | /** Software volume control. Reduce volume by 6 dB per step. See DAC ISR. */
90 |
91 | uint8_t volume;
92 |
93 | #endif // DVOLUME
94 | /** FatReader instance for current wave file. */
95 | FatReader* fd;
96 |
97 | WaveHC(void);
98 | uint8_t create(FatReader &f);
99 | /** Return the size of the WAV file */
100 | uint32_t getSize(void) {return fd->fileSize();}
101 | uint8_t isPaused(void);
102 | void pause(void);
103 | void play(void);
104 | int16_t readWaveData(uint8_t *buff, uint16_t len);
105 | uint32_t readPositionNow();
106 | void resume(void);
107 | void seek(uint32_t pos);
108 | void setSampleRate(uint32_t samplerate);
109 | void stop(void);
110 |
111 | };
112 |
113 | #endif //WaveHC_h
114 |
--------------------------------------------------------------------------------
/libraries/WaveHC/WavePinDefs.h:
--------------------------------------------------------------------------------
1 | /**
2 | * \file
3 | * Pin definitions
4 | */
5 | #include
6 | #ifndef WavePinDefs_h
7 | #define WavePinDefs_h
8 |
9 | //SPI pin definitions
10 |
11 | /** SPI slave select pin. Warning: SS may be redefined as another pin
12 | but the hardware SS_PIN must be set to output mode before any calls to
13 | WaveHC functions. The SS_PIN can then be used as a general output pin */
14 | #define SS SS_PIN
15 |
16 | /** SPI master output, slave input pin. */
17 | #define MOSI MOSI_PIN
18 |
19 | /** SPI master input, slave output pin. */
20 | #define MISO MISO_PIN
21 |
22 | /** SPI serial clock pin. */
23 | #define SCK SCK_PIN
24 |
25 | //------------------------------------------------------------------------------
26 | // DAC pin definitions
27 |
28 | // LDAC may be connected to ground to save a pin
29 | /** Set USE_MCP_DAC_LDAC to 0 if LDAC is grounded. */
30 | #define USE_MCP_DAC_LDAC 1
31 |
32 | // use arduino pins 2, 3, 4, 5 for DAC
33 |
34 | // pin 2 is DAC chip select
35 |
36 | /** Data direction register for DAC chip select. */
37 | #define MCP_DAC_CS_DDR PIN2_DDRREG
38 | /** Port register for DAC chip select. */
39 | #define MCP_DAC_CS_PORT PIN2_PORTREG
40 | /** Port bit number for DAC chip select. */
41 | #define MCP_DAC_CS_BIT PIN2_BITNUM
42 |
43 | // pin 3 is DAC serial clock
44 | /** Data direction register for DAC clock. */
45 | #define MCP_DAC_SCK_DDR PIN3_DDRREG
46 | /** Port register for DAC clock. */
47 | #define MCP_DAC_SCK_PORT PIN3_PORTREG
48 | /** Port bit number for DAC clock. */
49 | #define MCP_DAC_SCK_BIT PIN3_BITNUM
50 |
51 | // pin 4 is DAC serial data in
52 |
53 | /** Data direction register for DAC serial in. */
54 | #define MCP_DAC_SDI_DDR PIN4_DDRREG
55 | /** Port register for DAC clock. */
56 | #define MCP_DAC_SDI_PORT PIN4_PORTREG
57 | /** Port bit number for DAC clock. */
58 | #define MCP_DAC_SDI_BIT PIN4_BITNUM
59 |
60 | // pin 5 is LDAC if used
61 | #if USE_MCP_DAC_LDAC
62 | /** Data direction register for Latch DAC Input. */
63 | #define MCP_DAC_LDAC_DDR PIN5_DDRREG
64 | /** Port register for Latch DAC Input. */
65 | #define MCP_DAC_LDAC_PORT PIN5_PORTREG
66 | /** Port bit number for Latch DAC Input. */
67 | #define MCP_DAC_LDAC_BIT PIN5_BITNUM
68 | #endif // USE_MCP_DAC_LDAC
69 |
70 | #endif // WavePinDefs_h
--------------------------------------------------------------------------------
/libraries/WaveHC/WaveUtil.cpp:
--------------------------------------------------------------------------------
1 |
2 | #if ARDUINO < 100
3 | #include
4 | #else // ARDUINO
5 | #include
6 | #endif // ARDUINO
7 | #include
8 | //------------------------------------------------------------------------------
9 | /** Return the number of bytes currently free in RAM. */
10 | int FreeRam(void) {
11 | extern int __bss_end;
12 | extern int *__brkval;
13 | int free_memory;
14 | if((int)__brkval == 0) {
15 | // if no heap use from end of bss section
16 | free_memory = ((int)&free_memory) - ((int)&__bss_end);
17 | }
18 | else {
19 | // use from top of stack to heap
20 | free_memory = ((int)&free_memory) - ((int)__brkval);
21 | }
22 | return free_memory;
23 | }
24 | //------------------------------------------------------------------------------
25 | /**
26 | * %Print a string in flash memory to the serial port.
27 | *
28 | * \param[in] str Pointer to string stored in flash memory.
29 | */
30 | void SerialPrint_P(PGM_P str) {
31 | for (uint8_t c; (c = pgm_read_byte(str)); str++) Serial.write(c);
32 | }
33 | //------------------------------------------------------------------------------
34 | /**
35 | * %Print a string in flash memory followed by a CR/LF.
36 | *
37 | * \param[in] str Pointer to string stored in flash memory.
38 | */
39 | void SerialPrintln_P(PGM_P str) {
40 | SerialPrint_P(str);
41 | Serial.println();
42 | }
--------------------------------------------------------------------------------
/libraries/WaveHC/WaveUtil.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ifndef WaveUtil_h
4 | #define WaveUtil_h
5 | #include
6 |
7 | // ladayada uses this name
8 | #define putstring(x) SerialPrint_P(PSTR(x))
9 |
10 | // ladayada uses this name
11 | #define putstring_nl(x) SerialPrintln_P(PSTR(x))
12 |
13 | /** Store and print a string in flash memory.*/
14 | #define PgmPrint(x) SerialPrint_P(PSTR(x))
15 |
16 | /** Store and print a string in flash memory followed by a CR/LF.*/
17 | #define PgmPrintln(x) SerialPrintln_P(PSTR(x))
18 |
19 | int FreeRam(void);
20 | void SerialPrint_P(PGM_P str);
21 | void SerialPrintln_P(PGM_P str);
22 | #endif //WaveUtil_h
23 |
--------------------------------------------------------------------------------
/libraries/WaveHC/Wavemainpage.h:
--------------------------------------------------------------------------------
1 | /* Arduino WaveHC Library
2 | * Copyright (C) 2009 by William Greiman
3 | *
4 | * This file is part of the Arduino WaveHC Library
5 | *
6 | * This Library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This Library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with the Arduino WaveHC Library. If not, see
18 | * .
19 | */
20 |
21 | /**
22 | \mainpage Arduino WaveHC Library
23 | Copyright © 2009 by William Greiman
24 |
25 |
26 | \section Intro Introduction
27 |
28 | WaveHC is an Arduino library for the Adafruit Wave Shield. It can play
29 | uncompressed mono Wave(.WAV) files at sample rate up to 44.1 K samples per
30 | second. Only the high 12 bits of 16-bit files are used. Audio files are read
31 | from an SD flash memory card.
32 |
33 | Standard SD and high capacity SDHC flash memory cards are supported with
34 | FAT16 or FAT32 file systems. The WaveHC only supports short FAT 8.3 names.
35 |
36 | WaveHC does not support MMC flash cards.
37 |
38 | \section comment Bugs and Comments
39 |
40 | If you wish to report bugs or have comments, send email to
41 | fat16lib@sbcglobal.net.
42 |
43 | \section SDcard SD/SDHC Cards
44 |
45 | Arduinos access SD cards using the cards SPI protocol. PCs, Macs, and
46 | most consumer devices use the 4-bit parallel SD protocol. A card that
47 | functions well on A PC or Mac may not work well on the Arduino.
48 |
49 | Most cards have good SPI read performance but cards vary widely in
50 | how there SPI hardware interface is implemented. Newer card require
51 | very fast rise times for SPI signals. Version 1.0 of the Wave Shield
52 | may not work well with these cards. Ladyada's improved Version 1.1
53 | works with almost all SD/SDHC cards.
54 |
55 | The default SPI clock rate is 8 Mhz. It may be helpful on Version 1.0
56 | wave shields to reduce this to 4 Mhz. See SdReader::init() for details.
57 |
58 | SanDisk cards generally have good performance in the Version 1.0 Wave Shield.
59 |
60 |
61 | \section WaveHCClass WaveHC Usage
62 |
63 | See Ladyada's excellent tutorial on using WaveHC:
64 |
65 | http://www.ladyada.net/make/waveshield/libraryhc.html
66 |
67 | Also see the readme.txt file for instructions on installing WaveHC.
68 |
69 | Advanced users may need to edit the WavePinDefs.h file.
70 |
71 | WaveHC uses a slightly restricted form of short file names.
72 | Only printable ASCII characters are supported. No characters with code point
73 | values greater than 127 are allowed. Space is not allowed even though space
74 | was allowed in the API of early versions of DOS.
75 |
76 | Short names are limited to 8 characters followed by an optional period (.)
77 | and extension of up to 3 characters. The characters may be any combination
78 | of letters and digits. The following special characters are also allowed:
79 |
80 | $ % ' - _ @ ~ ` ! ( ) { } ^ # &
81 |
82 | Short names are always converted to upper case and their original case
83 | value is lost.
84 |
85 | \section HowTo How to Format and Prepare SD Cards for WaveHC
86 |
87 | WaveHC is optimized for contiguous files. It will only play 16-bit
88 | 44.1 K files if they are contiguous. All files copied to a newly
89 | formatted card will be contiguous. It is only possible to create
90 | a fragmented file if you delete a file from an SD and copy a larger
91 | file to the SD.
92 |
93 | You should use a freshly formatted SD card for best performance. FAT
94 | file systems become slower if many files have been created and deleted.
95 | This is because the directory entry for a deleted file is marked as deleted,
96 | but is not deleted. When a file is opened, these entries must be scanned
97 | to find the file to be opened, a flaw in the FAT design. Also files can
98 | become fragmented which causes reads to be slower.
99 |
100 | Microsoft operating systems support removable media formatted with a
101 | Master Boot Record, MBR, or formatted as a super floppy with a FAT Boot Sector
102 | in block zero.
103 |
104 | Microsoft operating systems expect MBR formatted removable media
105 | to have only one partition. The first partition should be used.
106 |
107 | Microsoft operating systems do not support partitioning SD flash cards.
108 | If you erase an SD card with a program like KillDisk, Most versions of
109 | Windows will format the card as a super floppy.
110 |
111 | The best way to restore an SD card's format is to use SDFormatter
112 | which can be downloaded from:
113 |
114 | http://www.sdcard.org/consumers/formatter/
115 |
116 | SDFormatter aligns flash erase boundaries with file
117 | system structures which reduces write latency and file system overhead.
118 |
119 | SDFormatter does not have an option for FAT type so it may format
120 | small cards as FAT12.
121 |
122 | After the MBR is restored by SDFormatter you may need to reformat small
123 | cards that have been formatted FAT12 to force the volume type to be FAT16.
124 |
125 | If you reformat the SD card with an OS utility, choose a cluster size that
126 | will result in:
127 |
128 | 4084 < CountOfClusters && CountOfClusters < 65525
129 |
130 | The volume will then be FAT16.
131 |
132 | If you are formatting an SD card on OS X or Linux, be sure to use the first
133 | partition. Format this partition with a cluster count in above range.
134 |
135 | \section References References
136 |
137 | Adafruit Industries:
138 |
139 | http://www.adafruit.com/
140 |
141 | http://www.ladyada.net/make/waveshield/
142 |
143 | The Arduino site:
144 |
145 | http://www.arduino.cc/
146 |
147 | For more information about FAT file systems see:
148 |
149 | http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
150 |
151 | For information about using SD cards as SPI devices see:
152 |
153 | http://www.sdcard.org/developers/tech/sdcard/pls/Simplified_Physical_Layer_Spec.pdf
154 |
155 | The ATmega328 datasheet:
156 |
157 | http://www.atmel.com/dyn/resources/prod_documents/doc8161.pdf
158 |
159 |
160 | */
--------------------------------------------------------------------------------
/libraries/WaveHC/examples/PiSpeakHC/PiSpeakHC.pde:
--------------------------------------------------------------------------------
1 | /*
2 | * Text-to-speech example to speak the first n digits of pi.
3 | * The number is stored in flash, each digit is spoken one at a time.
4 | */
5 | #include
6 | #include
7 |
8 | // put pi in flash memory
9 | const char pi[] PROGMEM = "3.1415926535897932384626433832795028841971693993751058209749";
10 |
11 | SdReader card; // This object holds the information for the card
12 | FatVolume vol; // This holds the information for the partition on the card
13 | FatReader root; // This holds the information for the volumes root directory
14 | FatReader file; // This object represent the WAV file for a pi digit or period
15 | WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
16 | /*
17 | * Define macro to put error messages in flash memory
18 | */
19 | #define error(msg) error_P(PSTR(msg))
20 |
21 | //////////////////////////////////// SETUP
22 |
23 | void setup() {
24 | // set up Serial library at 9600 bps
25 | Serial.begin(9600);
26 |
27 | PgmPrintln("Pi speaker");
28 |
29 | if (!card.init()) {
30 | error("Card init. failed!");
31 | }
32 | if (!vol.init(card)) {
33 | error("No partition!");
34 | }
35 | if (!root.openRoot(vol)) {
36 | error("Couldn't open dir");
37 | }
38 |
39 | PgmPrintln("Files found:");
40 | root.ls();
41 | }
42 |
43 | /////////////////////////////////// LOOP
44 |
45 | unsigned digit = 0;
46 |
47 | void loop() {
48 | // get next character from flash memory
49 | char c = pgm_read_byte(&pi[digit++]);
50 |
51 | if (c == 0) {
52 | digit = 0;
53 | Serial.println();
54 | return;
55 | }
56 | Serial.write(c);
57 |
58 | speaknum(c);
59 |
60 | delay(10);
61 | }
62 |
63 | /////////////////////////////////// HELPERS
64 |
65 | char filename[13];
66 | void speaknum(char c) {
67 | uint8_t i=0;
68 |
69 | // copy flash string for 'period' to filename
70 | strcpy_P(filename, PSTR("P.WAV"));
71 |
72 | if ('0' <= c && c <= '9') {
73 | // digit - change 'P' to digit
74 | filename[0] = c;
75 | i = 1;
76 | }
77 | else if (c != '.') {
78 | // error if not period
79 | return;
80 | }
81 | playcomplete(filename);
82 | }
83 | /*
84 | * print error message and halt
85 | */
86 | void error_P(const char *str) {
87 | PgmPrint("Error: ");
88 | SerialPrint_P(str);
89 | sdErrorCheck();
90 | while(1);
91 | }
92 | /*
93 | * print error message and halt if SD I/O error
94 | */
95 | void sdErrorCheck(void) {
96 | if (!card.errorCode()) return;
97 | PgmPrint("\r\nSD I/O error: ");
98 | Serial.print(card.errorCode(), HEX);
99 | PgmPrint(", ");
100 | Serial.println(card.errorData(), HEX);
101 | while(1);
102 | }
103 | /*
104 | * Play a file and wait for it to complete
105 | */
106 | void playcomplete(char *name) {
107 | playfile(name);
108 | while (wave.isplaying);
109 |
110 | // see if an error occurred while playing
111 | sdErrorCheck();
112 | }
113 | /*
114 | * Open and start playing a WAV file
115 | */
116 | void playfile(char *name) {
117 | if (wave.isplaying) {// already playing something, so stop it!
118 | wave.stop(); // stop it
119 | }
120 | if (!file.open(root, name)) {
121 | PgmPrint("Couldn't open file ");
122 | Serial.print(name);
123 | return;
124 | }
125 | if (!wave.create(file)) {
126 | PgmPrintln("Not a valid WAV");
127 | return;
128 | }
129 | // ok time to play!
130 | wave.play();
131 | }
132 |
--------------------------------------------------------------------------------
/libraries/WaveHC/examples/SampleRateHC/SampleRateHC.pde:
--------------------------------------------------------------------------------
1 | /*
2 | * Adafruit SampleRateMod.pde example modified to use WaveHC.
3 | *
4 | * Play files with sample rate controlled by voltage on analog pin zero.
5 | */
6 | #include
7 | #include
8 |
9 | SdReader card; // This object holds the information for the card
10 | FatVolume vol; // This holds the information for the partition on the card
11 | FatReader root; // This holds the information for the volumes root directory
12 | FatReader file; // This object represent the WAV file
13 | WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
14 |
15 | /*
16 | * Define macro to put error messages in flash memory
17 | */
18 | #define error(msg) error_P(PSTR(msg))
19 |
20 | //////////////////////////////////// SETUP
21 | void setup() {
22 | Serial.begin(9600);
23 | Serial.println("Wave test!");
24 |
25 | // try card.init(true) if errors occur on V1.0 Wave Shield
26 | if (!card.init()) {
27 | error("Card init. failed!");
28 | }
29 | // enable optimize read - some cards may timeout
30 | card.partialBlockRead(true);
31 |
32 | if (!vol.init(card)) {
33 | error("No partition!");
34 | }
35 | if (!root.openRoot(vol)) {
36 | error("Couldn't open root");
37 | }
38 | putstring_nl("Files found:");
39 | root.ls();
40 | }
41 |
42 | // forward declarition
43 | void playcomplete(FatReader &file);
44 |
45 | //////////////////////////////////// LOOP
46 | void loop() {
47 | uint8_t i, r;
48 | char c, name[15];
49 | dir_t dir;
50 |
51 | root.rewind();
52 | // scroll through the files in the directory
53 | while (root.readDir(dir) > 0) {
54 | // only play .WAV files
55 | if (!strncmp_P((char *)&dir.name[8]. PSTR("WAV"))) continue;
56 |
57 | if (!file.open(vol, dir)){
58 | putstring("Can't open ");
59 | printEntryName(dir);
60 | Serial.println();
61 | continue;
62 | }
63 | putstring("\n\rPlaying ");
64 | printEntryName(dir);
65 | Serial.println();
66 | playcomplete(file);
67 | file.close();
68 | }
69 | }
70 | /////////////////////////////////// HELPERS
71 | /*
72 | * print error message and halt
73 | */
74 | void error_P(const char *str) {
75 | PgmPrint("Error: ");
76 | SerialPrint_P(str);
77 | sdErrorCheck();
78 | while(1);
79 | }
80 | /*
81 | * print error message and halt if SD I/O error, great for debugging!
82 | */
83 | void sdErrorCheck(void) {
84 | if (!card.errorCode()) return;
85 | PgmPrint("\r\nSD I/O error: ");
86 | Serial.print(card.errorCode(), HEX);
87 | PgmPrint(", ");
88 | Serial.println(card.errorData(), HEX);
89 | while(1);
90 | }
91 | int16_t lastpotval = 0;
92 | #define HYSTERESIS 3
93 | /*
94 | * play file with sample rate changes
95 | */
96 | void playcomplete(FatReader &file) {
97 | int16_t potval;
98 | uint32_t newsamplerate;
99 |
100 | if (!wave.create(file)) {
101 | putstring_nl(" Not a valid WAV"); return;
102 | }
103 | // ok time to play!
104 | wave.play();
105 |
106 | while (wave.isplaying) {
107 | potval = analogRead(0);
108 | if ( ((potval - lastpotval) > HYSTERESIS) || ((lastpotval - potval) > HYSTERESIS)) {
109 | putstring("pot = ");
110 | Serial.println(potval, DEC);
111 | putstring("tickspersam = ");
112 | Serial.print(wave.dwSamplesPerSec, DEC);
113 | putstring(" -> ");
114 | newsamplerate = wave.dwSamplesPerSec;
115 | newsamplerate *= potval;
116 | newsamplerate /= 512; // we want to 'split' between sped up and slowed down.
117 | if (newsamplerate > 24000) {
118 | newsamplerate = 24000;
119 | }
120 | if (newsamplerate < 1000) {
121 | newsamplerate = 1000;
122 | }
123 | wave.setSampleRate(newsamplerate);
124 |
125 | Serial.println(newsamplerate, DEC);
126 | lastpotval = potval;
127 | }
128 | delay(100);
129 | }
130 | sdErrorCheck();
131 | }
132 |
--------------------------------------------------------------------------------
/libraries/WaveHC/examples/SdReadTest/SdReadTest.pde:
--------------------------------------------------------------------------------
1 | // this sketch wiil do a read stress test on a SD card.
2 | // run time is about 25 seconds
3 |
4 | #include
5 | #include
6 | #include
7 | SdReader card;
8 |
9 | uint8_t cidDmp(void) {
10 | cid_t cid;
11 | if (!card.readCID(cid)) {
12 | putstring("readCID failed");
13 | sdError();
14 | return 0;
15 | }
16 | putstring("\nManufacturer ID: ");
17 | Serial.println(cid.mid, HEX);
18 | putstring("OEM ID: ");
19 | Serial.write(cid.oid[0]);
20 | Serial.write(cid.oid[1]);
21 | Serial.println();
22 | putstring("Product: ");
23 | for (uint8_t i = 0; i < 5; i++) {
24 | Serial.write(cid.pnm[i]);
25 | }
26 | putstring("\nVersion: ");
27 | Serial.print(cid.prv_n, DEC);
28 | Serial.write('.');
29 | Serial.println(cid.prv_m, DEC);
30 | putstring("Serial number: ");
31 | Serial.println(cid.psn);
32 | putstring("Manufacturing date: ");
33 | Serial.print(cid.mdt_month, DEC);
34 | Serial.write('/');
35 | Serial.println(2000 + cid.mdt_year_low + (cid.mdt_year_high << 4));
36 | Serial.println();
37 | return 1;
38 | }
39 | // print partition table
40 | uint8_t partDmp(void) {
41 | part_t pt;
42 | putstring_nl("partion,boot,type,start,length");
43 | for (uint8_t ip = 1; ip < 5; ip++) {
44 | if (!card.readData(0, PART_OFFSET + 16*(ip-1), (uint8_t *)&pt, 16)) {
45 | putstring("read partition table failed");
46 | sdError();
47 | return 0;
48 | }
49 | Serial.print(ip, DEC);
50 | Serial.write(',');
51 | Serial.print(pt.boot,HEX);
52 | Serial.write(',');
53 | Serial.print(pt.type, HEX);
54 | Serial.write(',');
55 | Serial.print(pt.firstSector);
56 | Serial.write(',');
57 | Serial.println(pt.totalSectors);
58 | }
59 | return true;
60 | }
61 |
62 | void sdError(void) {
63 | putstring_nl("SD error");
64 | putstring("errorCode: ");
65 | Serial.println(card.errorCode(), HEX);
66 | putstring("errorData: ");
67 | Serial.println(card.errorData(), HEX);
68 | return;
69 | }
70 | void setup(void) {
71 | Serial.begin(9600);
72 | }
73 |
74 | void loop(void) {
75 | while (Serial.read() >= 0) {}
76 | putstring_nl("\ntype any character to start");
77 | while (Serial.read() < 0) {}
78 | uint32_t t0 = millis();
79 | uint8_t r = card.init(0);
80 | uint32_t d = millis()- t0;
81 | if (!r) {
82 | putstring_nl("\ncard.init failed");
83 | sdError();
84 | return;
85 | }
86 | putstring("\ninit time: ");
87 | Serial.println(d);
88 | putstring("\nCard type: ");
89 | switch(card.type()) {
90 | case SD_CARD_TYPE_SD1:
91 | putstring_nl("SD1");
92 | break;
93 | case SD_CARD_TYPE_SD2:
94 | putstring_nl("SD2");
95 | break;
96 | case SD_CARD_TYPE_SDHC:
97 | putstring_nl("SDHC");
98 | break;
99 | default:
100 | putstring_nl("Unknown");
101 | }
102 |
103 | if(!cidDmp()) return;
104 | uint32_t size = card.cardSize();
105 | if (size == 0) {
106 | putstring("cardSize failed");
107 | sdError();
108 | return;
109 | }
110 | putstring("card size: ");
111 | Serial.print(size);
112 | putstring(" (512 byte blocks)\n");
113 | if(!partDmp()) return;
114 | uint16_t nTest = 20000;
115 | uint16_t nRead = 0;
116 | uint8_t buf[2];
117 | d = size/nTest;
118 | uint32_t b;
119 | putstring_nl("Read test starting. Please Wait.");
120 | uint32_t m0 = millis();
121 | for (nRead = 0; nRead < nTest; nRead++){
122 | b = nRead*d;
123 | if (!(r = card.readData(b, 510, buf, 2))) break;
124 | if (nRead == 0 && (buf[0] != 0X55 || buf[1] != 0XAA)) {
125 | putstring("Invalid block zero signature: ");
126 | Serial.print(buf[0], HEX);
127 | Serial.write(',');
128 | Serial.println(buf[1], HEX);
129 | }
130 | }
131 | uint32_t m1 = millis();
132 | putstring("\nRead ");
133 | Serial.print(nRead);
134 | putstring_nl(" blocks");
135 | putstring("mills: ");
136 | Serial.println(m1 - m0);
137 | if(r) {
138 | putstring_nl("\nDone");
139 | }
140 | else {
141 | putstring_nl("\nRead Failure");
142 | putstring("lbn: ");
143 | Serial.println(b);
144 | sdError();
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/libraries/WaveHC/examples/SoftVolumeHC/SoftVolumeHC.pde:
--------------------------------------------------------------------------------
1 | /*
2 | * DVOLUME must be set nonzero in WaveHC.h to use this example.
3 | *
4 | * Adafruit SoftVolumeChange.pde modified to use WaveHC library.
5 | *
6 | * Play files with software volume control.
7 |
8 | */
9 | #include
10 | #include
11 |
12 | SdReader card; // This object holds the information for the card
13 | FatVolume vol; // This holds the information for the partition on the card
14 | FatReader root; // This holds the information for the volumes root directory
15 | FatReader file; // This object represent the WAV file
16 | WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
17 |
18 | /*
19 | * Define macro to put error messages in flash memory
20 | */
21 | #define error(msg) error_P(PSTR(msg))
22 |
23 | //////////////////////////////////// SETUP
24 | void setup() {
25 | Serial.begin(9600);
26 | Serial.println("Wave test!");
27 |
28 | // try card.init(true) if errors occur on V1.0 Wave Shield
29 | if (!card.init()) {
30 | error("Card init. failed!");
31 | }
32 | // enable optimize read - some cards may timeout
33 | card.partialBlockRead(true);
34 |
35 | if (!vol.init(card)) {
36 | error("No partition!");
37 | }
38 | if (!root.openRoot(vol)) {
39 | error("Couldn't open root"); return;
40 | }
41 | putstring_nl("Files found:");
42 | root.ls();
43 | }
44 |
45 | // forward declarition
46 | void playcomplete(FatReader &file);
47 |
48 | //////////////////////////////////// LOOP
49 | void loop() {
50 | uint8_t i, r;
51 | char c, name[15];
52 | dir_t dir;
53 |
54 | root.rewind();
55 | // scroll through the files in the directory
56 | while (root.readDir(dir) > 0) {
57 | // only play .WAV files
58 | if (!strncmp_P((char *)&dir.name[8]. PSTR("WAV"))) continue;
59 |
60 | if (!file.open(vol, dir)){
61 | putstring("Can't open ");
62 | printEntryName(dir);
63 | Serial.println();
64 | continue;
65 | }
66 | putstring("\n\rPlaying ");
67 | printEntryName(dir);
68 | Serial.println();
69 | playcomplete(file);
70 | file.close();
71 | }
72 | }
73 |
74 | /////////////////////////////////// HELPERS
75 | /*
76 | * print error message and halt
77 | */
78 | void error_P(const char *str) {
79 | PgmPrint("Error: ");
80 | SerialPrint_P(str);
81 | sdErrorCheck();
82 | while(1);
83 | }
84 | /*
85 | * print error message and halt if SD I/O error, great for debugging!
86 | */
87 | void sdErrorCheck(void) {
88 | if (!card.errorCode()) return;
89 | PgmPrint("\r\nSD I/O error: ");
90 | Serial.print(card.errorCode(), HEX);
91 | PgmPrint(", ");
92 | Serial.println(card.errorData(), HEX);
93 | while(1);
94 | }
95 | /*
96 | * Play files with software volume control
97 | */
98 | void playcomplete(FatReader &file) {
99 | if (!wave.create(file)) {
100 | putstring_nl(" Not a valid WAV"); return;
101 | }
102 | // ok time to play!
103 | wave.play();
104 | while (wave.isplaying) {
105 | putstring("Vol: ");
106 |
107 | // DVOLUME must be nonzero in WaveHC.h to use volume.
108 | Serial.println(wave.volume, DEC);
109 |
110 | delay(2000);
111 | wave.volume++;
112 | if ( wave.volume == 12) {
113 | wave.volume = 0;
114 | }
115 | }
116 | sdErrorCheck();
117 | }
118 |
--------------------------------------------------------------------------------
/libraries/WaveHC/examples/daphc/daphc.pde:
--------------------------------------------------------------------------------
1 | /*
2 | * This example plays every .WAV file it finds on the SD card in a loop
3 | */
4 | #include
5 | #include
6 |
7 | SdReader card; // This object holds the information for the card
8 | FatVolume vol; // This holds the information for the partition on the card
9 | FatReader root; // This holds the information for the volumes root directory
10 | WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
11 |
12 | uint8_t dirLevel; // indent level for file/dir names (for prettyprinting)
13 | dir_t dirBuf; // buffer for directory reads
14 |
15 |
16 | /*
17 | * Define macro to put error messages in flash memory
18 | */
19 | #define error(msg) error_P(PSTR(msg))
20 |
21 | // Function definitions (we define them here, but the code is below)
22 | void play(FatReader &dir);
23 |
24 | //////////////////////////////////// SETUP
25 | void setup() {
26 | Serial.begin(9600); // set up Serial library at 9600 bps for debugging
27 |
28 | putstring_nl("\nWave test!"); // say we woke up!
29 |
30 | putstring("Free RAM: "); // This can help with debugging, running out of RAM is bad
31 | Serial.println(FreeRam());
32 |
33 | // if (!card.init(true)) { //play with 4 MHz spi if 8MHz isn't working for you
34 | if (!card.init()) { //play with 8 MHz spi (default faster!)
35 | error("Card init. failed!"); // Something went wrong, lets print out why
36 | }
37 |
38 | // enable optimize read - some cards may timeout. Disable if you're having problems
39 | card.partialBlockRead(true);
40 |
41 | // Now we will look for a FAT partition!
42 | uint8_t part;
43 | for (part = 0; part < 5; part++) { // we have up to 5 slots to look in
44 | if (vol.init(card, part))
45 | break; // we found one, lets bail
46 | }
47 | if (part == 5) { // if we ended up not finding one :(
48 | error("No valid FAT partition!"); // Something went wrong, lets print out why
49 | }
50 |
51 | // Lets tell the user about what we found
52 | putstring("Using partition ");
53 | Serial.print(part, DEC);
54 | putstring(", type is FAT");
55 | Serial.println(vol.fatType(), DEC); // FAT16 or FAT32?
56 |
57 | // Try to open the root directory
58 | if (!root.openRoot(vol)) {
59 | error("Can't open root dir!"); // Something went wrong,
60 | }
61 |
62 | // Whew! We got past the tough parts.
63 | putstring_nl("Files found (* = fragmented):");
64 |
65 | // Print out all of the files in all the directories.
66 | root.ls(LS_R | LS_FLAG_FRAGMENTED);
67 | }
68 |
69 | //////////////////////////////////// LOOP
70 | void loop() {
71 | root.rewind();
72 | play(root);
73 | }
74 |
75 | /////////////////////////////////// HELPERS
76 | /*
77 | * print error message and halt
78 | */
79 | void error_P(const char *str) {
80 | PgmPrint("Error: ");
81 | SerialPrint_P(str);
82 | sdErrorCheck();
83 | while(1);
84 | }
85 | /*
86 | * print error message and halt if SD I/O error, great for debugging!
87 | */
88 | void sdErrorCheck(void) {
89 | if (!card.errorCode()) return;
90 | PgmPrint("\r\nSD I/O error: ");
91 | Serial.print(card.errorCode(), HEX);
92 | PgmPrint(", ");
93 | Serial.println(card.errorData(), HEX);
94 | while(1);
95 | }
96 | /*
97 | * play recursively - possible stack overflow if subdirectories too nested
98 | */
99 | void play(FatReader &dir) {
100 | FatReader file;
101 | while (dir.readDir(dirBuf) > 0) { // Read every file in the directory one at a time
102 |
103 | // Skip it if not a subdirectory and not a .WAV file
104 | if (!DIR_IS_SUBDIR(dirBuf)
105 | && strncmp_P((char *)&dirBuf.name[8], PSTR("WAV"), 3)) {
106 | continue;
107 | }
108 |
109 | Serial.println(); // clear out a new line
110 |
111 | for (uint8_t i = 0; i < dirLevel; i++) {
112 | Serial.write(' '); // this is for prettyprinting, put spaces in front
113 | }
114 | if (!file.open(vol, dirBuf)) { // open the file in the directory
115 | error("file.open failed"); // something went wrong
116 | }
117 |
118 | if (file.isDir()) { // check if we opened a new directory
119 | putstring("Subdir: ");
120 | printEntryName(dirBuf);
121 | Serial.println();
122 | dirLevel += 2; // add more spaces
123 | // play files in subdirectory
124 | play(file); // recursive!
125 | dirLevel -= 2;
126 | }
127 | else {
128 | // Aha! we found a file that isnt a directory
129 | putstring("Playing ");
130 | printEntryName(dirBuf); // print it out
131 | if (!wave.create(file)) { // Figure out, is it a WAV proper?
132 | putstring(" Not a valid WAV"); // ok skip it
133 | } else {
134 | Serial.println(); // Hooray it IS a WAV proper!
135 | wave.play(); // make some noise!
136 |
137 | uint8_t n = 0;
138 | while (wave.isplaying) {// playing occurs in interrupts, so we print dots in realtime
139 | putstring(".");
140 | if (!(++n % 32))Serial.println();
141 | delay(100);
142 | }
143 | sdErrorCheck(); // everything OK?
144 | // if (wave.errors)Serial.println(wave.errors); // wave decoding errors
145 | }
146 | }
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/libraries/WaveHC/examples/openByIndex/openByIndex.pde:
--------------------------------------------------------------------------------
1 | /*
2 | * This sketch illustrates opening files by index
3 | * which can significantly reduce latency.
4 | *
5 | * How to prepare a test SD:
6 | * Start with a clean newly formatted SD.
7 | * First copy the 400 files in the 'fill' folder to the SD.
8 | * Next copy the 16 files in the 'DTMF' folder to the SD.
9 | * There should be 416 files in the SD root directory.
10 | *
11 | * You must copy the files in the above order so the 'fill'
12 | * files occur in the directory before the DTMF files.
13 | *
14 | * Run this sketch using the prepared SD. Notice the
15 | * difference in latency between play by name and
16 | * play by index.
17 | */
18 |
19 | #include
20 | #include
21 |
22 | SdReader card; // This object holds the information for the card
23 | FatVolume vol; // This holds the information for the partition on the card
24 | FatReader root; // This holds the information for the volumes root directory
25 | FatReader file; // This object represent the WAV file
26 | WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
27 |
28 | // time to play each tone in milliseconds
29 | #define PLAY_TIME 200
30 |
31 | /*
32 | * Define macro to put error messages in flash memory
33 | */
34 | #define error(msg) error_P(PSTR(msg))
35 |
36 | //////////////////////////////////// SETUP
37 | void setup() {
38 | Serial.begin(9600);
39 |
40 | if (!card.init()) error("card.init");
41 |
42 | // enable optimized read - some cards may timeout
43 | card.partialBlockRead(true);
44 |
45 | if (!vol.init(card)) error("vol.init");
46 |
47 | if (!root.openRoot(vol)) error("openRoot");
48 |
49 | PgmPrintln("Index files");
50 | indexFiles();
51 |
52 | PgmPrintln("Play files by index");
53 | playByIndex();
54 |
55 | PgmPrintln("Play files by name");
56 | playByName();
57 | }
58 |
59 | //////////////////////////////////// LOOP
60 | void loop() { }
61 |
62 | /////////////////////////////////// HELPERS
63 | /*
64 | * print error message and halt
65 | */
66 | void error_P(const char *str) {
67 | PgmPrint("Error: ");
68 | SerialPrint_P(str);
69 | sdErrorCheck();
70 | while(1);
71 | }
72 | /*
73 | * print error message and halt if SD I/O error, great for debugging!
74 | */
75 | void sdErrorCheck(void) {
76 | if (!card.errorCode()) return;
77 | PgmPrint("\r\nSD I/O error: ");
78 | Serial.print(card.errorCode(), HEX);
79 | PgmPrint(", ");
80 | Serial.println(card.errorData(), HEX);
81 | while(1);
82 | }
83 |
84 | // Number of files.
85 | #define FILE_COUNT 16
86 |
87 | // Files are 'touch tone phone' DTMF tones, P = #, S = *
88 | // Most phones don't have A, B, C, and D tones.
89 | // file names are of the form DTMFx.WAV where x is one of
90 | // the letters from fileLetter[]
91 | char fileLetter[] = {'0', '1', '2', '3', '4', '5', '6',
92 | '7', '8', '9', 'A', 'B', 'C', 'D', 'P', 'S'};
93 |
94 | // index of DTMF files in the root directory
95 | uint16_t fileIndex[FILE_COUNT];
96 | /*
97 | * Find files and save file index. A file's index is is the
98 | * index of it's directory entry in it's directory file.
99 | */
100 | void indexFiles(void) {
101 | char name[10];
102 |
103 | // copy flash string to RAM
104 | strcpy_P(name, PSTR("DTMFx.WAV"));
105 |
106 | for (uint8_t i = 0; i < FILE_COUNT; i++) {
107 |
108 | // Make file name
109 | name[4] = fileLetter[i];
110 |
111 | // Open file by name
112 | if (!file.open(root, name)) error("open by name");
113 |
114 | // Save file's index (byte offset of directory entry divided by entry size)
115 | // Current position is just after entry so subtract one.
116 | fileIndex[i] = root.readPosition()/32 - 1;
117 | }
118 | PgmPrintln("Done");
119 | }
120 | /*
121 | * Play file by index and print latency in ms
122 | */
123 | void playByIndex(void) {
124 | for (uint8_t i = 0; i < FILE_COUNT; i++) {
125 |
126 | // start time
127 | uint32_t t = millis();
128 |
129 | // open by index
130 | if (!file.open(root, fileIndex[i])) {
131 | error("open by index");
132 | }
133 |
134 | // create and play Wave
135 | if (!wave.create(file)) error("wave.create");
136 | wave.play();
137 |
138 | // print time to open file and start play
139 | Serial.println(millis() - t);
140 |
141 | // stop after PLAY_TIME ms
142 | while((millis() - t) < PLAY_TIME);
143 | wave.stop();
144 |
145 | // check for play errors
146 | sdErrorCheck();
147 | }
148 | PgmPrintln("Done");
149 | }
150 | /*
151 | * Play file by name and print latency in ms
152 | */
153 | void playByName(void) {
154 | char name[10];
155 |
156 | // copy flash string to RAM
157 | strcpy_P(name, PSTR("DTMFx.WAV"));
158 |
159 | for (uint8_t i = 0; i < FILE_COUNT; i++) {
160 | // start time
161 | uint32_t t = millis();
162 |
163 | // make file name
164 | name[4] = fileLetter[i];
165 |
166 | // open file by name
167 | if (!file.open(root, name)) error("open by name");
168 |
169 | // create wave and start play
170 | if (!wave.create(file))error("wave.create");
171 | wave.play();
172 |
173 | // print time
174 | Serial.println(millis() - t);
175 |
176 | // stop after PLAY_TIME ms
177 | while((millis() - t) < PLAY_TIME);
178 | wave.stop();
179 |
180 | // check for play errors
181 | sdErrorCheck();
182 | }
183 | PgmPrintln("Done");
184 | }
185 |
--------------------------------------------------------------------------------
/libraries/WaveHC/mcpDac.h:
--------------------------------------------------------------------------------
1 | /* Arduino WaveHC Library
2 | * Copyright (C) 2009 by William Greiman
3 | *
4 | * This file is part of the Arduino WaveHC Library
5 | *
6 | * This Library is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * This Library is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with the Arduino WaveHC Library. If not, see
18 | * .
19 | */
20 | /**
21 | * Macros and inline functions for MCP4921 DAC
22 | */
23 | #ifndef mcpDac_h
24 | #define mcpDac_h
25 |
26 | #include
27 | #include
28 |
29 |
30 | //------------------------------------------------------------------------------
31 | #define mcpDacCsLow() MCP_DAC_CS_PORT &= ~_BV(MCP_DAC_CS_BIT)
32 | #define mcpDacCsHigh() MCP_DAC_CS_PORT |= _BV(MCP_DAC_CS_BIT)
33 |
34 | #define mcpDacSckLow() MCP_DAC_SCK_PORT &= ~_BV(MCP_DAC_SCK_BIT)
35 | #define mcpDacSckHigh() MCP_DAC_SCK_PORT |= _BV(MCP_DAC_SCK_BIT)
36 | #define mcpDacSckPulse() {mcpDacSckHigh();mcpDacSckLow();}
37 |
38 | #define mcpDacSdiLow() MCP_DAC_SDI_PORT &= ~_BV(MCP_DAC_SDI_BIT)
39 | #define mcpDacSdiHigh() MCP_DAC_SDI_PORT |= _BV(MCP_DAC_SDI_BIT)
40 | #define mcpDacSdiSet(v) if(v){mcpDacSdiHigh();}else{mcpDacSdiLow();}
41 |
42 | // send bit b of d
43 | #define mcpDacSendBit(d, b) {mcpDacSdiSet(d&_BV(b));mcpDacSckPulse();}
44 |
45 | //------------------------------------------------------------------------------
46 | // init dac I/O ports
47 | inline void mcpDacInit(void) {
48 | // set all to output mode
49 | MCP_DAC_CS_DDR |= _BV(MCP_DAC_CS_BIT);
50 | MCP_DAC_SCK_DDR |= _BV(MCP_DAC_SCK_BIT);
51 | MCP_DAC_SDI_DDR |= _BV(MCP_DAC_SDI_BIT);
52 | // chip select high
53 | mcpDacCsHigh();
54 |
55 | #if USE_MCP_DAC_LDAC
56 | // LDAC low always - use unbuffered mode
57 | MCP_DAC_LDAC_DDR |= _BV(MCP_DAC_LDAC_BIT);
58 | MCP_DAC_LDAC_PORT &= ~_BV(MCP_DAC_LDAC_BIT);
59 | #endif // USE_MCP_DAC_LDAC
60 | }
61 | //------------------------------------------------------------------------------
62 | // send 12 bits to dac
63 | // trusted compiler to optimize and it does
64 | // csLow to csHigh takes 8 - 9 usec on a 16 MHz Arduino
65 | inline void mcpDacSend(uint16_t data) {
66 | mcpDacCsLow();
67 | // send DAC config bits
68 | mcpDacSdiLow();
69 | mcpDacSckPulse(); // DAC A
70 | mcpDacSckPulse(); // unbuffered
71 | mcpDacSdiHigh();
72 | mcpDacSckPulse(); // 1X gain
73 | mcpDacSckPulse(); // no SHDN
74 | // send 12 data bits
75 | mcpDacSendBit(data, 11);
76 | mcpDacSendBit(data, 10);
77 | mcpDacSendBit(data, 9);
78 | mcpDacSendBit(data, 8);
79 | mcpDacSendBit(data, 7);
80 | mcpDacSendBit(data, 6);
81 | mcpDacSendBit(data, 5);
82 | mcpDacSendBit(data, 4);
83 | mcpDacSendBit(data, 3);
84 | mcpDacSendBit(data, 2);
85 | mcpDacSendBit(data, 1);
86 | mcpDacSendBit(data, 0);
87 | mcpDacCsHigh();
88 | }
89 |
90 | #endif //mcpDac_h
--------------------------------------------------------------------------------
/microGranny/HW_DEFINES.ino:
--------------------------------------------------------------------------------
1 | #define LATCH_PIN 7
2 | #define CLOCK_PIN 6
3 | #define DATA_PIN 8
4 |
5 | #define ROW_1_PIN 16
6 | #define ROW_2_PIN 17
7 | #define ROW_3_PIN 18
8 | #define ROW_4_PIN 9
9 | #define ROW_5_PIN 19
10 |
11 | #define SET 8
12 | #define PREW 2
13 | #define UP 1
14 | #define DOWN 0
15 | #define BIG_1 3
16 | #define BIG_2 4
17 | #define BIG_3 5
18 | #define BIG_4 6
19 | #define POT 7
20 |
21 |
22 | #define KNOB_PIN_0 0
23 | #define KNOB_PIN_1 1
24 |
25 | #define KNOB_TOLERANCE 3
26 | #define KNOB_FREEZE_DISTANCE 128
27 | #define NUMBER_OF_KNOBS 2
28 | #define NUMBER_OF_BUTTONS 9
29 |
30 | #define SWITCH 4
31 | unsigned char mode;
32 | const unsigned char row[5]={ ROW_1_PIN,ROW_2_PIN,ROW_3_PIN,ROW_4_PIN,ROW_5_PIN };
33 | const unsigned char bigButtons[4]={BIG_1,BIG_2,BIG_3,BIG_4};
34 | const unsigned char knobPin[4]={KNOB_PIN_0,KNOB_PIN_1};
35 |
36 | PROGMEM prog_uint16_t noteSampleRateTable[49]={/*0-C*/2772,2929,3103,3281,3495,3679,3910,4146,4392,4660,4924,5231,/*12-C*/5529,5863,6221,6579,6960,7355,7784,8278,8786,9333,9847,10420,/*24 C*/11025,11665,12402,13119,13898,14706,15606,16491,17550,18555,19677,20857,/*36-C*/22050,23420,24807,26197,27815,29480,31215,33070,35064,37119,39318,41709,/*48-C*/44100};
37 | PROGMEM prog_char texts[]={"standuinoxxxindintpardirpchcrsstrcutshfloprteamtonnoffnorbckrndrd2presel2nd1strepdirlfovolcopsvesvdlpslpecpdpstclr"};
38 | #define XXX 9
39 | #define IND 12
40 | #define INT 15
41 | #define PAR 18
42 | #define DIR 21
43 | #define PCH 24
44 | #define CRS 27
45 | #define STR 30
46 | #define CTT 33
47 | #define SHF 36
48 | #define LOP 39
49 | #define RTE 42
50 | #define AMT 45
51 | #define ONN 48
52 | #define OFF 51
53 | #define FWD 54
54 | #define BCK 57
55 | #define RD1 60
56 | #define RD2 63
57 | #define PRE 66
58 | #define SEL 69
59 |
60 | #define ND 72
61 | #define ST 75
62 | #define REP 78
63 | #define DIR 81
64 | #define LFO 84
65 | #define VOL 87
66 | #define COP 90
67 | #define SVE 93
68 | #define SVD 96
69 | #define LPS 99
70 | #define LPE 102
71 | #define CPD 105
72 | #define PST 108
73 | #define CLR 111
74 |
75 |
76 | #define SEG_A 7 //Display pin 14
77 | #define SEG_B 6 //Display pin 16
78 | #define SEG_C 5 //Display pin 13
79 | #define SEG_D 4 //Display pin 3
80 | #define SEG_E 3 //Display pin 5
81 | #define SEG_F 2 //Display pin 11
82 | #define SEG_G 1 //Display pin 15
83 | #define SEG_DOT 0
84 |
85 |
86 | /*
87 | Segments
88 | - A
89 | F / / B
90 | - G
91 | E / / C
92 | - D
93 | */
94 |
95 | const unsigned char segments[8]={
96 | SEG_A,SEG_B,SEG_C,SEG_D,SEG_E,SEG_F,SEG_G,SEG_DOT};
97 |
98 |
99 | PROGMEM prog_uchar typo[38]={
100 | B00111111, //0
101 | B00000110, //1
102 | B01011011, //2
103 | B01001111, //3
104 | B01100110, //4
105 | B01101101, //5
106 | B01111101, //6
107 | B00000111, //7
108 | B01111111, //8
109 | B01101111, //9
110 | B01110111, //A 10
111 | B01111100, //b
112 | B01011000, //c
113 | B01011110, //d
114 | B01111001, //e
115 | B01110001, //f
116 | B00111101, //g
117 | B01110100, //h
118 | B00000100, //i
119 | B00011110, //j
120 | B01110000, //k 20
121 | B00111000, //l
122 | B01010101, //m
123 | B01010100, //n
124 | B01011100, //o
125 | B01110011, //p 25
126 | B01100111, //q
127 | B01010000, //r
128 | B01101101, //s //tu memit
129 | B01111000, //t
130 | B00011100, //u 30
131 | B00001100, //v 31
132 | B01101010, //w
133 | B01001001, //x
134 | B01110010, //y
135 | B01011011, //z tu menit 35
136 | B00000000, // void 36
137 | B01000000,
138 | };
139 |
140 | #define VOID 36
141 | #define MINUS 37
142 |
143 | /*
144 | Segments
145 | - A
146 | F / / B
147 | - G
148 | E / / C
149 | - D
150 | */
151 |
--------------------------------------------------------------------------------
/microGranny/HW_DEFINITION.ino:
--------------------------------------------------------------------------------
1 | unsigned char buttonState, switchHash,justPressed, justReleased;
2 | unsigned char dealRow;
3 | unsigned char displayBuffer[4];
4 | unsigned char knobHash;
5 | int knobValues[2];
6 |
7 |
8 | #define PITCH_INDEX 0
9 | #define CRUSH_INDEX 1
10 | #define START_INDEX 2
11 | #define CUT_INDEX 3
12 | #define SHIFT_SPEED_INDEX 4
13 | #define LOOP_LEN_INDEX 5
14 | #define LFO_RATE_INDEX 6
15 | #define LFO_AMT_INDEX 7
16 |
17 | const unsigned char knobMaxValue[8]={
18 | 49,64,128,32,64,64,32,16};
19 |
20 | byte doIt;
21 | void UpdateUIInputs(){
22 | HandleMatrix();
23 | UpdateKnobUIInputs();
24 | }
25 |
26 | void InitUI(){
27 |
28 | pinMode(LATCH_PIN,OUTPUT);
29 | pinMode(CLOCK_PIN,OUTPUT);
30 | pinMode(DATA_PIN,OUTPUT);
31 | for(int i=0;i<4;i++){
32 | pinMode(row[i],OUTPUT);
33 | }
34 | pinMode(row[4],INPUT);
35 | digitalWrite(LATCH_PIN,HIGH);
36 | UpdateUIInputs();
37 | IsThereChangeInMidiChannel();
38 | ShouldIClearMemory();
39 |
40 |
41 | }
42 |
43 |
44 | void HandleMatrix(){
45 | for(int i=0;i<9;i++){
46 | JustReleased(i,false);
47 | JustPressed(i,false);
48 | }
49 |
50 | if(dealRow<=4) digitalWrite(row[dealRow],LOW);
51 |
52 | doIt++;
53 | if(doIt>10){
54 |
55 | doIt=0;
56 | }
57 |
58 | dealRow++;
59 | if(dealRow>=4){
60 | ReadButtonsRoutine();
61 | }
62 | if(dealRow>4){
63 | dealRow=0;
64 | }
65 |
66 | if(dealRow<4){
67 | digitalWrite(LATCH_PIN,LOW);
68 | shiftOut(DATA_PIN,CLOCK_PIN,LSBFIRST,~displayBuffer[dealRow]);
69 | digitalWrite(LATCH_PIN,HIGH);
70 | digitalWrite(row[dealRow],HIGH);
71 | }
72 |
73 | }
74 |
75 | void ReadButtonsRoutine(){
76 | digitalWrite(LATCH_PIN,LOW);
77 | shiftOut(DATA_PIN,CLOCK_PIN,LSBFIRST,255);
78 | digitalWrite(LATCH_PIN,HIGH);
79 | digitalWrite(row[3],LOW);
80 | pinMode(row[3],INPUT);
81 | delayMicroseconds(100);
82 | boolean newState=digitalRead(row[3]);
83 |
84 | boolean justRel = (ButtonState(8)!=newState && ButtonState(8))? true: false;
85 | JustReleased(8,justRel);
86 |
87 | boolean justPres = (ButtonState(8)!=newState && !ButtonState(8))? true: false;
88 | JustPressed(8,justPres);
89 |
90 | ButtonState(8,newState);
91 |
92 | /*
93 | if(justPressed(8)){
94 | setTime=millis();
95 | measureSet=true;
96 | }
97 | if(justRealeased(8)){
98 | measureSet=false;
99 | }
100 | if(measureSet){
101 | if(ButtonState(8)){
102 | if(millis()-setTime>=200){
103 | measureSet=false;
104 | setPressed=true;
105 | }
106 | }
107 | }
108 | */
109 |
110 | pinMode(row[3],OUTPUT);
111 | digitalWrite(row[3],LOW);
112 |
113 | digitalWrite(LATCH_PIN,LOW);
114 | shiftOut(DATA_PIN,CLOCK_PIN,LSBFIRST,0);
115 | digitalWrite(LATCH_PIN,HIGH);
116 | for(int i=0;i<8;i++){
117 | unsigned char whichButton=1< KNOB_FREEZE_DISTANCE) {
144 | // KnobFreezed(knobRead, false);
145 | KnobChanged(knobRead, true);
146 | // knobValues[knobRead] = newValue;
147 | }
148 | */
149 | if(CompareToMemory(newValue,knobRead)){
150 | KnobFreezed(knobRead, false);
151 | KnobChanged(knobRead, true);
152 | knobValues[knobRead] = newValue;
153 | };
154 |
155 | //if(newValue==
156 |
157 | }
158 | else if (abs(newValue - knobValues[knobRead]) > KNOB_TOLERANCE) {
159 | knobValues[knobRead] = newValue;
160 | KnobChanged(knobRead, true);
161 | }
162 | }
163 |
164 | }
165 |
166 |
167 | //#################################### Under Functions ####################################//
168 |
169 | unsigned int GetKnobValue(unsigned int index) {
170 | return knobValues[index]; //map(knobValues[index], 0, 1024, 0, 1024);
171 | }
172 |
173 | void FreezeKnobs(){
174 | for(int i=0;i 0){
35 | if (Serial.available() > 0) {
36 |
37 | // read the incoming byte:
38 | byte incomingByte = Serial.read();
39 | Serial.write(incomingByte);
40 |
41 | switch (state){
42 | case 0:
43 |
44 | if(incomingByte==0xF8){ //clock
45 | clockTick++;
46 | if(clockTick==6) doSlaveStep=true, clockTick=0;
47 | slaveMode=true;
48 | }
49 | else if(incomingByte==0xFA){ //start
50 | startPressed=true;
51 | }
52 | else if(incomingByte==0xFC){ //stop
53 |
54 | }
55 |
56 |
57 | else if(incomingByte < 128) { // if running status byte
58 | if(!ignore){ //
59 | note=incomingByte;
60 | state=2;
61 | }
62 | }
63 |
64 | if (incomingByte== (144 | channel)){ // look for as status-byte, our channel, note on
65 | state=1;
66 | ignore=false;
67 | }
68 |
69 | else if (incomingByte== (0x80 | channel)){ // look for as status-byte, our channel, note off
70 | state=1;
71 | ignore=false;
72 | comandOff=true;
73 |
74 | }
75 | else if(incomingByte>127){
76 | ignore=true;
77 | }
78 |
79 |
80 |
81 | break;
82 |
83 | case 1:
84 | // get the note to play or stop
85 | if(incomingByte < 128) {
86 | note=incomingByte;
87 | state=2;
88 | }
89 | else{
90 | state = 0; // reset state machine as this should be a note number
91 | }
92 | break;
93 |
94 | case 2: // get the velocity
95 |
96 | if(incomingByte < 128) {
97 |
98 | if(incomingByte!=0){
99 | if(comandOff){
100 | SetMIDINoteOff(note+1);
101 | //StopSound();
102 |
103 | comandOff=false;
104 | }
105 | else{
106 | // if(note<17){
107 | SetMIDINote(note+1), FreezeKnobs(),ResetCurrentLoop(); // PlaySound(note%12)
108 | //}
109 | // digitalWrite(13,HIGH);
110 | midiNoteOn=true;
111 | }
112 | }
113 | else{
114 | SetMIDINoteOff(note+1);
115 | //StopSound();
116 | // digitalWrite(13,LOW);
117 | midiNoteOn=false;
118 | }
119 | }
120 | state=0;
121 | break;
122 | }
123 | }
124 | }
125 | }
126 |
127 |
128 | boolean midiMode;
129 | unsigned char midiBuffer[16];
130 | unsigned char midiBufferIndex;
131 |
132 | void SetMIDIMode(boolean newMode) {
133 | midiMode = newMode;
134 | }
135 |
136 | void SetMIDINote(unsigned char note) {
137 | midiBuffer[midiBufferIndex] = note;
138 | if (midiBufferIndex < 5) {
139 | midiBufferIndex++;
140 | }
141 | DealMidiInEditMode();
142 |
143 | PlaySound(note);
144 | }
145 |
146 |
147 |
148 | void SetMIDINoteOff(unsigned char note) {
149 | int i = 0;
150 | boolean noteFound = false;
151 | for (i; i < 16; i++) {
152 | if (noteFound) {
153 | midiBuffer[i - 1] = midiBuffer[i];
154 | }
155 | else if (midiBuffer[i] == note) {
156 | midiBuffer[i] = 0;
157 | noteFound = true;
158 | }
159 | }
160 | if (noteFound) {
161 | midiBufferIndex--;
162 | }
163 | if (midiBufferIndex == 0) {
164 | midiMode = false;
165 | setValuesInMidi=true;
166 | StopSound();
167 | }
168 | else{
169 |
170 | if(lastNotePlayed!=midiBuffer[midiBufferIndex-1]) PlaySound(midiBuffer[midiBufferIndex-1]);
171 |
172 | }
173 | /*
174 | for (int j; j <5; j++) {
175 | if(midiBuffer[j]!=0){
176 | PlaySound(midiBuffer([j]);
177 | }
178 | */
179 |
180 | }
181 |
--------------------------------------------------------------------------------
/microGranny/PresetStorage.ino:
--------------------------------------------------------------------------------
1 | unsigned char value[15][8];
2 | unsigned char copyMemory[8];
3 |
4 | unsigned char tempo, currentPreset,preset;
5 | boolean blink;
6 | #define NUMBER_OF_LETTER_1_BYTE 0
7 | #define NUMBER_OF_LETTER_1_BITS 6
8 | #define NUMBER_OF_LETTER_1_OFFSET 0
9 |
10 | #define NUMBER_OF_LETTER_2_BYTE 1
11 | #define NUMBER_OF_LETTER_2_BITS 6
12 | #define NUMBER_OF_LETTER_2_OFFSET 0
13 |
14 | #define NUMBER_OF_LOOP_LEN_BYTE 2
15 | #define NUMBER_OF_LOOP_LEN_BITS 6
16 | #define NUMBER_OF_LOOP_LEN_OFFSET 0
17 |
18 |
19 |
20 | #define NUMBER_OF_PITCH_BYTE 4
21 | #define NUMBER_OF_PITCH_BITS 6
22 | #define NUMBER_OF_PITCH_OFFSET 0
23 |
24 | #define NUMBER_OF_CRUSH_BYTE 5
25 | #define NUMBER_OF_CRUSH_BITS 6
26 | #define NUMBER_OF_CRUSH_OFFSET 0
27 |
28 | #define NUMBER_OF_START_BYTE 6
29 | #define NUMBER_OF_START_BITS 6
30 | #define NUMBER_OF_START_OFFSET 0
31 |
32 | #define NUMBER_OF_START_BYTE_2 2
33 | #define NUMBER_OF_START_BITS_2 1
34 | #define NUMBER_OF_START_OFFSET_2 6
35 |
36 | #define NUMBER_OF_CUT_BYTE 7
37 | #define NUMBER_OF_CUT_BITS 5
38 | #define NUMBER_OF_CUT_OFFSET 0
39 |
40 | #define NUMBER_OF_SHIFT_DIR_BYTE 0
41 | #define NUMBER_OF_SHIFT_DIR_BITS 1
42 | #define NUMBER_OF_SHIFT_DIR_OFFSET 6
43 |
44 | #define NUMBER_OF_LFO_DEST_BYTE 1
45 | #define NUMBER_OF_LFO_DEST_BITS 2
46 | #define NUMBER_OF_LFO_DEST_OFFSET 6
47 |
48 |
49 |
50 | #define NUMBER_OF_REPEAT_BYTE 2
51 | #define NUMBER_OF_REPEAT_BITS 1
52 | #define NUMBER_OF_REPEAT_OFFSET 7
53 |
54 | #define NUMBER_OF_VOLUME_BYTE 3
55 | #define NUMBER_OF_VOLUME_BITS 3
56 | #define NUMBER_OF_VOLUME_OFFSET 5
57 |
58 | #define NUMBER_OF_SHIFT_SPEED_BYTE_1 3
59 | #define NUMBER_OF_SHIFT_SPEED_BITS_1 5
60 | #define NUMBER_OF_SHIFT_SPEED_OFFSET_1 0
61 |
62 | #define NUMBER_OF_SHIFT_SPEED_BYTE_2 0
63 | #define NUMBER_OF_SHIFT_SPEED_BITS_2 1
64 | #define NUMBER_OF_SHIFT_SPEED_OFFSET_2 7
65 |
66 | #define NUMBER_OF_LFO_AMT_BYTE_1 4
67 | #define NUMBER_OF_LFO_AMT_BYTE_2 5
68 | #define NUMBER_OF_LFO_AMT_BITS_1 2
69 | #define NUMBER_OF_LFO_AMT_BITS_2 2
70 | #define NUMBER_OF_LFO_AMT_OFFSET_1 6
71 | #define NUMBER_OF_LFO_AMT_OFFSET_2 6
72 |
73 | #define NUMBER_OF_LFO_RATE_BYTE_1 6
74 | #define NUMBER_OF_LFO_RATE_BYTE_2 7
75 | #define NUMBER_OF_LFO_RATE_BITS_1 2
76 | #define NUMBER_OF_LFO_RATE_BITS_2 3
77 | #define NUMBER_OF_LFO_RATE_OFFSET_1 6
78 | #define NUMBER_OF_LFO_RATE_OFFSET_2 5
79 |
80 | #define LETTER_1 0
81 | #define LETTER_2 1
82 | #define SHIFT_DIR 2
83 | #define LOOP 3
84 | #define VOLUME 4
85 | #define LFO_DEST 5
86 | #define REPEAT 6
87 |
88 | #define PITCH 7
89 | #define CRUSH 8
90 | #define SHIFT_SPEED 9
91 | #define LOOP_LEN 10
92 | #define START 11
93 | #define CUT 12
94 | #define LFO_RATE 13
95 | #define LFO_AMT 14
96 |
97 | void SetValue(unsigned char _VALUE_TYPE,unsigned char _SOUND, unsigned int _setValue){
98 | _SOUND--;
99 | switch(_VALUE_TYPE){
100 | case LETTER_1:
101 | for(int i=0;i=4) potMode=0;
27 |
28 | lastMode=mode;
29 |
30 | if(JustPressed(SET)) setTime=millis();
31 |
32 | if(mode>=10) mode=0, StopSound();
33 | if(mode!=0 && lastMode==0) StopSound(), playSound=0,hold=false;
34 |
35 | if(wave.isplaying) setTime=millis();
36 |
37 | if(ButtonState(SET)){
38 | if(millis()-setTime>50) setMidLongPress=true;
39 | if(millis()-setTime>800) setMidLongPress=false, setLongPress=true, mode=0;
40 | }
41 | else{
42 | setTime=millis();
43 | }
44 |
45 | if(ButtonState(SET) && JustPressed(UP) && mode<8) mode++,setTime=millis(),setMidLongPress=false,setLongPress=false,doublePress=true;
46 | if(ButtonState(SET) && JustPressed(DOWN) && mode>0) mode--,mode--,setTime=millis(),setMidLongPress=false,setLongPress=false,doublePress=true;
47 |
48 | if(lastMode!=0 && mode==0) SetValuesToMemory(editSound),IndexFiles(); //save
49 | if(lastMode==0 && mode!=0) SetValuesFromMemory(editSound);
50 |
51 | if(JustReleased(SET) && !wave.isplaying) {
52 | if(setMidLongPress) mode++, setLongPress=false;//mode=0, setLongPress=false;
53 | else if(setLongPress) mode=0, setLongPress=false;
54 | else if(doublePress) doublePress=false;
55 | // else mode++;
56 |
57 | }
58 |
59 | }
60 |
61 |
62 | void DealMidiInEditMode(){
63 | if(note<=16){
64 | if (mode!=0) editSound=note+1, SetValuesToMemory(lastEditSound), SetValuesFromMemory(editSound), FreezeKnobs();
65 | else if(hold) playSound=note+1, FreezeKnobs(),ResetCurrentLoop();
66 | }
67 | }
68 |
69 | void ProceedEditMode(){
70 |
71 | if(JustPressed(PREW)) PlayAndMakeIndexIfNecessary(editSound);
72 | if(JustReleased(PREW)) StopSound();
73 |
74 | lastEditSound=editSound;
75 |
76 | for(int i=0;i<4;i++){
77 | if(JustPressed(bigButtons[i])) {
78 | bitWrite(editSound,i,!bitRead(editSound,i));
79 | SetValuesToMemory(lastEditSound);
80 | SetValuesFromMemory(editSound);
81 | FreezeKnobs();
82 | }
83 | }
84 |
85 | if(editSound!=0){
86 | if(!ButtonState(SET)){
87 | switch(mode){
88 | case 1:
89 | if(JustPressed(UP) && letter2<35) letter2++,SetValuesToMemory(editSound),SetIndexStatus(editSound,true);
90 | if(JustPressed(DOWN) && letter2>0) letter2--,SetValuesToMemory(editSound),SetIndexStatus(editSound,true);
91 | break;
92 | case 2:
93 | if(JustPressed(UP) && letter1<35) letter1++,SetValuesToMemory(editSound),SetIndexStatus(editSound,true);
94 | if(JustPressed(DOWN) && letter1>0) letter1--,SetValuesToMemory(editSound),SetIndexStatus(editSound,true);
95 | break;
96 | case 3:
97 | if(JustPressed(UP) | JustPressed(DOWN)) repeat=!repeat;
98 | break;
99 | case 4:
100 | if(JustPressed(UP) && shiftDirection<1) shiftDirection++;
101 | if(JustPressed(DOWN) && shiftDirection>0) shiftDirection--;
102 | break;
103 | case 5:
104 | if(JustPressed(UP) | JustPressed(DOWN)) lfoDest=!lfoDest;
105 | break;
106 | case 6:
107 | if(JustPressed(UP) && volume<7) volume++;
108 | if(JustPressed(DOWN) && volume>0) volume--;
109 | break;
110 | case 7:
111 | if(JustPressed(UP)) Copy();
112 | if(JustPressed(DOWN)) Paste();
113 | break;
114 | case 8:
115 | if(JustPressed(UP)) StorePreset(preset), DisplayPGMText(SVD);
116 | if(JustPressed(DOWN)) StorePreset(preset),DisplayPGMText(SVD);
117 | break;
118 | case 9:
119 | if(JustPressed(UP) && preset<7) preset++,LoadPreset(preset),FreezeKnobs(),SetValuesFromMemory(editSound);
120 | if(JustPressed(DOWN) && preset>0) preset--,LoadPreset(preset),FreezeKnobs(),SetValuesFromMemory(editSound);
121 | break;
122 | }
123 | }
124 |
125 | for(int i=0;i<2;i++){
126 | if(KnobChanged(i) && !KnobFreezed(i)) currentSoundVal[i+2*potMode]=map(GetKnobValue(i),0,1024,0,knobMaxValue[i+2*potMode]), SetValuesToMemory(editSound);
127 | }
128 | }
129 |
130 | }
131 |
132 |
133 | void ProceedPlayMode(){
134 |
135 | if(JustPressed(PREW)) hold=!hold;
136 |
137 |
138 | lastPlaySound=playSound;
139 | if(hold) {
140 | for(int i=0;i<4;i++) {
141 | if(JustPressed(bigButtons[i])) bitWrite(playSound,i,!bitRead(playSound,i));
142 | }
143 | }
144 | else{
145 | for(int i=0;i<4;i++) {
146 | bitWrite(playSound,i,ButtonState(bigButtons[i]));
147 | }
148 | }
149 |
150 |
151 | if(playSound!=lastPlaySound) PlaySound(playSound), FreezeKnobs(),ResetCurrentLoop(); // PLAY SOUND
152 | if(lastPlaySound!=0 && playSound==0) StopSound();
153 |
154 | SetValuesFromKnobs();
155 |
156 | if(JustPressed(UP)){
157 | if(wave.isplaying){
158 | switch(currentLoopState){
159 | case 0:
160 | currentLoopStart=wave.readPositionNow();
161 | DisplayPGMText(LPS);
162 | currentLoopState++;
163 | break;
164 | case 1:
165 | currentLoopEnd=wave.readPositionNow();
166 | currentLoop=true;
167 | DisplayPGMText(LPE);
168 | currentLoopState++;
169 | break;
170 | case 2:
171 | ResetCurrentLoop();
172 | break;
173 |
174 | }
175 |
176 | }
177 |
178 | }
179 |
180 | }
181 |
182 | void ResetCurrentLoop(){
183 |
184 | DisplayPGMText(XXX);
185 | //currentLoopStart=0;
186 | //currentLoopEnd=0;
187 | currentLoopState=0;
188 | currentLoop=false;
189 | }
190 |
191 | unsigned char numberOfTap;
192 | long lastTapTime;
193 | int tapMemory[8];
194 |
195 | void tap(){
196 | if(millis()-lastTapTime>3000){
197 | numberOfTap=0;
198 | }
199 | if(numberOfTap==0){
200 | lastTapTime=millis();
201 | numberOfTap++;
202 | }
203 | else{
204 | if(numberOfTap>8){
205 | for(int i=0;i<8;i++) {
206 | tapMemory[i]=tapMemory[i+1];
207 | }
208 | numberOfTap=8;
209 | }
210 | tapMemory[numberOfTap-1]= millis()-lastTapTime;
211 | lastTapTime=millis();
212 | int tapTogether;
213 | for(int i=0;i80) blink=!blink, blinkTime=millis();
73 | if(millis()-knobDisplayTime>320) knobDisplay=false;
74 |
75 | if(whileShow){
76 | if(millis()-whileTime>WHILE) whileShow=false, ShowValue();
77 | }
78 |
79 | else {
80 | for(int i=0;i=36) DisplayNumber(currentSoundVal[i+2*potMode]-36),lightNumber(VOID,0);
84 | else DisplayNumber(36- currentSoundVal[i+2*potMode]),lightNumber(MINUS,0);
85 | }
86 | else if(i+2*potMode==4){
87 | if(currentSoundVal[4]>=32) DisplayNumber(currentSoundVal[i+2*potMode]-32),lightNumber(VOID,0);
88 | else DisplayNumber(32- currentSoundVal[i+2*potMode]),lightNumber(MINUS,0);
89 | }
90 | else DisplayNumber(currentSoundVal[i+2*potMode]);
91 | knobDisplay=true;
92 | knobDisplayTime=millis();
93 | }
94 | };
95 | if(!knobDisplay){
96 | switch(mode){
97 | case 0:
98 | break;
99 | case 1:
100 | ShowValue();
101 | if(blink) lightNumber(VOID,2);
102 | break;
103 | case 2:
104 | ShowValue();
105 | if(blink) lightNumber(VOID,1);
106 | break;
107 | default:
108 | ShowValue();
109 | break;
110 |
111 | }
112 | }
113 |
114 | }
115 |
116 |
117 | lastShowType=showType;
118 | if(KnobChanged(0)) lastKnobChanged=0;
119 | if(KnobChanged(1)) lastKnobChanged=1;
120 | if(KnobChanged(0) | KnobChanged(1)) showType= 2*potMode+lastKnobChanged;
121 |
122 |
123 | if(lastShowType!=showType){
124 | modeDisplayed=false;
125 | switch(showType){ // nahradit textovym arrayem
126 | case PITCH_INDEX:
127 | ShowForAWhilePGM(PCH);
128 | break;
129 | case CRUSH_INDEX:
130 | ShowForAWhilePGM(CRS);
131 | break;
132 | case START_INDEX:
133 | ShowForAWhilePGM(STR);
134 | break;
135 | case CUT_INDEX:
136 | ShowForAWhilePGM(CTT);
137 | break;
138 | case SHIFT_SPEED_INDEX:
139 | ShowForAWhilePGM(SHF);
140 | break;
141 | case LOOP_LEN_INDEX:
142 | ShowForAWhilePGM(LOP);
143 | break;
144 | case LFO_RATE_INDEX:
145 | ShowForAWhilePGM(RTE);
146 | break;
147 | case LFO_AMT_INDEX:
148 | ShowForAWhilePGM(AMT);
149 | break;
150 | }
151 | }
152 |
153 | bitWrite(displayBuffer[3],1,bitRead(potMode,1));
154 | bitWrite(displayBuffer[3],7,bitRead(potMode,0));
155 |
156 |
157 | if(mode==0){
158 | for(int i=0;i<4;i++) bitWrite(displayBuffer[3],i+3,bitRead(playSound,i));
159 | bitWrite(displayBuffer[3],PREW,hold);
160 | }
161 | else{
162 | for(int i=0;i<4;i++) bitWrite(displayBuffer[3],i+3,bitRead(editSound,i));
163 | bitWrite(displayBuffer[3],PREW,ButtonState(PREW));
164 | }
165 |
166 |
167 | if(mode!=lastMode){
168 | modeDisplayed=true;
169 | if(mode==0) ShowForAWhilePGM(XXX);
170 | else if(editSound!=0){
171 | switch(mode){ // nahradit textovym arrayem
172 | case 0:
173 | ShowForAWhilePGM(XXX);
174 | break;
175 | case 1:
176 | ShowForAWhilePGM(ND);
177 | break;
178 | case 2:
179 | ShowForAWhilePGM(ST);
180 | break;
181 | case 3:
182 | ShowForAWhilePGM(REP);
183 | break;
184 | case 4:
185 | ShowForAWhilePGM(DIR);
186 | break;
187 | case 5:
188 | ShowForAWhilePGM(LFO);
189 | break;
190 | case 6:
191 | ShowForAWhilePGM(VOL);
192 | break;
193 | case 7:
194 | ShowForAWhilePGM(COP);
195 | break;
196 | case 8:
197 | ShowForAWhilePGM(SVE);
198 | break;
199 | case 9:
200 | ShowForAWhilePGM(PRE);
201 | break;
202 | }
203 | }
204 | else{
205 | // DisplayNumber(freeRam());
206 | DisplayPGMText(SEL);
207 | // ShowForAWhile("sel");
208 | }
209 | }
210 |
211 |
212 | if(mode>2){
213 | for(int i=0;i<3;i++) bitWrite(displayBuffer[2-i],0,bitRead(mode-2,i));
214 | }
215 | else for(int i=0;i<3;i++) bitWrite(displayBuffer[2-i],0,0);
216 |
217 | }
218 |
219 |
220 | void ShowForAWhile(char* _charShow){
221 | // showedChar=_charShow;
222 | whileShow=true;
223 | whileTime=millis();
224 | DisplayText(_charShow);
225 |
226 | }
227 |
228 | void ShowForAWhilePGM(int _charShow){
229 | // showedChar=_charShow;
230 | whileShow=true;
231 | whileTime=millis();
232 | DisplayPGMText(_charShow);
233 |
234 | }
235 |
236 | void ShowForAWhile(int _charShow){
237 |
238 | // showedChar=_charShow;
239 | whileShow=true;
240 | whileTime=millis();
241 | DisplayNumber(_charShow);
242 |
243 | }
244 |
245 |
246 | void DisplayNumber(int _number){
247 |
248 | lightNumber(_number/100,0);
249 | lightNumber((_number%100)/10,1);
250 | lightNumber(_number%10,2);
251 |
252 | }
253 |
254 | void InitialAnimation(){
255 |
256 | long time; // nahradit textovym arrayem a forcyklem
257 | char temp[3];
258 | for(int j=0;j<7;j++){
259 | for(int i=0;i<3;i++) temp[i]=pgm_read_word_near(texts+i+j);
260 |
261 | DisplayText(temp);
262 | time=millis();
263 | while((millis()-time)<250) UpdateUIInputs();
264 | }
265 | /*
266 | DisplayNumber(freeRam());
267 | time=millis();
268 | while((millis()-time)<400) UpdateUIInputs();
269 | */
270 | DisplayPGMText(XXX);
271 | }
272 |
273 |
274 | int freeRam () {
275 | extern int __heap_start, *__brkval;
276 | int v;
277 | return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
278 | }
279 |
280 | void DisplayPGMText(unsigned char _whichText){
281 | char temp[3];
282 | for(int i=0;i<3;i++) temp[i]=pgm_read_word_near(texts+_whichText+i);
283 | DisplayText(temp);
284 | }
285 |
--------------------------------------------------------------------------------
/microGranny/microGranny.ino:
--------------------------------------------------------------------------------
1 | /*
2 | ****************************************************
3 | -----STANDUINO-------MICRO GRANNY--SAMPLER---------
4 | ***************************************************
5 |
6 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 | SAMPLER:
8 | -plays wave samples from SD card through 12 bit D/A converter
9 | -hackable in hardware (there is lot of free space to add features) and software (it is open source and re-programmable form Arduino)
10 | -intuitive interface with 4 perfect response big buttons, 2 pots, 5 small buttons and 3 digit 7-segment display
11 | -edit mode where you fully adjust the 15 different sound (each big button press combination makes different sound)
12 | -for each sound you can adjust:
13 | -basic functions: sample,repeat,volume,pitch,bitCrush,start,cut
14 | -micro sampling features: loop length, shift speed, shift direction
15 | -lfo: rate, amt, destination
16 | -MIDI input
17 | -8 presets
18 | -3,5mm headphone output jack connector (directly to pwm pin) -can power stereo headphones (but instrument is in mono),
19 | -volume adjust pot
20 | -9-12V power supply from battery or adaptor
21 |
22 | software by: Vaclav Pelousek www.pelousek.eu
23 | developed by Standuino: www.standuino.eu
24 |
25 | uses hacked version of waveHC library
26 | uses parts of Audio project and MIDI library
27 |
28 |
29 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30 |
31 | */
32 |
33 | /*
34 |
35 | to be fixed to DONE DONE
36 | -DONE - end of sample stop by readPosition-doesn affect bad samples
37 | -instant loop in microSampling...?
38 |
39 | future improovements
40 | -midi cc
41 |
42 | jako easter egg:
43 | -loop lenth násobek hodnoty tempo
44 | -tempo tapovací
45 | -tempo spocítat z délky tracku
46 | delka tracku v bytech
47 | samplovací frekvence.počet bytů za secundu
48 | f=b/t
49 | t=b/f
50 | t=size/22500
51 | tempo=beats/t
52 | 64 32 16 8 4 2 1 2x 4x 8x
53 |
54 | */
55 |
56 | #include
57 | #include
58 | #include
59 | #include
60 |
61 | SdReader card; // This object holds the information for the card
62 | FatVolume vol; // This holds the information for the partition on the card
63 | FatReader root; // This holds the information for the volumes root directory
64 | FatReader file; // This object represent the WAV file for a pi digit or period
65 | WaveHC wave; // This is the only wave (audio) object, since we will only play one at a time
66 | #define error(msg) error_P(PSTR(msg))
67 | boolean isError;
68 | #define XXX 9
69 |
70 | void setup() {
71 |
72 | InitUI();
73 | MidiBegin();
74 | SamplerInit();
75 | LoadPreset(0);
76 | InitialAnimation();
77 | IndexFiles();
78 | DisplayPGMText(XXX);
79 |
80 | }
81 |
82 |
83 | void loop() {
84 |
85 | MidiRead();
86 | // MidiRead();
87 | UpdateUIInputs();
88 | MidiRead();
89 | // MidiRead();
90 | UpdateApplicationLayer();
91 | MidiRead();
92 | // MidiRead();
93 | ReflectApplicationLayer();
94 | MidiRead();
95 | // MidiRead();
96 | RenderSample();
97 |
98 | }
99 |
--------------------------------------------------------------------------------
/microGranny/sampler.ino:
--------------------------------------------------------------------------------
1 | char sampleName[]="00.WAV";
2 | uint16_t fileIndex[16];
3 | long startGranule, cutTime,cutLimit,loopTime,loopLimit,shiftNow, lfoTime;
4 | unsigned char start,midiPitch;
5 | int shiftSpeed;
6 | boolean lfoUp=true,shiftUp;
7 | int lfoStep;
8 |
9 |
10 | void RenderSample(){
11 | // current loop
12 | if(currentLoop){
13 | if(wave.readPositionNow()>=currentLoopEnd){
14 | wave.stop();
15 | wave.seek(currentLoopStart);
16 | wave.play();
17 | if(midiMode) wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+midiPitch));
18 | else wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+currentSoundVal[PITCH_INDEX]));
19 |
20 | }
21 | }
22 |
23 | //REPEAT
24 | //if(wave.readPositionNow()>=wave.getSize()-50) wave.stop();
25 |
26 | if (!wave.isplaying){
27 | shiftNow=0;
28 | if(mode==0){
29 | if(repeat && playSound!=0) {
30 |
31 | wave.seek(startGranule*start);
32 | cutTime=millis();
33 | wave.play();
34 | if(midiMode) wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+midiPitch));
35 | else wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+currentSoundVal[PITCH_INDEX]));
36 |
37 | }
38 |
39 | else wave.stop();
40 | }
41 |
42 | else{
43 | if(repeat && ButtonState(PREW)) {
44 | wave.seek(startGranule*start);
45 | cutTime=millis();
46 | wave.play();
47 | if(midiMode) wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+midiPitch));
48 | else wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+currentSoundVal[PITCH_INDEX]));
49 |
50 | }
51 | else wave.stop();
52 | }
53 |
54 | }
55 | //REPEAT
56 |
57 | //CUT //wave.readPosition(); //a wish
58 | if(currentSoundVal[CUT_INDEX]<31){
59 | if(millis()-cutTime>=cutLimit){
60 | wave.stop();
61 | }
62 | }
63 | //CUT
64 |
65 | //MICROSAMPLING
66 | if (wave.isplaying){
67 | if(currentSoundVal[LOOP_LEN_INDEX]!=0){
68 |
69 |
70 | if(millis()-loopTime>=loopLimit){
71 | loopTime=millis();
72 |
73 | switch(shiftDirection){
74 | case 0:
75 | shiftNow+=shiftSpeed;
76 | /*
77 | if(shiftSpeed==32) shiftNow=shiftNow;
78 | else if(shiftSpeed>32) shiftNow+=(shiftSpeed-32);
79 | else if (shiftSpeed<32) shiftNow-=(32-shiftSpeed);
80 | */
81 |
82 | break;
83 | case 1:
84 | if(random(2)==0) shiftNow+=shiftSpeed;
85 | else shiftNow-=shiftSpeed;
86 | break;
87 | /*
88 | shiftNow-=shiftSpeed;
89 | break;
90 | case 2:
91 |
92 | break;
93 | case 3:
94 | if(random(4)==0) shiftUp=!shiftUp;
95 | if(shiftUp) shiftNow+=shiftSpeed;
96 | else shiftNow-=shiftSpeed;
97 |
98 | break;
99 | */
100 | }
101 |
102 | wave.stop();
103 | wave.seek(startGranule*start+shiftNow);
104 | wave.play();
105 | if(midiMode) wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+midiPitch));
106 | else wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+currentSoundVal[PITCH_INDEX]));
107 |
108 | }
109 |
110 | }
111 | else{
112 | shiftNow=wave.readPositionNow();
113 | }
114 |
115 | }
116 | //MICROSAMPLING
117 |
118 | //RENDER TWEAKING
119 | if(potMode==0 && KnobChanged(0) && !KnobFreezed(0)) if(!midiMode) wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+currentSoundVal[PITCH_INDEX])); //UDELAT LADENOU TABULKU!!!
120 | if(potMode==0 && KnobChanged(1) && !KnobFreezed(1)) wave.crush= map(currentSoundVal[CRUSH_INDEX],0,64,0,255);
121 |
122 | if(potMode==1 && KnobChanged(0) && !KnobFreezed(0)) start=currentSoundVal[START_INDEX];
123 | if(potMode==1 && KnobChanged(1) && !KnobFreezed(1)) cutLimit=map(currentSoundVal[CUT_INDEX],0,31,1,1000);
124 |
125 | if(potMode==2 && KnobChanged(0) && !KnobFreezed(0)) shiftSpeed=map(currentSoundVal[SHIFT_SPEED_INDEX],0,64,-5000,5000);
126 | if(potMode==2 && KnobChanged(1) && !KnobFreezed(1)) loopLimit=map(currentSoundVal[LOOP_LEN_INDEX],0,64,1,500);
127 | //RENDER TWEAKING
128 |
129 | //RENDER LFO
130 |
131 | RenderLfo();
132 |
133 | }
134 |
135 | void RenderLfo(){
136 |
137 | if(currentSoundVal[LFO_AMT_INDEX]!=0){
138 |
139 | unsigned char lfoAmt=currentSoundVal[LFO_AMT_INDEX];
140 | unsigned char lfoRate=map(currentSoundVal[LFO_RATE_INDEX],0,31,50,1);
141 |
142 | if(millis()-lfoTime>=lfoRate){
143 | lfoTime=millis();
144 |
145 | if(lfoUp){
146 | lfoStep++;
147 | if(lfoStep>=16) lfoUp=false;
148 | }
149 | else{
150 | lfoStep--;
151 | if(lfoStep<=0) lfoUp=true;
152 | }
153 |
154 | switch(lfoDest){
155 |
156 | case 0:
157 | if(midiMode) wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+midiPitch)+lfoAmt*(lfoStep-8)*50);
158 | else wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+currentSoundVal[PITCH_INDEX])+lfoAmt*(lfoStep-8)*50);
159 |
160 | // wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+currentSoundVal[PITCH_INDEX])+lfoAmt*(lfoStep-8)*50);
161 | break;
162 | case 1:
163 | wave.crush= map(currentSoundVal[CRUSH_INDEX],0,64,0,255)+lfoStep*lfoAmt;
164 | break;
165 | }
166 |
167 | }
168 | }
169 |
170 | }
171 |
172 |
173 | void PlaySound(unsigned char _playSound){
174 |
175 | if(_playSound>16) midiMode = true;
176 | else {
177 | midiMode = false, lastPlayedNote=_playSound;
178 |
179 | };
180 |
181 | unsigned char _playWhat;
182 | StopSound();
183 |
184 |
185 | if(mode!=0) _playWhat=editSound;
186 | else {
187 | if(midiMode){
188 | _playWhat=lastPlayedNote;
189 | if(setValuesInMidi) SetValuesFromMemory(lastPlayedNote),setValuesInMidi=false;
190 | }
191 | else _playWhat=_playSound, SetValuesFromMemory(_playSound);
192 | }
193 | wave.crush= map(currentSoundVal[CRUSH_INDEX],0,64,0,255);
194 | playfile(_playWhat);
195 | if(currentSoundVal[START_INDEX]!=0){
196 | startGranule=wave.getSize()/128;
197 | start=currentSoundVal[START_INDEX];
198 | wave.seek(startGranule*start);
199 | }
200 | else{
201 | wave.seek(0);
202 | }
203 |
204 | cutLimit=map(currentSoundVal[CUT_INDEX],0,31,1,1000);
205 | cutTime=millis();
206 | shiftSpeed=map(currentSoundVal[SHIFT_SPEED_INDEX],0,64,-5000,5000);
207 | loopLimit=map(currentSoundVal[LOOP_LEN_INDEX],0,64,1,500);
208 | loopTime=millis();
209 | shiftNow=0;
210 | wave.play();
211 | wave.volume= 7-volume;
212 | if(midiMode) {
213 | if(_playSound<25) midiPitch=0;
214 | else if(_playSound>72) midiPitch=48;
215 | else midiPitch=_playSound-25;
216 | wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+midiPitch));
217 | lastNotePlayed=_playSound;
218 | }
219 | else wave.setSampleRate(pgm_read_word_near(noteSampleRateTable+currentSoundVal[PITCH_INDEX])),lastNotePlayed=_playSound;
220 |
221 |
222 |
223 | }
224 |
225 |
226 |
227 |
228 | void StopSound(){
229 | wave.stop();
230 | }
231 |
232 |
233 | char* soundName(byte soundNumber){
234 |
235 | letter1=GetValue(LETTER_1,soundNumber);
236 | letter2=GetValue(LETTER_2,soundNumber);
237 |
238 | if(letter1>9) sampleName[0]=letter1+55;
239 | else sampleName[0]=letter1+48;
240 | if(letter2>9) sampleName[1]=letter2+55;
241 | else sampleName[1]=letter2+48;
242 |
243 | return sampleName;
244 | }
245 |
246 | char* soundName(){
247 | if(letter1>9) sampleName[0]=letter1+55;
248 | else sampleName[0]=letter1+48;
249 | if(letter2>9) sampleName[1]=letter2+55;
250 | else sampleName[1]=letter2+48;
251 | return sampleName;
252 | }
253 |
254 |
255 |
256 | void playfile(char *name) { //not indexed
257 | if (wave.isplaying) {
258 | wave.stop();
259 | }
260 |
261 | if (!file.open(root, name)) {
262 | //PgmPrint("Couldn't open file ");
263 | return;
264 | }
265 |
266 | if (!wave.create(file)) {
267 | //PgmPrintln("Not a valid WAV");
268 | return;
269 | }
270 |
271 | // wave.play();
272 | }
273 |
274 | void playfile(unsigned char soundNumber) { //INDEXED
275 |
276 | if (wave.isplaying) {
277 | wave.stop();
278 | }
279 |
280 | if (!file.open(root, fileIndex[soundNumber-1])) {
281 | //error("open by index");
282 | return;
283 | }
284 |
285 | if (!wave.create(file)) {
286 | //PgmPrintln("Not a valid WAV");
287 | return;
288 | }
289 |
290 | // wave.play();
291 | }
292 |
293 | void IndexFiles(void)
294 | {
295 | wave.stop();
296 | DisplayPGMText(IND);
297 | for (int i = 0; i < 15; i++) {
298 | UpdateUIInputs();
299 | if(GetIndexStatus(i+1)){
300 | if (!file.open(root, soundName(i+1))) ;
301 | fileIndex[i] = root.readPosition()/32 - 1;
302 | } // Save file's index (byte offset of directory entry divided by entry size) // Current position is just after entry so subtract on
303 | SetIndexStatus(i+1,false);
304 | }
305 |
306 | }
307 |
308 | void IndexFile(unsigned char _sound)
309 | {
310 | wave.stop();
311 | if (!file.open(root, soundName(_sound))) ;
312 | fileIndex[_sound-1] = root.readPosition()/32 - 1;
313 | SetIndexStatus(_sound,false);
314 |
315 |
316 | }
317 |
318 |
319 | void Reboot(){
320 | for(int i=0;i