├── bootloaderbuild ├── EEPROM.h ├── main.cpp └── Makefile ├── core ├── core.a ├── Tone.cpp.o ├── wiring.c.o ├── Print.cpp.o ├── WMath.cpp.o ├── WString.cpp.o ├── WInterrupts.c.o ├── wiring_analog.c.o ├── wiring_digital.c.o ├── wiring_pulse.c.o ├── wiring_shift.c.o ├── HardwareSerial.cpp.o ├── TinySoftwareSPI.cpp.o ├── TinySoftwareSerial.cpp.o ├── WMath.cpp.d ├── WString.cpp.d ├── wiring.c.d ├── WInterrupts.c.d ├── wiring_analog.c.d ├── wiring_pulse.c.d ├── wiring_shift.c.d ├── wiring_digital.c.d ├── Print.cpp.d ├── Tone.cpp.d ├── HardwareSerial.cpp.d ├── TinySoftwareSerial.cpp.d └── TinySoftwareSPI.cpp.d ├── java_source ├── MANIFEST.MF ├── waveFile │ ├── WavFile.class │ ├── AePlayWave.class │ ├── ReadExample.class │ ├── WriteExample.class │ ├── WavFile$IOState.class │ ├── WavFileException.class │ ├── AePlayWave$Position.class │ ├── WavFileException.java │ ├── ReadExample.java │ ├── WriteExample.java │ ├── AePlayWave.java │ └── WavFile.java ├── wavCreator │ ├── BootFrame.class │ ├── HexToSignal.class │ ├── WavCodeGenerator.class │ ├── BootFrame.java │ ├── HexToSignal.java │ └── WavCodeGenerator.java ├── hexTools │ ├── IntelHexFormat.class │ └── IntelHexFormat.java ├── controllPanel │ ├── Main_WavBootLoader.class │ ├── Main_WavBootLoader.java │ ├── Model_ProgrammParameters.class │ ├── Main_WavBootLoader$writeWav_ButtonListener.class │ ├── Main_WavBootLoader$inputHexFile_ButtonListener.class │ ├── Main_WavBootLoader$inputHexFile_ButtonListener$1.class │ └── Model_ProgrammParameters.java └── java_compile.sh ├── doc ├── AudioBootLoader.odp ├── AudioBootloader.fzz ├── NeoCycloSynth.PNG ├── 8BitMixTapeNeolit.jpg ├── AudioBootLoaderFlyer.png ├── audioInputSchematic.PNG ├── FritzingNeoCycloSynth.PNG ├── 8BitMixedTapeNeoprenEdition.jpg └── AudioBootLoaderMinimumBreadBoard.PNG ├── .gitignore ├── README.md └── TinyAudioBoot ├── EEPROM.h └── TinyAudioBoot.c /bootloaderbuild/EEPROM.h: -------------------------------------------------------------------------------- 1 | ../TinyAudioBoot/EEPROM.h -------------------------------------------------------------------------------- /bootloaderbuild/main.cpp: -------------------------------------------------------------------------------- 1 | ../TinyAudioBoot/TinyAudioBoot.c -------------------------------------------------------------------------------- /core/core.a: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/core.a -------------------------------------------------------------------------------- /core/Tone.cpp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/Tone.cpp.o -------------------------------------------------------------------------------- /core/wiring.c.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/wiring.c.o -------------------------------------------------------------------------------- /java_source/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Main-Class: controllPanel/Main_WavBootLoader 3 | -------------------------------------------------------------------------------- /core/Print.cpp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/Print.cpp.o -------------------------------------------------------------------------------- /core/WMath.cpp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/WMath.cpp.o -------------------------------------------------------------------------------- /core/WString.cpp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/WString.cpp.o -------------------------------------------------------------------------------- /core/WInterrupts.c.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/WInterrupts.c.o -------------------------------------------------------------------------------- /core/wiring_analog.c.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/wiring_analog.c.o -------------------------------------------------------------------------------- /core/wiring_digital.c.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/wiring_digital.c.o -------------------------------------------------------------------------------- /core/wiring_pulse.c.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/wiring_pulse.c.o -------------------------------------------------------------------------------- /core/wiring_shift.c.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/wiring_shift.c.o -------------------------------------------------------------------------------- /doc/AudioBootLoader.odp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/doc/AudioBootLoader.odp -------------------------------------------------------------------------------- /doc/AudioBootloader.fzz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/doc/AudioBootloader.fzz -------------------------------------------------------------------------------- /doc/NeoCycloSynth.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/doc/NeoCycloSynth.PNG -------------------------------------------------------------------------------- /core/HardwareSerial.cpp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/HardwareSerial.cpp.o -------------------------------------------------------------------------------- /doc/8BitMixTapeNeolit.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/doc/8BitMixTapeNeolit.jpg -------------------------------------------------------------------------------- /core/TinySoftwareSPI.cpp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/TinySoftwareSPI.cpp.o -------------------------------------------------------------------------------- /doc/AudioBootLoaderFlyer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/doc/AudioBootLoaderFlyer.png -------------------------------------------------------------------------------- /doc/audioInputSchematic.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/doc/audioInputSchematic.PNG -------------------------------------------------------------------------------- /core/TinySoftwareSerial.cpp.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/core/TinySoftwareSerial.cpp.o -------------------------------------------------------------------------------- /doc/FritzingNeoCycloSynth.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/doc/FritzingNeoCycloSynth.PNG -------------------------------------------------------------------------------- /doc/8BitMixedTapeNeoprenEdition.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/doc/8BitMixedTapeNeoprenEdition.jpg -------------------------------------------------------------------------------- /java_source/waveFile/WavFile.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/waveFile/WavFile.class -------------------------------------------------------------------------------- /java_source/wavCreator/BootFrame.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/wavCreator/BootFrame.class -------------------------------------------------------------------------------- /java_source/waveFile/AePlayWave.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/waveFile/AePlayWave.class -------------------------------------------------------------------------------- /java_source/waveFile/ReadExample.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/waveFile/ReadExample.class -------------------------------------------------------------------------------- /doc/AudioBootLoaderMinimumBreadBoard.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/doc/AudioBootLoaderMinimumBreadBoard.PNG -------------------------------------------------------------------------------- /java_source/wavCreator/HexToSignal.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/wavCreator/HexToSignal.class -------------------------------------------------------------------------------- /java_source/waveFile/WriteExample.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/waveFile/WriteExample.class -------------------------------------------------------------------------------- /java_source/hexTools/IntelHexFormat.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/hexTools/IntelHexFormat.class -------------------------------------------------------------------------------- /java_source/waveFile/WavFile$IOState.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/waveFile/WavFile$IOState.class -------------------------------------------------------------------------------- /java_source/waveFile/WavFileException.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/waveFile/WavFileException.class -------------------------------------------------------------------------------- /java_source/wavCreator/WavCodeGenerator.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/wavCreator/WavCodeGenerator.class -------------------------------------------------------------------------------- /java_source/waveFile/AePlayWave$Position.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/waveFile/AePlayWave$Position.class -------------------------------------------------------------------------------- /java_source/controllPanel/Main_WavBootLoader.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/controllPanel/Main_WavBootLoader.class -------------------------------------------------------------------------------- /java_source/controllPanel/Main_WavBootLoader.java: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/controllPanel/Main_WavBootLoader.java -------------------------------------------------------------------------------- /java_source/controllPanel/Model_ProgrammParameters.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/controllPanel/Model_ProgrammParameters.class -------------------------------------------------------------------------------- /core/WMath.cpp.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/WMath.cpp.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WMath.cpp 3 | -------------------------------------------------------------------------------- /java_source/controllPanel/Main_WavBootLoader$writeWav_ButtonListener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/controllPanel/Main_WavBootLoader$writeWav_ButtonListener.class -------------------------------------------------------------------------------- /java_source/controllPanel/Main_WavBootLoader$inputHexFile_ButtonListener.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/controllPanel/Main_WavBootLoader$inputHexFile_ButtonListener.class -------------------------------------------------------------------------------- /java_source/controllPanel/Main_WavBootLoader$inputHexFile_ButtonListener$1.class: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATtinyTeenageRiot/TinyAudioBoot/HEAD/java_source/controllPanel/Main_WavBootLoader$inputHexFile_ButtonListener$1.class -------------------------------------------------------------------------------- /core/WString.cpp.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/WString.cpp.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WString.cpp \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WString.h 4 | -------------------------------------------------------------------------------- /java_source/java_compile.sh: -------------------------------------------------------------------------------- 1 | rm -fr */*.class 2 | javac -classpath . */*.java 3 | jar cvfm hex2wav.jar MANIFEST.MF */*.class 4 | #java -cp . controllPanel/Main_WavBootLoader 5 | java -jar hex2wav.jar /Users/xcorex/Documents/Projects/AVR/8BitMixtapeNeo/TinyAudioBoot/build/AudioBootAttiny85_AudioPB3_LEDPB1.hex 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /TinyAudioBoot/SendOnlySoftwareSerial.d 2 | /TinyAudioBoot/SendOnlySoftwareSerial.o 3 | /TinyAudioBoot/SendOnlySoftwareSerial.cpp.lst 4 | /build/TinyAudioBoot.ino.lst 5 | /build/main.bin 6 | /build/main.map 7 | /build/main.hex 8 | /build/TinyAudioBoot.d 9 | /build/TinyAudioBoot.o 10 | /java_source/test.wav 11 | /build/test.wav 12 | -------------------------------------------------------------------------------- /java_source/waveFile/WavFileException.java: -------------------------------------------------------------------------------- 1 | // source from http://www.labbookpages.co.uk/audio/javaWavFiles.html 2 | package waveFile; 3 | 4 | public class WavFileException extends Exception 5 | { 6 | public WavFileException() 7 | { 8 | super(); 9 | } 10 | 11 | public WavFileException(String message) 12 | { 13 | super(message); 14 | } 15 | 16 | public WavFileException(String message, Throwable cause) 17 | { 18 | super(message, cause); 19 | } 20 | 21 | public WavFileException(Throwable cause) 22 | { 23 | super(cause); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /core/wiring.c.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/wiring.c.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring.c \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_private.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h 7 | -------------------------------------------------------------------------------- /core/WInterrupts.c.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/WInterrupts.c.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WInterrupts.c \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_private.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h 7 | -------------------------------------------------------------------------------- /core/wiring_analog.c.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/wiring_analog.c.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_analog.c \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_private.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h 7 | -------------------------------------------------------------------------------- /core/wiring_pulse.c.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/wiring_pulse.c.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_pulse.c \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_private.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h 7 | -------------------------------------------------------------------------------- /core/wiring_shift.c.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/wiring_shift.c.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_shift.c \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_private.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h 7 | -------------------------------------------------------------------------------- /core/wiring_digital.c.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/wiring_digital.c.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_digital.c \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_private.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h 7 | -------------------------------------------------------------------------------- /core/Print.cpp.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/Print.cpp.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Print.cpp \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WCharacter.h \ 7 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WString.h \ 8 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/HardwareSerial.h \ 9 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/TinySoftwareSerial.h \ 10 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Stream.h \ 11 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Print.h 12 | -------------------------------------------------------------------------------- /core/Tone.cpp.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/Tone.cpp.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Tone.cpp \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WCharacter.h \ 7 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WString.h \ 8 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/HardwareSerial.h \ 9 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/TinySoftwareSerial.h \ 10 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Stream.h \ 11 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Print.h \ 12 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_private.h 13 | -------------------------------------------------------------------------------- /core/HardwareSerial.cpp.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/HardwareSerial.cpp.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/HardwareSerial.cpp \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WCharacter.h \ 7 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WString.h \ 8 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/HardwareSerial.h \ 9 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/TinySoftwareSerial.h \ 10 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Stream.h \ 11 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Print.h \ 12 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_private.h 13 | -------------------------------------------------------------------------------- /core/TinySoftwareSerial.cpp.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/TinySoftwareSerial.cpp.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/TinySoftwareSerial.cpp \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WCharacter.h \ 7 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WString.h \ 8 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/HardwareSerial.h \ 9 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/TinySoftwareSerial.h \ 10 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Stream.h \ 11 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Print.h \ 12 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/wiring_private.h 13 | -------------------------------------------------------------------------------- /core/TinySoftwareSPI.cpp.d: -------------------------------------------------------------------------------- 1 | /var/folders/x6/17svhgds0x7889jbwj0rb4y80000gp/T/arduino_build_426281/core/TinySoftwareSPI.cpp.o: \ 2 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/TinySoftwareSPI.cpp \ 3 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/TinySoftwareSPI.h \ 4 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h \ 5 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/binary.h \ 6 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5/pins_arduino.h \ 7 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WCharacter.h \ 8 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/WString.h \ 9 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/HardwareSerial.h \ 10 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/TinySoftwareSerial.h \ 11 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Stream.h \ 12 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Print.h \ 13 | /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny/Arduino.h 14 | -------------------------------------------------------------------------------- /java_source/controllPanel/Model_ProgrammParameters.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | wave generator for audio bootloader 4 | 5 | standard setup 6 | 7 | (c) -C-H-R-I-S-T-O-P-H- -H-A-B-E-R-E-R- 2011 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | */ 14 | package controllPanel; 15 | 16 | import java.io.File; 17 | 18 | public class Model_ProgrammParameters 19 | { 20 | private File inputHexFile; 21 | private File outputWavFile; 22 | private int data[]; 23 | 24 | public Model_ProgrammParameters() 25 | { 26 | inputHexFile=new File("test.hex"); 27 | outputWavFile=new File("test.wav"); 28 | 29 | data=new int[200]; 30 | // test 31 | for(int n=0;n<200;n++)data[n]=n; 32 | } 33 | 34 | public void setOutputWavFile(File outputWavFile) { 35 | this.outputWavFile = outputWavFile; 36 | } 37 | 38 | public File getOutputWavFile() { 39 | return outputWavFile; 40 | } 41 | 42 | public void setInputHexFile(File inputHexFile) { 43 | this.inputHexFile = inputHexFile; 44 | } 45 | 46 | public File getInputHexFile() { 47 | return inputHexFile; 48 | } 49 | 50 | public void setData(int data[]) { 51 | this.data = data; 52 | } 53 | 54 | public int[] getData() { 55 | return data; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /java_source/waveFile/ReadExample.java: -------------------------------------------------------------------------------- 1 | // source from http://www.labbookpages.co.uk/audio/javaWavFiles.html 2 | package waveFile; 3 | 4 | import java.io.*; 5 | 6 | public class ReadExample 7 | { 8 | public static void main(String[] args) 9 | { 10 | try 11 | { 12 | // Open the wav file specified as the first argument 13 | WavFile wavFile = WavFile.openWavFile(new File(args[0])); 14 | 15 | // Display information about the wav file 16 | wavFile.display(); 17 | 18 | // Get the number of audio channels in the wav file 19 | int numChannels = wavFile.getNumChannels(); 20 | 21 | // Create a buffer of 100 frames 22 | double[] buffer = new double[100 * numChannels]; 23 | 24 | int framesRead; 25 | double min = Double.MAX_VALUE; 26 | double max = Double.MIN_VALUE; 27 | 28 | do 29 | { 30 | // Read frames into buffer 31 | framesRead = wavFile.readFrames(buffer, 100); 32 | 33 | // Loop through frames and look for minimum and maximum value 34 | for (int s=0 ; s max) max = buffer[s]; 37 | if (buffer[s] < min) min = buffer[s]; 38 | } 39 | } 40 | while (framesRead != 0); 41 | 42 | // Close the wavFile 43 | wavFile.close(); 44 | 45 | // Output the minimum and maximum value 46 | System.out.printf("Min: %f, Max: %f\n", min, max); 47 | } 48 | catch (Exception e) 49 | { 50 | System.err.println(e); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /java_source/waveFile/WriteExample.java: -------------------------------------------------------------------------------- 1 | package waveFile; 2 | 3 | import java.io.*; 4 | 5 | public class WriteExample 6 | { 7 | public static void main(String[] args) 8 | { 9 | try 10 | { 11 | int sampleRate = 44100; // Samples per second 12 | double duration = 5.0; // Seconds 13 | 14 | // Calculate the number of frames required for specified duration 15 | long numFrames = (long)(duration * sampleRate); 16 | 17 | // Create a wav file with the name specified as the first argument 18 | WavFile wavFile = WavFile.newWavFile(new File("test.wav"), 2, numFrames, 16, sampleRate); 19 | 20 | // Create a buffer of 100 frames 21 | double[][] buffer = new double[2][100]; 22 | 23 | // Initialise a local frame counter 24 | long frameCounter = 0; 25 | 26 | // Loop until all frames written 27 | while (frameCounter < numFrames) 28 | { 29 | // Determine how many frames to write, up to a maximum of the buffer size 30 | long remaining = wavFile.getFramesRemaining(); 31 | int toWrite = (remaining > 100) ? 100 : (int) remaining; 32 | 33 | // Fill the buffer, one tone per channel 34 | for (int s=0 ; s>8)&0xFF; 67 | 68 | data[3]=totalLength&0xFF; 69 | data[4]=(totalLength>>8)&0xFF; 70 | 71 | data[5]=crc&0xFF; 72 | data[6]=(crc>>8)&0xFF; 73 | return data; 74 | } 75 | 76 | public void setFrameSize(int frameSize) { 77 | this.frameSize = frameSize; 78 | } 79 | 80 | public int getFrameSize() { 81 | return frameSize; 82 | } 83 | 84 | public void setCommand(int command) { 85 | this.command = command; 86 | } 87 | 88 | public int getCommand() { 89 | return command; 90 | } 91 | 92 | public void setPageIndex(int pageIndex) { 93 | this.pageIndex = pageIndex; 94 | } 95 | 96 | public int getPageIndex() { 97 | return pageIndex; 98 | } 99 | 100 | public void setTotalLength(int totalLength) { 101 | this.totalLength = totalLength; 102 | } 103 | 104 | public int getTotalLength() { 105 | return totalLength; 106 | } 107 | 108 | public void setCrc(int crc) { 109 | this.crc = crc; 110 | } 111 | 112 | public int getCrc() { 113 | return crc; 114 | } 115 | 116 | public void setPageStart(int pageStart) { 117 | this.pageStart = pageStart; 118 | } 119 | 120 | public int getPageStart() { 121 | return pageStart; 122 | } 123 | 124 | public void setPageSize(int pageSize) { 125 | this.pageSize = pageSize; 126 | } 127 | 128 | public int getPageSize() { 129 | return pageSize; 130 | } 131 | 132 | public void setSilenceBetweenPages(double silenceBetweenPages) { 133 | this.silenceBetweenPages = silenceBetweenPages; 134 | } 135 | 136 | public double getSilenceBetweenPages() { 137 | return silenceBetweenPages; 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /java_source/waveFile/AePlayWave.java: -------------------------------------------------------------------------------- 1 | package waveFile; 2 | 3 | // this class was found at 4 | // www.anyexample.com/programming/java/java_play_wav_sound_file.xml 5 | 6 | 7 | import java.io.File; 8 | import java.io.IOException; 9 | import javax.sound.sampled.AudioFormat; 10 | import javax.sound.sampled.AudioInputStream; 11 | import javax.sound.sampled.AudioSystem; 12 | import javax.sound.sampled.DataLine; 13 | import javax.sound.sampled.FloatControl; 14 | import javax.sound.sampled.LineUnavailableException; 15 | import javax.sound.sampled.SourceDataLine; 16 | import javax.sound.sampled.UnsupportedAudioFileException; 17 | 18 | public class AePlayWave extends Thread { 19 | 20 | private String filename; 21 | 22 | private Position curPosition; 23 | 24 | private final int EXTERNAL_BUFFER_SIZE = 524288; // 128Kb 25 | 26 | enum Position { 27 | LEFT, RIGHT, NORMAL 28 | }; 29 | 30 | public AePlayWave(String wavfile) { 31 | filename = wavfile; 32 | curPosition = Position.NORMAL; 33 | } 34 | 35 | public AePlayWave(String wavfile, Position p) { 36 | filename = wavfile; 37 | curPosition = p; 38 | } 39 | 40 | public void run() { 41 | 42 | File soundFile = new File(filename); 43 | if (!soundFile.exists()) { 44 | System.err.println("Wave file not found: " + filename); 45 | return; 46 | } 47 | 48 | AudioInputStream audioInputStream = null; 49 | try { 50 | audioInputStream = AudioSystem.getAudioInputStream(soundFile); 51 | } catch (UnsupportedAudioFileException e1) { 52 | e1.printStackTrace(); 53 | return; 54 | } catch (IOException e1) { 55 | e1.printStackTrace(); 56 | return; 57 | } 58 | 59 | AudioFormat format = audioInputStream.getFormat(); 60 | SourceDataLine auline = null; 61 | DataLine.Info info = new DataLine.Info(SourceDataLine.class, format); 62 | 63 | try { 64 | auline = (SourceDataLine) AudioSystem.getLine(info); 65 | auline.open(format); 66 | } catch (LineUnavailableException e) { 67 | e.printStackTrace(); 68 | return; 69 | } catch (Exception e) { 70 | e.printStackTrace(); 71 | return; 72 | } 73 | 74 | if (auline.isControlSupported(FloatControl.Type.PAN)) { 75 | FloatControl pan = (FloatControl) auline 76 | .getControl(FloatControl.Type.PAN); 77 | if (curPosition == Position.RIGHT) 78 | pan.setValue(1.0f); 79 | else if (curPosition == Position.LEFT) 80 | pan.setValue(-1.0f); 81 | } 82 | 83 | auline.start(); 84 | int nBytesRead = 0; 85 | byte[] abData = new byte[EXTERNAL_BUFFER_SIZE]; 86 | 87 | try { 88 | while (nBytesRead != -1) { 89 | nBytesRead = audioInputStream.read(abData, 0, abData.length); 90 | if (nBytesRead >= 0) 91 | auline.write(abData, 0, nBytesRead); 92 | } 93 | } catch (IOException e) { 94 | e.printStackTrace(); 95 | return; 96 | } finally { 97 | auline.drain(); 98 | auline.close(); 99 | } 100 | 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TinyAudioBoot 2 | Audio Bootloader for Attiny85 Microcontrollers 3 | 4 | ## What? 5 | 6 | You can simply program an Attiny85 via the audio output of a PC, Smartphone or audio-player. 7 | 8 |

9 | 10 |

11 | 12 | Only a low-part count circuit is needed. 13 | 14 | The bootloader presented here has the following features: 15 | 16 | - low memory footprint: ~1KB 17 | - [full Arduino IDE integration] (https://github.com/8BitMixtape/8Bit-Mixtape-NEO/wiki/3_3-IDE-integration) 18 | - automatic Baudrate detection and callibration 19 | - very simple circuit: two 10 k resistors and a 100 nF capacitor are needed to connect the microcontroller to the audio output 20 | of the PC or audio player 21 | - one pin for data transmission is needed 22 | - an optional led indicator, needs an extra pin, for the state of the boot loader 23 | - as hex/binary to wav converter, programmed in java, is also available. It works on win and linux 24 | 25 | ## Why? 26 | 27 | In some cases it is simpler to play an audio file to program a microcontroller than to install an IDE and dig up 28 | a programming dongle ! 29 | 30 | A good starting point for using this bootloader can be found here: [8bitmixedtape synthesizer](https://8bitmixtape.github.io/). A collection of ready-to-play files. 31 | 32 | ## How? 33 | 34 | ### installing the bootloader on the Attiny85 35 | 36 | Firtly, the bootloader must be flashed onto the microcontroller with an ISP programmer. 37 | You can use an [Arduino-Uno as ISP-pogrammer] (https://www.frag-duino.de/index.php/maker-faq/37-atmel-attiny-85-mit-arduino-arduinoisp-flashen-und-programmieren) 38 | 39 | There are precompiled HEX files (one file per configuration) e.g.: 40 | 41 | **AudioBootAttiny85_AudioPB4_LedPB1_V3_1.hex** 42 | 43 | AudioPB4 means: PB4 is the audio input pin 44 | LEDPB1 means: The LED signal is on PB1 45 | 46 | Some fuses have to be programmed too (for the ATTiny85): 47 | 48 | Extended: 0xFE 49 | HIGH: 0xDD 50 | LOW: 0xE1 51 | 52 | With these settings the ATTiny will run at 16Mhz 53 | 54 | If you are using avrdude this is the commandl ine to set the fuses (for a serial com called ttyACM0): 55 | > avrdude -P /dev/ttyACM0 -b 19200 -c avrisp -p t85 -U efuse:w:0xfe:m -U 56 | hfuse:w:0xdd:m -U lfuse:w:0xe1:m 57 | 58 | This is the command line to program the bootloader with audio input at PB3 and Led at PB1 (again for ttyACM0): 59 | > avrdude -v -pattiny85 -c avrisp -P/dev/ttyACM0 -b19200 60 | -Uflash:w:/home/dusjagr/Arduino/AttinySound-master/AudioBoot/AudioBootAttiny85_InputPB3_LEDPB1.hex:i 61 | 62 | 63 | ### bootloader operation 64 | 65 | 1. After reset the bootloader waits for about 5 seconds for a signal from the audio input. 66 | During this period the LED blinks at 1/2 Hz 67 | 68 | 2. If there was no signal, the bootloader starts the main program from flash 69 | 70 | 3. If there was a signal, the bootloader starts receiving the new program data an flashes it 71 | 72 | The sound volume has to be adjusted to a suitable value (some trial and error needed here). 73 | On most PCs the AudioBootloader should work with a **volume setting of 70%** . 74 | 75 | 76 | ## creating the WAV file 77 | 78 | ### Arduino IDE integration 79 | 80 | You could directly integrate the wav-file generator into your Arduino IDE to program your sketches: 81 | 82 | [full Arduino IDE integration] (https://github.com/8BitMixtape/8Bit-Mixtape-NEO/wiki/3_3-IDE-integration) 83 | 84 | ### HEX to WAV java Progam 85 | 86 | There is a java program in this repository to convert the hex files to wav files. 87 | 88 | **AudioBootAttiny85.jar** 89 | 90 | You can start by just clicking on it, if supported by your operating system or from the command line (see below). 91 | The wav-file is created and stored in the same directory where you started the java program. 92 | 93 | You can also use AudioBootAttiny85.jar directly from the command line without starting the GUI with the following command: 94 | 95 | > java -jar AudioBootAttiny85.jar someExampleFile.hex 96 | 97 | This might be useful if you want to integrate it in your own applications. 98 | 99 | ## interfacing the Attiny85 with the audio line 100 | 101 | You need two resistors and a capacitor as shown in the schematic below. 102 | You could also add a LED as status indicator for the bootloader. It allows to see if the bootloader has started and to quickly check if programming is underway due to the different blinking pattern. 103 | 104 |

105 | 106 |

107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /bootloaderbuild/Makefile: -------------------------------------------------------------------------------- 1 | # Name: Makefile 2 | # Project: USBaspLoader 3 | # Author: Christian Starkjohann 4 | # Creation Date: 2007-12-10 5 | # Tabsize: 4 6 | # Copyright: (c) 2007 by OBJECTIVE DEVELOPMENT Software GmbH 7 | # License: GNU GPL v2 (see License.txt) 8 | # This Revision: $Id: Makefile 798 2010-07-27 17:29:28Z cs $ 9 | 10 | 11 | ############################################################################### 12 | # Configure the following variables according to your AVR. 13 | # Program the device with 14 | # make fuse # to set the clock generator, boot section size etc. 15 | # make flash # to load the boot loader into flash 16 | # make lock # to protect the boot loader from overwriting 17 | # make disablereset # for ATtiny85 target - to use external reset line for IO (CAUTION: this is not easy to enable again, see README) 18 | 19 | F_CPU = 16500000 20 | 21 | ARDUINOAPPDIR = /Applications/Arduino.app 22 | AVRDIR = $(ARDUINOAPPDIR)/Contents/Java/hardware/tools/avr 23 | AVRBIN = $(AVRDIR)/bin 24 | AVRINCLUDE = $(ARDUINOAPPDIR)/Contents/Java/hardware/tools/avr/avr/include 25 | 26 | DEVICE = attiny85 27 | 28 | # hexadecimal address for bootloader section to begin. To calculate the best value: 29 | # - make clean; make main.hex; ### output will list data: 2124 (or something like that) 30 | # - for the size of your device (8kb = 1024 * 8 = 8192) subtract above value 2124... = 6068 31 | # - How many pages in is that? 6068 / 64 (tiny85 page size in bytes) = 94.8125 32 | # - round that down to 94 - our new bootloader address is 94 * 64 = 6016, in hex = 1780 33 | BOOTLOADER_ADDRESS = 0x1BC0 34 | 35 | LOCKOPT = -U lock:w:0x2f:m 36 | 37 | #PROGRAMMER contains AVRDUDE options to address your programmer 38 | PROGRAMMER = -c USBasp 39 | 40 | FUSEOPT_t85 = -U lfuse:w:0xe1:m -U hfuse:w:0xdd:m -U efuse:w:0xfe:m 41 | FUSEOPT_t85_DISABLERESET = -U lfuse:w:0xe1:m -U efuse:w:0xfe:m -U hfuse:w:0x5d:m 42 | 43 | FUSEOPT = $(FUSEOPT_t85) 44 | 45 | ARDUINO_BOARD_CORE = /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/cores/tiny 46 | ARDUINO_BOARD_PINS = /Users/xcorex/Library/Arduino15/packages/ATTinyCore/hardware/avr/1.0.6/variants/tinyX5 47 | ARDUINO_BOARD_INCLUDES = -I$(ARDUINO_BOARD_CORE) -I$(ARDUINO_BOARD_PINS) -I../TinyAudioBoot 48 | 49 | # Tools: 50 | AVRDUDE = $(AVRBIN)/avrdude $(PROGRAMMER) -p $(DEVICE) -C $(AVRDIR)/etc/avrdude.conf 51 | CC = $(AVRBIN)/avr-gcc 52 | CPP = $(AVRBIN)/avr-g++ 53 | AVROBJCOPY= $(AVRBIN)/avr-objcopy 54 | AVROBJDUMP= $(AVRBIN)/avr-objdump 55 | AVRSIZE= $(AVRBIN)/avr-size 56 | 57 | # Options: 58 | DEFINES = -DBOOTLOADER_ADDRESS=0x$(BOOTLOADER_ADDRESS) -DARDUINO=10801 -DARDUINO_AVR_COCOMAKE7 -DARDUINO_ARCH_AVR -DF_CPU=$(F_CPU) 59 | CPPFLAGS = -c -g -Os -w -std=gnu++11 -fno-exceptions -ffunction-sections -fdata-sections -fno-threadsafe-statics -MMD -I. -mmcu=$(DEVICE) $(DEFINES) $(ARDUINO_BOARD_INCLUDES) 60 | CFLAGS = -c -g -Os -w -std=gnu11 -ffunction-sections -fdata-sections -MMD -I. -mmcu=$(DEVICE) $(DEFINES) $(ARDUINO_BOARD_INCLUDES) 61 | LDFLAGS = -Wl,--relax,--gc-sections -Wl,--section-start=.text=$(BOOTLOADER_ADDRESS),-Map=main.map 62 | 63 | OBJECTS = main.o 64 | 65 | 66 | # symbolic targets: 67 | all: main.hex 68 | 69 | ## Compile c++ files 70 | 71 | %.o : %.ino 72 | $(CPP) $(CPPFLAGS) -x c++ -c $< -o $@ -Wa,-ahls=$<.lst 73 | 74 | .cpp.o: 75 | $(CPP) $(CPPFLAGS) -x c++ -c $< -o $@ -Wa,-ahls=$<.lst 76 | 77 | ## Compile c files 78 | .c.o: 79 | $(CC) $(CFLAGS) -c $< -o $@ -Wa,-ahls=$<.lst 80 | 81 | 82 | ## Compile S files 83 | .S.o: 84 | $(CC) $(CPPFLAGS) -c -g -x assembler-with-cpp $< -o $@ 85 | 86 | .c.s: 87 | @$(CC) $(CFLAGS) -S $< -o $@ 88 | 89 | .cpp.s: 90 | $(GCC) $(CPPFLAGS) -S $< -o $@ 91 | 92 | flash: all 93 | $(AVRDUDE) $(FUSEOPT) 94 | $(AVRDUDE) -Uflash:w:main.hex:i 95 | 96 | readflash: 97 | $(AVRDUDE) -U flash:r:read.hex:i 98 | 99 | fuse: 100 | $(AVRDUDE) $(FUSEOPT) 101 | 102 | disablereset: 103 | $(AVRDUDE) $(FUSEOPT_t85_DISABLERESET) 104 | 105 | lock: 106 | $(AVRDUDE) $(LOCKOPT) 107 | 108 | read_fuses: 109 | $(UISP) --rd_fuses 110 | 111 | clean: 112 | rm -f main.hex main.bin *.o main.s main.cpp.lst TinyAudioBoot.ino.lst main.map main.d TinyAudioBoot.d SendOnlySoftwareSerial.cpp.lst SendOnlySoftwareSerial.d 113 | 114 | # file targets: 115 | 116 | #link files 117 | main.bin: $(OBJECTS) 118 | $(CC) -w -Os -Wl,--gc-sections -mmcu=$(DEVICE) -o main.bin $(OBJECTS) $(LDFLAGS) 119 | 120 | main.hex: main.bin 121 | rm -f main.hex main.eep.hex 122 | $(AVROBJCOPY) -j .text -j .data -O ihex main.bin main.hex 123 | @echo Size of binary hexfile. Use the "data" size to calculate the bootloader address 124 | $(AVRSIZE) main.hex 125 | 126 | disasm: main.bin 127 | $(AVROBJDUMP) -d main.bin -------------------------------------------------------------------------------- /java_source/wavCreator/HexToSignal.java: -------------------------------------------------------------------------------- 1 | 2 | package wavCreator; 3 | 4 | public class HexToSignal 5 | { 6 | private int startSequencePulses = 40; 7 | private int numStartBits = 1; 8 | private int numStopBits = 1; 9 | private double manchesterPhase = 1; // current phase for differential manchester coding 10 | 11 | private boolean invertSignal = true; // correction of an inverted audio signal line 12 | // only used in non differential code 13 | 14 | private int lowNumberOfPulses = 2; // not for manchester coding, only for flankensignal 15 | private int highNumberOfPulses = 3; // not for manchester coding, only for flankensignal 16 | 17 | private int manchesterNumberOfSamplesPerBit = 4; // this value must be even 18 | private boolean useDifferentialManchsterCode = true; 19 | 20 | public void setSignalSpeed(boolean fullSpeedFlag) 21 | { 22 | if( fullSpeedFlag ) manchesterNumberOfSamplesPerBit = 4; // full speed 23 | else manchesterNumberOfSamplesPerBit = 8; // half speed 24 | } 25 | 26 | public HexToSignal(boolean fullSpeedFlag) 27 | { 28 | setSignalSpeed(fullSpeedFlag); 29 | } 30 | /* flag=true: rising edge 31 | * flag=false: falling edge 32 | */ 33 | private double[] manchesterEdge(boolean flag, int pointerIntoSignal, double signal[] ) 34 | { 35 | double sigpart[]=new double[manchesterNumberOfSamplesPerBit]; 36 | int n; 37 | double value; 38 | 39 | if( !useDifferentialManchsterCode ) // non differential manchester code 40 | { 41 | if(flag) value=1; 42 | else value=-1; 43 | if(invertSignal)value=value*-1; // correction of an inverted audio signal line 44 | for(n=0;n 25 | #include 26 | #include 27 | 28 | /*** 29 | EERef class. 30 | 31 | This object references an EEPROM cell. 32 | Its purpose is to mimic a typical byte of RAM, however its storage is the EEPROM. 33 | This class has an overhead of two bytes, similar to storing a pointer to an EEPROM cell. 34 | ***/ 35 | 36 | struct EERef{ 37 | 38 | EERef( const int index ) 39 | : index( index ) {} 40 | 41 | //Access/read members. 42 | uint8_t operator*() const { return eeprom_read_byte( (uint8_t*) index ); } 43 | operator const uint8_t() const { return **this; } 44 | 45 | //Assignment/write members. 46 | EERef &operator=( const EERef &ref ) { return *this = *ref; } 47 | EERef &operator=( uint8_t in ) { return eeprom_write_byte( (uint8_t*) index, in ), *this; } 48 | EERef &operator +=( uint8_t in ) { return *this = **this + in; } 49 | EERef &operator -=( uint8_t in ) { return *this = **this - in; } 50 | EERef &operator *=( uint8_t in ) { return *this = **this * in; } 51 | EERef &operator /=( uint8_t in ) { return *this = **this / in; } 52 | EERef &operator ^=( uint8_t in ) { return *this = **this ^ in; } 53 | EERef &operator %=( uint8_t in ) { return *this = **this % in; } 54 | EERef &operator &=( uint8_t in ) { return *this = **this & in; } 55 | EERef &operator |=( uint8_t in ) { return *this = **this | in; } 56 | EERef &operator <<=( uint8_t in ) { return *this = **this << in; } 57 | EERef &operator >>=( uint8_t in ) { return *this = **this >> in; } 58 | 59 | EERef &update( uint8_t in ) { return in != *this ? *this = in : *this; } 60 | 61 | /** Prefix increment/decrement **/ 62 | EERef& operator++() { return *this += 1; } 63 | EERef& operator--() { return *this -= 1; } 64 | 65 | /** Postfix increment/decrement **/ 66 | uint8_t operator++ (int){ 67 | uint8_t ret = **this; 68 | return ++(*this), ret; 69 | } 70 | 71 | uint8_t operator-- (int){ 72 | uint8_t ret = **this; 73 | return --(*this), ret; 74 | } 75 | 76 | int index; //Index of current EEPROM cell. 77 | }; 78 | 79 | /*** 80 | EEPtr class. 81 | 82 | This object is a bidirectional pointer to EEPROM cells represented by EERef objects. 83 | Just like a normal pointer type, this can be dereferenced and repositioned using 84 | increment/decrement operators. 85 | ***/ 86 | 87 | struct EEPtr{ 88 | 89 | EEPtr( const int index ) 90 | : index( index ) {} 91 | 92 | operator const int() const { return index; } 93 | EEPtr &operator=( int in ) { return index = in, *this; } 94 | 95 | //Iterator functionality. 96 | bool operator!=( const EEPtr &ptr ) { return index != ptr.index; } 97 | EERef operator*() { return index; } 98 | 99 | /** Prefix & Postfix increment/decrement **/ 100 | EEPtr& operator++() { return ++index, *this; } 101 | EEPtr& operator--() { return --index, *this; } 102 | EEPtr operator++ (int) { return index++; } 103 | EEPtr operator-- (int) { return index--; } 104 | 105 | int index; //Index of current EEPROM cell. 106 | }; 107 | 108 | /*** 109 | EEPROMClass class. 110 | 111 | This object represents the entire EEPROM space. 112 | It wraps the functionality of EEPtr and EERef into a basic interface. 113 | This class is also 100% backwards compatible with earlier Arduino core releases. 114 | ***/ 115 | 116 | struct EEPROMClass{ 117 | 118 | //Basic user access methods. 119 | EERef operator[]( const int idx ) { return idx; } 120 | uint8_t read( int idx ) { return EERef( idx ); } 121 | void write( int idx, uint8_t val ) { (EERef( idx )) = val; } 122 | void update( int idx, uint8_t val ) { EERef( idx ).update( val ); } 123 | 124 | //STL and C++11 iteration capability. 125 | EEPtr begin() { return 0x00; } 126 | EEPtr end() { return length(); } //Standards requires this to be the item after the last valid entry. The returned pointer is invalid. 127 | uint16_t length() { return E2END + 1; } 128 | 129 | //Functionality to 'get' and 'put' objects to and from EEPROM. 130 | template< typename T > T &get( int idx, T &t ){ 131 | EEPtr e = idx; 132 | uint8_t *ptr = (uint8_t*) &t; 133 | for( int count = sizeof(T) ; count ; --count, ++e ) *ptr++ = *e; 134 | return t; 135 | } 136 | 137 | template< typename T > const T &put( int idx, const T &t ){ 138 | EEPtr e = idx; 139 | const uint8_t *ptr = (const uint8_t*) &t; 140 | for( int count = sizeof(T) ; count ; --count, ++e ) (*e).update( *ptr++ ); 141 | return t; 142 | } 143 | }; 144 | 145 | static EEPROMClass EEPROM; 146 | #endif -------------------------------------------------------------------------------- /java_source/wavCreator/WavCodeGenerator.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | wave generator for audio bootloader 4 | 5 | waveform generation: building the audio signal 6 | 7 | (c) -C-H-R-I-S-T-O-P-H- -H-A-B-E-R-E-R- 2011 8 | 9 | This program is free software; you can redistribute it and/or modify 10 | it under the terms of the GNU General Public License as published by 11 | the Free Software Foundation; either version 2 of the License, or 12 | (at your option) any later version. 13 | */ 14 | package wavCreator; 15 | 16 | import hexTools.IntelHexFormat; 17 | 18 | import java.io.*; 19 | 20 | import waveFile.WavFile; 21 | 22 | public class WavCodeGenerator 23 | { 24 | private int sampleRate = 44100; // Samples per second 25 | private BootFrame frameSetup; 26 | boolean fullSpeedFlag=true; 27 | 28 | public WavCodeGenerator() 29 | { 30 | frameSetup = new BootFrame(); 31 | } 32 | 33 | private double[] appendSignal(double[] sig1, double[] sig2) 34 | { 35 | int l1=sig1.length; 36 | int l2=sig2.length; 37 | double[] d=new double[l1+l2]; 38 | for(int n=0;n0) 103 | { 104 | frameSetup.setPageIndex(pagePointer++); 105 | frameSetup.setTotalLength(data.length); 106 | 107 | int[] partSig=new int[pl]; 108 | 109 | for(int n=0;ndata.length-1) partSig[n]=0xFF; 112 | else partSig[n]=data[n+sigPointer]; 113 | 114 | } 115 | 116 | sigPointer+=pl; 117 | double[] sig=generatePageSignal(partSig); 118 | signal=appendSignal(signal,sig); 119 | 120 | signal=appendSignal(signal,silence(frameSetup.getSilenceBetweenPages())); 121 | 122 | total-=pl; 123 | } 124 | 125 | signal=appendSignal(signal,makeRunCommand()); // send mc "start the application" 126 | // added silence at sound end to time out sound fading in some wav players like from Mircosoft 127 | for(int k=0;k<10;k++) 128 | { 129 | signal=appendSignal(signal,silence(frameSetup.getSilenceBetweenPages())); 130 | } 131 | return signal; 132 | } 133 | 134 | public boolean saveWav(double[] signal, File fileName) 135 | { 136 | try 137 | { 138 | // Calculate the number of frames required for specified duration 139 | //long numFrames = (long)(duration * sampleRate); 140 | long numFrames=signal.length; 141 | // Create a wav file with the name specified as the first argument 142 | WavFile wavFile = WavFile.newWavFile(fileName, 2, numFrames, 16, sampleRate); 143 | 144 | // Create a buffer of 100 frames 145 | double[][] buffer = new double[2][100]; 146 | 147 | // Initialize a local frame counter 148 | long frameCounter = 0; 149 | 150 | // Loop until all frames written 151 | while (frameCounter < numFrames) 152 | { 153 | // Determine how many frames to write, up to a maximum of the buffer size 154 | long remaining = wavFile.getFramesRemaining(); 155 | int toWrite = (remaining > 100) ? 100 : (int) remaining; 156 | 157 | // Fill the buffer, one tone per channel 158 | for (int s=0 ; sMustafa Yuecel 49 | */ 50 | public class IntelHexFormat 51 | { 52 | /** enable debugMode */ 53 | private final static boolean debugMode = true; 54 | 55 | /** default maximum length of a block */ 56 | private final static int maxblocklen = Integer.MAX_VALUE; 57 | 58 | //--- Methods (public) 59 | 60 | /** 61 | * Convert IntelHex file to a formatted byte array 62 | * 63 | * @param fp a File instance 64 | * @return formatted byte array (ch? 0 length_high length_low 0 startaddress_high startaddress_low ) 65 | * @throws Exception 66 | */ 67 | public static byte[] IntelHexFormatToByteArray(File fp) throws Exception 68 | { 69 | return IntelHexFormatToByteArray(fp, maxblocklen); 70 | } 71 | public static int toUnsignedInt(byte value) 72 | { 73 | return (value & 0x7F) + (value < 0 ? 128 : 0); 74 | } 75 | public static int[] toUnsignedIntArray(byte value[]) 76 | { 77 | int[] erg=new int[value.length]; 78 | 79 | for(int n=0;n10000) laenge=10000; 96 | int spalten=16; 97 | int anfang=6; 98 | 99 | String s=""; 100 | 101 | z=0; 102 | for(n=0;n< laenge;n++) 103 | { 104 | 105 | if(z==spalten) 106 | { 107 | if(debugMode)System.out.printf(" %s",s); 108 | s=""; 109 | if(debugMode)System.out.println(); 110 | z=0; 111 | } 112 | if(z==0) 113 | { 114 | 115 | if(debugMode)System.out.printf("%04x: ",n); 116 | } 117 | if(debugMode)System.out.printf("%02x ",daten[anfang+n]); 118 | Character c=(char) daten[anfang+n]; 119 | 120 | if((c>32)&&(c<255)) s=s+c; 121 | else s=s+"."; 122 | z++; 123 | } 124 | 125 | } 126 | /** 127 | * Convert IntelHex file to a formatted byte array 128 | * 129 | * @param fp a File instance 130 | * @param maxblocklen maximum length of a block 131 | * @return formatted byte array 132 | * @throws Exception 133 | */ 134 | public static byte[] IntelHexFormatToByteArray(File fp, int maxblocklen) 135 | throws Exception 136 | { 137 | if (debugMode) 138 | System.out.println("Parse the Intel Hex File..."); 139 | 140 | // reserve enough space 141 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 142 | ByteArrayOutputStream datablock = new ByteArrayOutputStream(); 143 | 144 | BufferedReader in = new BufferedReader(new FileReader(fp)); 145 | 146 | String stringline = null; 147 | byte[] byteline; 148 | int data_length; 149 | int data_address; 150 | int block_length = 0; 151 | int block_address = -1; 152 | int block_address_offset = 0; 153 | 154 | for (;;) 155 | { 156 | stringline = in.readLine(); 157 | 158 | // EOF reached 159 | if ( stringline == null ) 160 | throw new Exception("No End Of File record in file"); 161 | 162 | // start code exists? 163 | if ( stringline.length() == 0 || stringline.charAt(0) != ':' ) 164 | continue; 165 | 166 | // is Data record? 167 | if ( !stringline.substring(7,9).equals("00") ) 168 | { 169 | if ( stringline.substring(7,9).equals("01") ) 170 | { 171 | // End Of File record 172 | 173 | // write datablock if necessary 174 | if ( block_length > 0) 175 | { 176 | // write header and datablock into baos 177 | writeHeader(baos, block_length, block_address); 178 | // write datablock into baos 179 | datablock.writeTo(baos); 180 | } 181 | 182 | break; 183 | } 184 | else if ( stringline.substring(7,9).equals("02") ) 185 | { 186 | // Extended Segment Address Records (HEX86) 187 | 188 | int len = new BigInteger(stringline.substring(1,3),16 189 | ).intValue(); 190 | block_address_offset = 191 | new BigInteger(stringline.substring(9,9+2*len),16 192 | ).intValue(); 193 | block_address_offset *= 16; // byte_shift 194 | if (debugMode) 195 | System.out.println("Extend address record. Offset: 0x" 196 | + Integer.toHexString(block_address_offset 197 | ).toUpperCase()); 198 | 199 | continue; 200 | } 201 | else 202 | // jump to the next line 203 | continue; 204 | } 205 | 206 | // convert hex-string w/o start code to byte array 207 | byteline = new BigInteger(stringline.substring(1),16 208 | ).toByteArray(); 209 | 210 | // checksum is correct? 211 | checkSum(byteline); 212 | 213 | data_length = new BigInteger(stringline.substring(1,3),16 214 | ).intValue(); 215 | data_address = new BigInteger(stringline.substring(3,7),16 216 | ).intValue(); 217 | 218 | if ( ( block_address + block_length != data_address + 219 | block_address_offset ) 220 | || ( block_length+data_length > maxblocklen ) ) 221 | { 222 | // write last block header? 223 | if (block_address != -1) 224 | { 225 | // write header into baos 226 | writeHeader(baos, block_length, block_address); 227 | // write datablock into baos 228 | datablock.writeTo(baos); 229 | } 230 | 231 | datablock.reset(); 232 | block_length = 0; 233 | block_address = data_address + block_address_offset; 234 | } 235 | 236 | // write data 237 | datablock.write(byteline,4,data_length); 238 | // update length 239 | block_length += data_length; 240 | } 241 | 242 | return baos.toByteArray(); 243 | } 244 | public static byte[] discardHeaderBytes(byte[] data) 245 | { 246 | int headerOffset=6; 247 | byte[] newData= new byte[data.length-headerOffset]; 248 | for(int n=0;n bytelen ) 275 | { 276 | // cut array 277 | baos.write(b,b.length-bytelen,bytelen); 278 | } 279 | else 280 | { 281 | // fill up with '\0' 282 | for (int i=0;iFile instance 294 | * @return true, if file is in IntelHex format 295 | */ 296 | public static boolean isIntelHexFormat(File fp) 297 | { 298 | BufferedReader in; 299 | String stringline; 300 | byte[] byteline; 301 | 302 | try 303 | { 304 | in = new BufferedReader(new FileReader(fp)); 305 | } 306 | catch (FileNotFoundException e) 307 | { 308 | return false; 309 | } 310 | 311 | for (;;) 312 | { 313 | try 314 | { 315 | stringline = in.readLine(); 316 | } 317 | catch (IOException e) 318 | { 319 | return false; 320 | } 321 | 322 | // EOF reached 323 | if ( stringline == null ) 324 | return false; 325 | // start code exists? 326 | if ( stringline.length() == 0 || stringline.charAt(0) != ':' ) 327 | continue; 328 | // convert hex-string w/o start code to byte array 329 | byteline = new BigInteger(stringline.substring(1),16 330 | ).toByteArray(); 331 | 332 | try 333 | { 334 | // checksum is correct? 335 | checkSum(byteline); 336 | } 337 | catch (Exception e) 338 | { 339 | return false; 340 | } 341 | 342 | if ( stringline.substring(7,9).equals("01") ) 343 | break; 344 | 345 | } 346 | 347 | return true; 348 | } 349 | 350 | //--- Methods (private) 351 | 352 | /** 353 | * Calculate checksum (modulo 256) 354 | * 355 | * @param b byte array 356 | * @throws Exception 357 | */ 358 | private static void checkSum(byte[] b) throws Exception 359 | { 360 | int checksum = 0; 361 | 362 | for (int i=0;ibaos 374 | * 375 | * @param baos write header into ByteArrayOutputStream 376 | * @param length length information to write into header 377 | * @param address address information to write into header 378 | * @throws Exception 379 | */ 380 | private static void writeHeader(ByteArrayOutputStream baos, int length, 381 | int address) throws Exception 382 | { 383 | // write header and datablock into baos 384 | if (debugMode) 385 | System.out.println("Write Header: Length: " + length + 386 | " (0x" + Integer.toHexString(length).toUpperCase() + 387 | ") Address: 0x" + 388 | Integer.toHexString(address).toUpperCase()); 389 | 390 | // write length 391 | baos.write(IntToFixedByteArray(length,3)); 392 | // write address 393 | baos.write(IntToFixedByteArray(address,3)); 394 | } 395 | public static void main(String[] args) { 396 | 397 | try { 398 | 399 | File f = new File("C:\\Dokumente und Einstellungen\\chris\\Eigene Dateien\\Entwicklung\\java\\EclipseWorkspace2\\wavBootLoader\\test.hex"); 400 | //File f = new File("C:\\Dokumente und Einstellungen\\chris\\Desktop\\AnalyserAsuroBoot\\small.hex"); 401 | 402 | byte[] erg = IntelHexFormatToByteArray(f); 403 | if(debugMode)System.out.println(erg); 404 | /* 405 | int ende=erg.length; 406 | 407 | for(int n=0;nConfigurationOptions->Processortype 35 | 2. Project->ConfigurationOptions->Programming Modell 'Os' 36 | 3. Project->ConfigurationOptions->CustomOptions->LinkerOptions->see further down 37 | 38 | There is an article how to make an ATTINY boot loader ( German ): 39 | http://www.mikrocontroller.net/articles/Konzept_f%C3%BCr_einen_ATtiny-Bootloader_in_C 40 | ( thanks to the author of the article, very well written ) 41 | 42 | 43 | Creating the bootloader with Atmel Studio 7 44 | =========================================== 45 | 46 | 1. You have to define the bootloader sections and reset vector location 47 | 48 | => Toolchain/AVR_GNU_Linker/Memory Settings 49 | .bootreset=0x00 50 | .text=0xE00 // for 1KB Bootloader 51 | .text=0x0C00 // for 2KB Bootloader 52 | 53 | explanation: 54 | .text=0x0E00 *2 = 0x1C00 ==> this is the start address of the boot loader with 1KB size 55 | .text=0x0C00 *2 = 0x1800 ==> this is the start address of the boot loader with 2KB size 56 | 57 | 2. Disable unused sections optimization in the linker 58 | Be sure that in the linker parameters this is not used: -Wl, --gc-sections 59 | disable the following check box: 60 | ==>Toolchain/AVR_GNU_C Compiler/Optimization/Garbage collect unused sections 61 | 62 | 63 | Fuse settings for the bootloader 64 | ================================ 65 | 66 | There fuses have to match certain conditions. 67 | Mainly SELFPROGEN has to be set, Brown-Out-Detection activated and 68 | CKDIV8 disabled to achieve the needed F_CPU of 8MHz 69 | 70 | FUSES Attiny 85 ( F_CPU 16MHz with PLL ) 71 | ======================================== 72 | Extended: 0xFE 73 | HIGH: 0xDD 74 | LOW: 0xE1 75 | 76 | ************************************************************************************ 77 | 78 | v0.1 19.6.2008 C. -H-A-B-E-R-E-R- Bootloader for IR-Interface 79 | v1.0 03.9.2011 C. -H-A-B-E-R-E-R- Bootloader for audio signal 80 | v1.1 05.9.2011 C. -H-A-B-E-R-E-R- changing pin setup, comments, and exitcounter=3 81 | v1.2 12.5.2012 C. -H-A-B-E-R-E-R- Atmega8 Support added, java program has to be adapted too 82 | v1.3 20.5.2012 C. -H-A-B-E-R-E-R- now interrupts of user program are working 83 | v1.4 05.6.2012 C. -H-A-B-E-R-E-R- signal coding changed to differential manchester code 84 | v2.0 13.6.2012 C. -H-A-B-E-R-E-R- setup for various MCs 85 | v3.0 30.1.2017 B. -P-r-a-k-o-s-a- first version of Attiny85 Audio Bootloader 86 | v3.1 04.2.2017 C. -H-A-B-E-R-E-R- clean reset vector added, description added, pins rerouted 87 | v3.2 18.7.2017 C. -P-r-a-k-o-s-a- various refactor, added eeprom write mode, makefile for compiling using arduino ide toolchain 88 | 89 | This program is free software; you can redistribute it and/or modify 90 | it under the terms of the GNU General Public License as published by 91 | the Free Software Foundation; either version 2 of the License, or 92 | (at your option) any later version. 93 | 94 | It is mandatory to keep the list of authors in this code. 95 | 96 | */ 97 | /* 98 | 99 | 100 | schematic for audio input 101 | ========================= 102 | 103 | VCC 104 | | 105 | | | 10K 106 | | | 107 | | 108 | | 109 | audio in >-----||-----o-------> soundprog ( digital input pin ) 110 | 100nF | 111 | | 112 | | | 10K 113 | | | 114 | | 115 | GND 116 | 117 | 118 | 119 | Pinout ATtiny25/45/85 120 | ===================== 121 | 122 | 123 | _______ 124 | | U | 125 | (PCINT5/RESET/ADC0/dW) PB5-| |- VCC 126 | (PCINT3/XTAL1/CLKI/OC1B/ADC3) PB3-| ATTINY|- PB2 (SCK/USCK/SCL/ADC1/T0/INT0/PCINT2) 127 | (PCINT4/XTAL2/CLKO/OC1B/ADC2) PB4-| 85 |- PB1 (MISO/DO/AIN1/OC0B/OC1A/PCINT1) 128 | GND-| |- PB0 (MOSI/DI/SDA/AIN0/OC0A/OC1A/AREF/PCINT0) 129 | |_______| 130 | 131 | 132 | 133 | Pinout ARDUINO 134 | ============== 135 | _______ 136 | | U | 137 | reset/PB5-| |- VCC 138 | D3/A3 PB3-| ATTINY|- PB2 D2/A1 139 | soundprog-> D4/A2 PB4-| 85 |- PB1 D1 -> ARDUINO_LED 140 | GND-| |- PB0 D0 141 | |_______| 142 | 143 | 144 | 145 | */ 146 | 147 | #include 148 | #include 149 | #include 150 | #include 151 | #include 152 | #include 153 | 154 | // This value has to be adapted to the bootloader size 155 | // If you change this, please change BOOTLOADER_ADDRESS on Makefile too 156 | 157 | #define BOOTLOADER_ADDRESS 0x1BC0 // bootloader start address, e.g. 0x1C00 = 7168, set .text to 0x0E00 158 | 159 | //#define BOOTLOADER_ADDRESS 0x1800 // bootloader start address, e.g. 0x1800 = 6144, set .text to 0x0c00 160 | 161 | #define RJMP (0xC000U - 1) // opcode of RJMP minus offset 1 162 | #define RESET_SECTION __attribute__((section(".bootreset"))) __attribute__((used)) 163 | 164 | // this variable seems to be unused 165 | // but in fact it is written into the flash section 166 | // you could find it in the *.hex file 167 | uint16_t resetVector RESET_SECTION = RJMP + BOOTLOADER_ADDRESS / 2; 168 | 169 | #ifdef DEBUGON 170 | 171 | #define DEBUGPIN ( 1< 260 | #ifndef RWWSRE // bug in AVR libc: 261 | #define RWWSRE CTPB // RWWSRE is not defined on ATTinys, use CTBP instead 262 | #endif 263 | 264 | void (*start_appl_main) (void); 265 | 266 | #define BOOTLOADER_FUNC_ADDRESS (BOOTLOADER_STARTADDRESS - sizeof (start_appl_main)) 267 | 268 | #define sei() asm volatile("sei") 269 | #define cli() asm volatile("cli") 270 | #define nop() asm volatile("nop") 271 | #define wdr() asm volatile("wdr") 272 | 273 | //AVR ATtiny85 Programming: EEPROM Reading and Writing - YouTube 274 | //https://www.youtube.com/watch?v=DO-D6YmRpJk 275 | 276 | void eeprom_write(unsigned short address, unsigned char data) 277 | { 278 | while(EECR & (1<= 8)time += t; // time accumulator for mean period calculation only the last 8 times are used 338 | } 339 | 340 | delayTime = time * 3 / 4 / 8; 341 | // delay 3/4 bit 342 | while (TIMER < delayTime); 343 | 344 | //p=1; 345 | 346 | //****************** wait for start bit *************************** 347 | while (p == PINVALUE) // while not startbit ( no change of pinValue means 0 bit ) 348 | { 349 | // wait for edge 350 | while (p == PINVALUE); 351 | p = PINVALUE; 352 | TIMER = 0; 353 | 354 | // delay 3/4 bit 355 | while (TIMER < delayTime); 356 | TIMER = 0; 357 | 358 | counter++; 359 | } 360 | p = PINVALUE; 361 | 362 | //**************************************************************** 363 | //receive data bits 364 | k = 8; 365 | for (n = 0; n < (FRAMESIZE * 8); n++) 366 | { 367 | // wait for edge 368 | while (p == PINVALUE); 369 | TIMER = 0; 370 | p = PINVALUE; 371 | 372 | // delay 3/4 bit 373 | while (TIMER < delayTime); 374 | 375 | t = PINVALUE; 376 | 377 | 378 | counter++; 379 | 380 | FrameData[dataPointer] = FrameData[dataPointer] << 1; 381 | if (p != t) FrameData[dataPointer] |= 1; 382 | p = t; 383 | k--; 384 | if (k == 0) { 385 | dataPointer++; 386 | k = 8; 387 | }; 388 | } 389 | //uint16_t crc = (uint16_t)FrameData[CRCLOW] + FrameData[CRCHIGH] * 256; 390 | 391 | 392 | return true; 393 | } 394 | 395 | /*----------------------------------------------------------------------------------------------------------------------- 396 | Flash: fill page word by word 397 | ----------------------------------------------------------------------------------------------------------------------- 398 | */ 399 | #define boot_program_page_fill(byteaddr, word) \ 400 | { \ 401 | uint8_t sreg; \ 402 | sreg = SREG; \ 403 | cli (); \ 404 | boot_page_fill ((uint32_t) (byteaddr), word); \ 405 | SREG = sreg; \ 406 | } 407 | 408 | /*----------------------------------------------------------------------------------------------------------------------- 409 | Flash: erase and write page 410 | ----------------------------------------------------------------------------------------------------------------------- 411 | */ 412 | #define boot_program_page_erase_write(pageaddr) \ 413 | { \ 414 | uint8_t sreg; \ 415 | eeprom_busy_wait (); \ 416 | sreg = SREG; \ 417 | cli (); \ 418 | boot_page_erase ((uint32_t) (pageaddr)); \ 419 | boot_spm_busy_wait (); \ 420 | boot_page_write ((uint32_t) (pageaddr)); \ 421 | boot_spm_busy_wait (); \ 422 | boot_rww_enable (); \ 423 | SREG = sreg; \ 424 | } 425 | 426 | 427 | /*----------------------------------------------------------------------------------------------------------------------- 428 | write a block into flash 429 | ----------------------------------------------------------------------------------------------------------------------- 430 | */ 431 | static void 432 | pgm_write_block (uint16_t flash_addr, uint16_t * block, size_t size) 433 | { 434 | uint16_t start_addr; 435 | uint16_t addr; 436 | uint16_t w; 437 | uint8_t idx = 0; 438 | 439 | start_addr = (flash_addr / SPM_PAGESIZE) * SPM_PAGESIZE; // round down (granularity is SPM_PAGESIZE) 440 | 441 | for (idx = 0; idx < SPM_PAGESIZE / 2; idx++) 442 | { 443 | addr = start_addr + 2 * idx; 444 | 445 | if (addr >= flash_addr && size > 0) 446 | { 447 | w = *block++; 448 | size -= sizeof (uint16_t); 449 | } 450 | else 451 | { 452 | w = pgm_read_word (addr); 453 | } 454 | 455 | boot_program_page_fill (addr, w); 456 | } 457 | 458 | boot_program_page_erase_write(start_addr); // erase and write the page 459 | } 460 | 461 | 462 | //*************************************************************************************** 463 | // void boot_program_page (uint32_t page, uint8_t *buf) 464 | // 465 | // Erase and flash one page. 466 | // 467 | // input: page address and data to be programmed 468 | // 469 | //*************************************************************************************** 470 | void boot_program_page (uint32_t page, uint8_t *buf) 471 | { 472 | uint16_t i; 473 | cli(); // disable interrupts 474 | 475 | boot_page_erase(page); 476 | boot_spm_busy_wait (); // Wait until the memory is erased. 477 | 478 | for (i = 0; i < SPM_PAGESIZE; i += 2) 479 | { 480 | //read received data 481 | uint16_t w = *buf++; //low section 482 | w += (*buf++) << 8; //high section 483 | //combine low and high to get 16 bit 484 | 485 | //first page and first index is vector table... ( page 0 and index 0 ) 486 | if (page == 0 && i == 0) 487 | { 488 | 489 | //1.save jump to application vector for later patching 490 | void* appl = (void *)(w - RJMP); 491 | start_appl_main = ((void (*)(void)) appl); 492 | 493 | //2.replace w with jump vector to bootloader 494 | w = 0xC000 + (BOOTLOADER_ADDRESS / 2) - 1; 495 | } 496 | // else if (page == LAST_PAGE && i == 60) 497 | // { 498 | //3.retrieve saved reset vector 499 | // w = saved_reset_vector; 500 | // } 501 | 502 | boot_page_fill (page + i, w); 503 | boot_spm_busy_wait(); // Wait until the memory is written. 504 | } 505 | 506 | boot_page_write (page); // Store buffer in flash page. 507 | boot_spm_busy_wait(); // Wait until the memory is written. 508 | } 509 | 510 | void resetRegister() 511 | { 512 | DDRB = 0; 513 | cli(); 514 | TCCR0B = 0; // turn off timer1 515 | } 516 | 517 | void exitBootloader() 518 | { 519 | memcpy_P (&start_appl_main, (PGM_P) BOOTLOADER_FUNC_ADDRESS, sizeof (start_appl_main)); 520 | 521 | if (start_appl_main) 522 | { 523 | resetRegister(); 524 | (*start_appl_main) (); 525 | } 526 | } 527 | 528 | void runProgramm(void) 529 | { 530 | // reintialize registers to default 531 | resetRegister(); 532 | 533 | pgm_write_block (BOOTLOADER_FUNC_ADDRESS, (uint16_t *) &start_appl_main, sizeof (start_appl_main)); 534 | 535 | start_appl_main(); 536 | } 537 | 538 | //*************************************************************************************** 539 | // main loop 540 | //*************************************************************************************** 541 | static inline void a_main() 542 | { 543 | uint8_t p; 544 | uint16_t time = WAITBLINKTIME; 545 | uint8_t timeout = BOOT_TIMEOUT; 546 | 547 | p = PINVALUE; 548 | 549 | //*************** wait for toggling input pin or timeout ****************************** 550 | uint8_t exitcounter = 3; 551 | while (1) 552 | { 553 | 554 | if (TIMER > 100) // timedelay ==> frequency @16MHz= 16MHz/8/100=20kHz 555 | { 556 | TIMER = 0; 557 | time--; 558 | if (time == 0) 559 | { 560 | TOGGLELED; 561 | 562 | time = WAITBLINKTIME; 563 | timeout--; 564 | if (timeout == 0) 565 | { 566 | LEDOFF; // timeout, 567 | // leave bootloader and run program 568 | exitBootloader(); 569 | } 570 | } 571 | } 572 | if (p != PINVALUE) 573 | { 574 | p = PINVALUE; 575 | exitcounter--; 576 | } 577 | if (exitcounter == 0) break; // signal received, leave this loop and go on 578 | } 579 | //*************** start command interpreter ************************************* 580 | LEDON; 581 | while (1) 582 | { 583 | if (!receiveFrame()) 584 | { 585 | //***** if data transfer error: blink fast, press reset to restart ******************* 586 | 587 | while (1) 588 | { 589 | if (TIMER > 100) // timerstop ==> frequency @16MHz= 16MHz/8/100=20kHz 590 | { 591 | TIMER = 0; 592 | time--; 593 | if (time == 0) 594 | { 595 | TOGGLELED; 596 | time = 1000; 597 | } 598 | } 599 | } 600 | } 601 | else // succeed 602 | { 603 | switch (FrameData[COMMAND]) 604 | { 605 | 606 | case PROGCOMMAND: 607 | { 608 | uint16_t pageNumber = (((uint16_t)FrameData[PAGEINDEXHIGH]) << 8) + FrameData[PAGEINDEXLOW]; 609 | uint16_t address=SPM_PAGESIZE * pageNumber; 610 | 611 | if( address < BOOTLOADER_ADDRESS) // prevent bootloader form self killing 612 | { 613 | boot_program_page (address, FrameData + DATAPAGESTART); // erase and program page 614 | TOGGLELED; 615 | } 616 | } 617 | break; 618 | 619 | case RUNCOMMAND: 620 | { 621 | // after programming leave bootloader and run program 622 | runProgramm(); 623 | } 624 | break; 625 | 626 | // case EXITCOMMAND: 627 | // { 628 | // // after programming leave bootloader and run program 629 | // exitBootloader(); 630 | // } 631 | // break; 632 | 633 | case EEPROMCOMMAND: 634 | { 635 | uint8_t pageNumber = FrameData[PAGEINDEXLOW]; 636 | uint8_t data_length = FrameData[LENGTHLOW]; 637 | uint8_t address = SPM_PAGESIZE * pageNumber; 638 | 639 | uint8_t *buf = FrameData + DATAPAGESTART; 640 | 641 | for (uint8_t i = 0; i < data_length; i++) 642 | { 643 | //write received data to EEPROM 644 | uint8_t w = *buf++; 645 | eeprom_write(address + i, w); 646 | } 647 | 648 | //Leave bootloader after eeprom signal received 649 | //todo: wait until all data sent > spm pagesize (64) 650 | //fix this!!!! 651 | LEDOFF; 652 | exitBootloader(); 653 | 654 | } 655 | break; 656 | } 657 | FrameData[COMMAND] = NOCOMMAND; // delete command 658 | } 659 | } 660 | } 661 | 662 | int main() 663 | { 664 | INITDEBUGPIN 665 | INITLED; 666 | INITAUDIOPORT; 667 | 668 | // Timer 2 normal mode, clk/8, count up from 0 to 255 669 | // ==> frequency @16MHz= 16MHz/8/256=7812.5Hz 670 | TCCR0B = _BV(CS01); 671 | 672 | a_main(); // start the main function 673 | } -------------------------------------------------------------------------------- /java_source/waveFile/WavFile.java: -------------------------------------------------------------------------------- 1 | // source from http://www.labbookpages.co.uk/audio/javaWavFiles.html 2 | package waveFile; 3 | 4 | // Wav file IO class 5 | // A.Greensted 6 | // http://www.labbookpages.co.uk 7 | 8 | // File format is based on the information from 9 | // http://www.sonicspot.com/guide/wavefiles.html 10 | // http://www.blitter.com/~russtopia/MIDI/~jglatt/tech/wave.htm 11 | 12 | // Version 1.0 13 | 14 | import java.io.*; 15 | 16 | public class WavFile 17 | { 18 | private enum IOState {READING, WRITING, CLOSED}; 19 | private final static int BUFFER_SIZE = 4096; 20 | 21 | private final static int FMT_CHUNK_ID = 0x20746D66; 22 | private final static int DATA_CHUNK_ID = 0x61746164; 23 | private final static int RIFF_CHUNK_ID = 0x46464952; 24 | private final static int RIFF_TYPE_ID = 0x45564157; 25 | 26 | private File file; // File that will be read from or written to 27 | private IOState ioState; // Specifies the IO State of the Wav File (used for snaity checking) 28 | private int bytesPerSample; // Number of bytes required to store a single sample 29 | private long numFrames; // Number of frames within the data section 30 | private FileOutputStream oStream; // Output stream used for writting data 31 | private FileInputStream iStream; // Input stream used for reading data 32 | private double floatScale; // Scaling factor used for int <-> float conversion 33 | private double floatOffset; // Offset factor used for int <-> float conversion 34 | private boolean wordAlignAdjust; // Specify if an extra byte at the end of the data chunk is required for word alignment 35 | 36 | // Wav Header 37 | private int numChannels; // 2 bytes unsigned, 0x0001 (1) to 0xFFFF (65,535) 38 | private long sampleRate; // 4 bytes unsigned, 0x00000001 (1) to 0xFFFFFFFF (4,294,967,295) 39 | // Although a java int is 4 bytes, it is signed, so need to use a long 40 | private int blockAlign; // 2 bytes unsigned, 0x0001 (1) to 0xFFFF (65,535) 41 | private int validBits; // 2 bytes unsigned, 0x0002 (2) to 0xFFFF (65,535) 42 | 43 | // Buffering 44 | private byte[] buffer; // Local buffer used for IO 45 | private int bufferPointer; // Points to the current position in local buffer 46 | private int bytesRead; // Bytes read after last read into local buffer 47 | private long frameCounter; // Current number of frames read or written 48 | 49 | // Cannot instantiate WavFile directly, must either use newWavFile() or openWavFile() 50 | private WavFile() 51 | { 52 | buffer = new byte[BUFFER_SIZE]; 53 | } 54 | 55 | public int getNumChannels() 56 | { 57 | return numChannels; 58 | } 59 | 60 | public long getNumFrames() 61 | { 62 | return numFrames; 63 | } 64 | 65 | public long getFramesRemaining() 66 | { 67 | return numFrames - frameCounter; 68 | } 69 | 70 | public long getSampleRate() 71 | { 72 | return sampleRate; 73 | } 74 | 75 | public int getValidBits() 76 | { 77 | return validBits; 78 | } 79 | 80 | public static WavFile newWavFile(File file, int numChannels, long numFrames, int validBits, long sampleRate) throws IOException, WavFileException 81 | { 82 | // Instantiate new Wavfile and initialise 83 | WavFile wavFile = new WavFile(); 84 | wavFile.file = file; 85 | wavFile.numChannels = numChannels; 86 | wavFile.numFrames = numFrames; 87 | wavFile.sampleRate = sampleRate; 88 | wavFile.bytesPerSample = (validBits + 7) / 8; 89 | wavFile.blockAlign = wavFile.bytesPerSample * numChannels; 90 | wavFile.validBits = validBits; 91 | 92 | // Sanity check arguments 93 | if (numChannels < 1 || numChannels > 65535) throw new WavFileException("Illegal number of channels, valid range 1 to 65536"); 94 | if (numFrames < 0) throw new WavFileException("Number of frames must be positive"); 95 | if (validBits < 2 || validBits > 65535) throw new WavFileException("Illegal number of valid bits, valid range 2 to 65536"); 96 | if (sampleRate < 0) throw new WavFileException("Sample rate must be positive"); 97 | 98 | // Create output stream for writing data 99 | wavFile.oStream = new FileOutputStream(file); 100 | 101 | // Calculate the chunk sizes 102 | long dataChunkSize = wavFile.blockAlign * numFrames; 103 | long mainChunkSize = 4 + // Riff Type 104 | 8 + // Format ID and size 105 | 16 + // Format data 106 | 8 + // Data ID and size 107 | dataChunkSize; 108 | 109 | // Chunks must be word aligned, so if odd number of audio data bytes 110 | // adjust the main chunk size 111 | if (dataChunkSize % 2 == 1) { 112 | mainChunkSize += 1; 113 | wavFile.wordAlignAdjust = true; 114 | } 115 | else { 116 | wavFile.wordAlignAdjust = false; 117 | } 118 | 119 | // Set the main chunk size 120 | putLE(RIFF_CHUNK_ID, wavFile.buffer, 0, 4); 121 | putLE(mainChunkSize, wavFile.buffer, 4, 4); 122 | putLE(RIFF_TYPE_ID, wavFile.buffer, 8, 4); 123 | 124 | // Write out the header 125 | wavFile.oStream.write(wavFile.buffer, 0, 12); 126 | 127 | // Put format data in buffer 128 | long averageBytesPerSecond = sampleRate * wavFile.blockAlign; 129 | 130 | putLE(FMT_CHUNK_ID, wavFile.buffer, 0, 4); // Chunk ID 131 | putLE(16, wavFile.buffer, 4, 4); // Chunk Data Size 132 | putLE(1, wavFile.buffer, 8, 2); // Compression Code (Uncompressed) 133 | putLE(numChannels, wavFile.buffer, 10, 2); // Number of channels 134 | putLE(sampleRate, wavFile.buffer, 12, 4); // Sample Rate 135 | putLE(averageBytesPerSecond, wavFile.buffer, 16, 4); // Average Bytes Per Second 136 | putLE(wavFile.blockAlign, wavFile.buffer, 20, 2); // Block Align 137 | putLE(validBits, wavFile.buffer, 22, 2); // Valid Bits 138 | 139 | // Write Format Chunk 140 | wavFile.oStream.write(wavFile.buffer, 0, 24); 141 | 142 | // Start Data Chunk 143 | putLE(DATA_CHUNK_ID, wavFile.buffer, 0, 4); // Chunk ID 144 | putLE(dataChunkSize, wavFile.buffer, 4, 4); // Chunk Data Size 145 | 146 | // Write Format Chunk 147 | wavFile.oStream.write(wavFile.buffer, 0, 8); 148 | 149 | // Calculate the scaling factor for converting to a normalised double 150 | if (wavFile.validBits > 8) 151 | { 152 | // If more than 8 validBits, data is signed 153 | // Conversion required multiplying by magnitude of max positive value 154 | wavFile.floatOffset = 0; 155 | wavFile.floatScale = Long.MAX_VALUE >> (64 - wavFile.validBits); 156 | } 157 | else 158 | { 159 | // Else if 8 or less validBits, data is unsigned 160 | // Conversion required dividing by max positive value 161 | wavFile.floatOffset = 1; 162 | wavFile.floatScale = 0.5 * ((1 << wavFile.validBits) - 1); 163 | } 164 | 165 | // Finally, set the IO State 166 | wavFile.bufferPointer = 0; 167 | wavFile.bytesRead = 0; 168 | wavFile.frameCounter = 0; 169 | wavFile.ioState = IOState.WRITING; 170 | 171 | return wavFile; 172 | } 173 | 174 | public static WavFile openWavFile(File file) throws IOException, WavFileException 175 | { 176 | // Instantiate new Wavfile and store the file reference 177 | WavFile wavFile = new WavFile(); 178 | wavFile.file = file; 179 | 180 | // Create a new file input stream for reading file data 181 | wavFile.iStream = new FileInputStream(file); 182 | 183 | // Read the first 12 bytes of the file 184 | int bytesRead = wavFile.iStream.read(wavFile.buffer, 0, 12); 185 | if (bytesRead != 12) throw new WavFileException("Not enough wav file bytes for header"); 186 | 187 | // Extract parts from the header 188 | long riffChunkID = getLE(wavFile.buffer, 0, 4); 189 | long chunkSize = getLE(wavFile.buffer, 4, 4); 190 | long riffTypeID = getLE(wavFile.buffer, 8, 4); 191 | 192 | // Check the header bytes contains the correct signature 193 | if (riffChunkID != RIFF_CHUNK_ID) throw new WavFileException("Invalid Wav Header data, incorrect riff chunk ID"); 194 | if (riffTypeID != RIFF_TYPE_ID) throw new WavFileException("Invalid Wav Header data, incorrect riff type ID"); 195 | 196 | // Check that the file size matches the number of bytes listed in header 197 | if (file.length() != chunkSize+8) { 198 | throw new WavFileException("Header chunk size (" + chunkSize + ") does not match file size (" + file.length() + ")"); 199 | } 200 | 201 | boolean foundFormat = false; 202 | boolean foundData = false; 203 | 204 | // Search for the Format and Data Chunks 205 | while (true) 206 | { 207 | // Read the first 8 bytes of the chunk (ID and chunk size) 208 | bytesRead = wavFile.iStream.read(wavFile.buffer, 0, 8); 209 | if (bytesRead == -1) throw new WavFileException("Reached end of file without finding format chunk"); 210 | if (bytesRead != 8) throw new WavFileException("Could not read chunk header"); 211 | 212 | // Extract the chunk ID and Size 213 | long chunkID = getLE(wavFile.buffer, 0, 4); 214 | chunkSize = getLE(wavFile.buffer, 4, 4); 215 | 216 | // Word align the chunk size 217 | // chunkSize specifies the number of bytes holding data. However, 218 | // the data should be word aligned (2 bytes) so we need to calculate 219 | // the actual number of bytes in the chunk 220 | long numChunkBytes = (chunkSize%2 == 1) ? chunkSize+1 : chunkSize; 221 | 222 | if (chunkID == FMT_CHUNK_ID) 223 | { 224 | // Flag that the format chunk has been found 225 | foundFormat = true; 226 | 227 | // Read in the header info 228 | bytesRead = wavFile.iStream.read(wavFile.buffer, 0, 16); 229 | 230 | // Check this is uncompressed data 231 | int compressionCode = (int) getLE(wavFile.buffer, 0, 2); 232 | if (compressionCode != 1) throw new WavFileException("Compression Code " + compressionCode + " not supported"); 233 | 234 | // Extract the format information 235 | wavFile.numChannels = (int) getLE(wavFile.buffer, 2, 2); 236 | wavFile.sampleRate = getLE(wavFile.buffer, 4, 4); 237 | wavFile.blockAlign = (int) getLE(wavFile.buffer, 12, 2); 238 | wavFile.validBits = (int) getLE(wavFile.buffer, 14, 2); 239 | 240 | if (wavFile.numChannels == 0) throw new WavFileException("Number of channels specified in header is equal to zero"); 241 | if (wavFile.blockAlign == 0) throw new WavFileException("Block Align specified in header is equal to zero"); 242 | if (wavFile.validBits < 2) throw new WavFileException("Valid Bits specified in header is less than 2"); 243 | if (wavFile.validBits > 64) throw new WavFileException("Valid Bits specified in header is greater than 64, this is greater than a long can hold"); 244 | 245 | // Calculate the number of bytes required to hold 1 sample 246 | wavFile.bytesPerSample = (wavFile.validBits + 7) / 8; 247 | if (wavFile.bytesPerSample * wavFile.numChannels != wavFile.blockAlign) 248 | throw new WavFileException("Block Align does not agree with bytes required for validBits and number of channels"); 249 | 250 | // Account for number of format bytes and then skip over 251 | // any extra format bytes 252 | numChunkBytes -= 16; 253 | if (numChunkBytes > 0) wavFile.iStream.skip(numChunkBytes); 254 | } 255 | else if (chunkID == DATA_CHUNK_ID) 256 | { 257 | // Check if we've found the format chunk, 258 | // If not, throw an exception as we need the format information 259 | // before we can read the data chunk 260 | if (foundFormat == false) throw new WavFileException("Data chunk found before Format chunk"); 261 | 262 | // Check that the chunkSize (wav data length) is a multiple of the 263 | // block align (bytes per frame) 264 | if (chunkSize % wavFile.blockAlign != 0) throw new WavFileException("Data Chunk size is not multiple of Block Align"); 265 | 266 | // Calculate the number of frames 267 | wavFile.numFrames = chunkSize / wavFile.blockAlign; 268 | 269 | // Flag that we've found the wave data chunk 270 | foundData = true; 271 | 272 | break; 273 | } 274 | else 275 | { 276 | // If an unknown chunk ID is found, just skip over the chunk data 277 | wavFile.iStream.skip(numChunkBytes); 278 | } 279 | } 280 | 281 | // Throw an exception if no data chunk has been found 282 | if (foundData == false) throw new WavFileException("Did not find a data chunk"); 283 | 284 | // Calculate the scaling factor for converting to a normalised double 285 | if (wavFile.validBits > 8) 286 | { 287 | // If more than 8 validBits, data is signed 288 | // Conversion required dividing by magnitude of max negative value 289 | wavFile.floatOffset = 0; 290 | wavFile.floatScale = 1 << (wavFile.validBits - 1); 291 | } 292 | else 293 | { 294 | // Else if 8 or less validBits, data is unsigned 295 | // Conversion required dividing by max positive value 296 | wavFile.floatOffset = -1; 297 | wavFile.floatScale = 0.5 * ((1 << wavFile.validBits) - 1); 298 | } 299 | 300 | wavFile.bufferPointer = 0; 301 | wavFile.bytesRead = 0; 302 | wavFile.frameCounter = 0; 303 | wavFile.ioState = IOState.READING; 304 | 305 | return wavFile; 306 | } 307 | 308 | // Get and Put little endian data from local buffer 309 | // ------------------------------------------------ 310 | private static long getLE(byte[] buffer, int pos, int numBytes) 311 | { 312 | numBytes --; 313 | pos += numBytes; 314 | 315 | long val = buffer[pos] & 0xFF; 316 | for (int b=0 ; b>= 8; 327 | pos ++; 328 | } 329 | } 330 | 331 | // Sample Writing and Reading 332 | // -------------------------- 333 | private void writeSample(long val) throws IOException 334 | { 335 | for (int b=0 ; b>= 8; 345 | bufferPointer ++; 346 | } 347 | } 348 | 349 | private long readSample() throws IOException, WavFileException 350 | { 351 | long val = 0; 352 | 353 | for (int b=0 ; b 0) oStream.write(buffer, 0, bufferPointer); 675 | 676 | // If an extra byte is required for word alignment, add it to the end 677 | if (wordAlignAdjust) oStream.write(0); 678 | 679 | // Close the stream and set to null 680 | oStream.close(); 681 | oStream = null; 682 | } 683 | 684 | // Flag that the stream is closed 685 | ioState = IOState.CLOSED; 686 | } 687 | 688 | public void display() 689 | { 690 | display(System.out); 691 | } 692 | 693 | public void display(PrintStream out) 694 | { 695 | out.printf("File: %s\n", file); 696 | out.printf("Channels: %d, Frames: %d\n", numChannels, numFrames); 697 | out.printf("IO State: %s\n", ioState); 698 | out.printf("Sample Rate: %d, Block Align: %d\n", sampleRate, blockAlign); 699 | out.printf("Valid Bits: %d, Bytes per sample: %d\n", validBits, bytesPerSample); 700 | } 701 | 702 | public static void main(String[] args) 703 | { 704 | if (args.length < 1) 705 | { 706 | System.err.println("Must supply filename"); 707 | System.exit(1); 708 | } 709 | 710 | try 711 | { 712 | for (String filename : args) 713 | { 714 | WavFile readWavFile = openWavFile(new File(filename)); 715 | readWavFile.display(); 716 | 717 | long numFrames = readWavFile.getNumFrames(); 718 | int numChannels = readWavFile.getNumChannels(); 719 | int validBits = readWavFile.getValidBits(); 720 | long sampleRate = readWavFile.getSampleRate(); 721 | 722 | WavFile writeWavFile = newWavFile(new File("out.wav"), numChannels, numFrames, validBits, sampleRate); 723 | 724 | final int BUF_SIZE = 5001; 725 | 726 | // int[] buffer = new int[BUF_SIZE * numChannels]; 727 | // long[] buffer = new long[BUF_SIZE * numChannels]; 728 | double[] buffer = new double[BUF_SIZE * numChannels]; 729 | 730 | int framesRead = 0; 731 | int framesWritten = 0; 732 | 733 | do 734 | { 735 | framesRead = readWavFile.readFrames(buffer, BUF_SIZE); 736 | framesWritten = writeWavFile.writeFrames(buffer, BUF_SIZE); 737 | System.out.printf("%d %d\n", framesRead, framesWritten); 738 | } 739 | while (framesRead != 0); 740 | 741 | readWavFile.close(); 742 | writeWavFile.close(); 743 | } 744 | 745 | WavFile writeWavFile = newWavFile(new File("out2.wav"), 1, 10, 23, 44100); 746 | double[] buffer = new double[10]; 747 | writeWavFile.writeFrames(buffer, 10); 748 | writeWavFile.close(); 749 | } 750 | catch (Exception e) 751 | { 752 | System.err.println(e); 753 | e.printStackTrace(); 754 | } 755 | } 756 | } 757 | --------------------------------------------------------------------------------