├── .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