├── .gitignore ├── utils ├── concat.h └── multiply.h ├── microsound ├── instruments │ ├── harp.h │ ├── synthPiano.h │ ├── common │ │ ├── semirandom.h │ │ ├── expnegshort.h │ │ ├── commonWave.h │ │ ├── expneg.h │ │ └── sin.h │ ├── bassGuitar.h │ ├── overdrivenGuitar.h │ ├── harmonica.h │ ├── accordion.h │ ├── overdrivenGuitarChord.h │ ├── percussion.h │ ├── piano.h │ └── musicbox.h ├── devices │ ├── common │ │ └── skipSamples.h │ ├── attiny861timers01.h │ ├── atmega8timer2.h │ ├── atmega8timer1.h │ ├── atmega328Ptimer1.h │ ├── attiny85timers01.h │ ├── attiny26timers01.h │ └── atmega328Ptimer1out16bits.h ├── globalSoundInterpolation.h ├── wavechannel.h ├── declick.h ├── noisechannel.h ├── commands.h ├── delay.h ├── buffer.h ├── globalSoundInterpolationExperimental2.h ├── frequencies.h ├── micromusic.h ├── samples │ ├── notifications_four_channels.h │ ├── notifications_single_channel.h │ ├── oh_susanna.h │ └── for_elise.h └── microsound.h ├── LICENSE.md ├── demos ├── atmega328p │ ├── README.md │ ├── main.c │ └── Makefile ├── atmega8 │ ├── README.md │ ├── main.c │ └── Makefile ├── attiny26 │ ├── README.md │ ├── musicbox.h │ ├── Makefile │ └── main.c ├── attiny85 │ ├── README.md │ ├── main.c │ └── Makefile ├── attiny861 │ ├── README.md │ ├── main.c │ └── Makefile ├── arduino328p │ ├── README.md │ └── microsound.ino ├── atmega8lcd │ ├── README.md │ ├── Makefile │ └── main.c └── wavepot.js ├── buttons └── buttons.h ├── lcd └── lcd1602.h └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | *.elf 2 | *.hex 3 | *.asm 4 | -------------------------------------------------------------------------------- /utils/concat.h: -------------------------------------------------------------------------------- 1 | #ifndef CONCAT2 2 | #define CONCAT2_NX(A, B) A ## B 3 | #define CONCAT2(A, B) CONCAT2_NX(A, B) 4 | #endif 5 | 6 | #ifndef CONCAT3 7 | #define CONCAT3_NX(A, B, C) A ## B ## c 8 | #define CONCAT3(A, B, C) CONCAT3_NX(A, B, C) 9 | #endif 10 | -------------------------------------------------------------------------------- /microsound/instruments/harp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include "common/sin.h" 6 | #include "common/expnegshort.h" 7 | 8 | void playHarp(waveChannel* channel, uint8_t data) { 9 | setChannelWave(sinTable, data); 10 | setChannelVolume(expNegShortTable, 1); 11 | channel->currentVolume = channel->instrumentVolume; 12 | } 13 | -------------------------------------------------------------------------------- /microsound/instruments/synthPiano.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include "common/sin.h" 6 | #include "common/expneg.h" 7 | 8 | void playSynthPiano(waveChannel* channel, uint8_t data) { 9 | setChannelWave(sinTable, data); 10 | setChannelVolume(expNegTable, 2); 11 | channel->currentVolume = channel->instrumentVolume; 12 | } 13 | -------------------------------------------------------------------------------- /microsound/devices/common/skipSamples.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #if (MICROSOUND_FREQUENCY_DIVIDER > 1) && ((!defined INTERPOLATION_STRENGTH) || (INTERPOLATION_STRENGTH == 0)) 6 | static uint8_t microsampleSampleSkipCounter; 7 | if ((microsampleSampleSkipCounter++) & (MICROSOUND_FREQUENCY_DIVIDER - 1)) { 8 | return; 9 | } 10 | #endif 11 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Free for non-commercial usage. 2 | 3 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 4 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 5 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 6 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 7 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 8 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 9 | SOFTWARE. -------------------------------------------------------------------------------- /microsound/instruments/common/semirandom.h: -------------------------------------------------------------------------------- 1 | #ifndef SEMIRANDOM_DEFINED 2 | #define SEMIRANDOM_DEFINED 3 | 4 | /* 5 | * Fast semirandom values generator. Used for noise generation. 6 | * 7 | * Author: Aleksandr Maksymenko aka masyaman 8 | */ 9 | 10 | uint8_t semirandomA, semirandomB, semirandomC, semirandomValue; 11 | 12 | inline void nextSemirandom() { 13 | semirandomA++; 14 | semirandomB = semirandomB ^ semirandomValue ^ semirandomA; 15 | semirandomC = semirandomC + semirandomB; 16 | semirandomValue = semirandomValue + ((semirandomC >> 1) ^ semirandomB); 17 | } 18 | 19 | #endif 20 | -------------------------------------------------------------------------------- /microsound/instruments/common/expnegshort.h: -------------------------------------------------------------------------------- 1 | #ifndef EXP_NEG_SHORT_TABLE_DEFINED 2 | #define EXP_NEG_SHORT_TABLE_DEFINED 3 | 4 | /* 5 | * Table for e^(-x). 6 | * 7 | * Author: Aleksandr Maksymenko aka masyaman 8 | */ 9 | 10 | const uint8_t expNegShortTable[] PROGMEM = { 11 | 255, 233, 214, 196, 12 | 180, 165, 151, 139, 13 | 127, 116, 107, 98, 14 | 90, 82, 75, 69, 15 | 63, 58, 53, 49, 16 | 45, 41, 37, 34, 17 | 31, 29, 26, 24, 18 | 22, 20, 18, 17, 19 | 15, 14, 13, 12, 20 | 11, 10, 9, 8, 21 | 7, 7, 6, 6, 22 | 5, 5, 4, 4, 23 | 3, 3, 3, 3, 24 | 2, 2, 2, 2, 25 | 1, 1, 1, 1, 26 | 1, 1, 1, 0}; 27 | 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /demos/atmega328p/README.md: -------------------------------------------------------------------------------- 1 | # Microsound demo for ATmega328p 2 | 3 | Minimalistic example of using microsound on ATmega328p. 4 | 5 | # Characteristics 6 | 7 | - MCU: ATmega328p 8 | - CPU frequency: 8MHz 9 | - Sound quality: 8bits, 31250Hz 10 | - Output: PWM on pin PB1 11 | - Channels: 5 wavetable + 1 noise 12 | 13 | # Circuit 14 | 15 | ``` 16 | +5V 17 | ^ ATmega328p 18 | | +--------+ 19 | +---+VCC | R1 20 | | PB1+---/\/\--+-----> OUT 21 | | | | 22 | +---+GND | === C1 23 | | +--------+ | 24 | | | 25 | --- Grnd --- Grnd 26 | ``` 27 | 28 | # Build 29 | 30 | ``` 31 | make clean hex 32 | make program 33 | ``` 34 | -------------------------------------------------------------------------------- /demos/atmega8/README.md: -------------------------------------------------------------------------------- 1 | # Microsound demo for ATmega8 2 | 3 | Minimalistic example of using microsound on ATmega8. 4 | 5 | # Characteristics 6 | 7 | - MCU: ATmega8 / ATmega8a 8 | - CPU frequency: 8MHz 9 | - Sound quality: 8bits, 31250Hz 10 | - Output: PWM on pin PB1 11 | - Channels: 5 wavetable + 1 noise 12 | 13 | # Circuit 14 | 15 | ``` 16 | +5V 17 | ^ ATmega8 18 | | +--------+ 19 | +---+VCC | R1 20 | | PB1+---/\/\--+-----> OUT 21 | | | | 22 | +---+GND | === C1 23 | | +--------+ | 24 | | | 25 | --- Grnd --- Grnd 26 | ``` 27 | 28 | # Build 29 | 30 | ``` 31 | make clean hex 32 | make program 33 | ``` 34 | -------------------------------------------------------------------------------- /demos/attiny26/README.md: -------------------------------------------------------------------------------- 1 | # Microsound demo for ATtiny26 2 | 3 | Minimalistic example of using microsound on ATtiny26. 4 | 5 | # Characteristics 6 | 7 | - MCU: ATtiny26 8 | - CPU frequency: 16MHz 9 | - Sound quality: 8bits, 31250Hz 10 | - Output: PWM on pin PB3 11 | - Channels: 4 wavetable, no per-channel volume control 12 | 13 | # Circuit 14 | 15 | ``` 16 | +5V 17 | ^ ATtiny26 18 | | +--------+ 19 | +---+VCC | R1 20 | | PB3+---/\/\--+-----> OUT 21 | | | | 22 | +---+GND | === C1 23 | | +--------+ | 24 | | | 25 | --- Grnd --- Grnd 26 | ``` 27 | 28 | # Build 29 | 30 | ``` 31 | make clean hex 32 | make program 33 | ```PB3 34 | -------------------------------------------------------------------------------- /microsound/instruments/common/commonWave.h: -------------------------------------------------------------------------------- 1 | #ifndef setChannelWave 2 | 3 | #define setChannelWave(waveTable, note) \ 4 | channel->waveStep = pgm_read_word(&frequencies[note]); \ 5 | channel->waveForm = waveTable; \ 6 | channel->waveSample = 0; // Can be omit if declick is disabled 7 | 8 | 9 | #define setChannelVolumeWithLength(volumeTable, tableLength, ticksPerSample) \ 10 | channel->volumeForm = volumeTable; \ 11 | channel->volumeFormLength = tableLength; \ 12 | channel->volumeTicksPerSample = ticksPerSample; \ 13 | channel->volumeTicksCounter = ticksPerSample; 14 | 15 | #define setChannelVolume(volumeTable, ticksPerSample) \ 16 | setChannelVolumeWithLength(volumeTable, sizeof(volumeTable) - 1, ticksPerSample); 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /demos/attiny85/README.md: -------------------------------------------------------------------------------- 1 | # Microsound demo for ATtiny85 / ATtiny45 2 | 3 | Minimalistic example of using microsound on ATtiny85 / ATtiny45. 4 | 5 | # Characteristics 6 | 7 | - MCU: ATtiny85 / ATtiny45 8 | - CPU frequency: 16MHz 9 | - Sound quality: 8bits, 32000Hz 10 | - Output: PWM on pin PB4 11 | - Channels: 5 wavetable + 1 noise 12 | 13 | # Circuit 14 | 15 | ``` 16 | +5V 17 | ^ ATtiny85 18 | | +--------+ 19 | +---+VCC | R1 20 | | PB4+---/\/\--+-----> OUT 21 | | | | 22 | +---+GND | === C1 23 | | +--------+ | 24 | | | 25 | --- Grnd --- Grnd 26 | ``` 27 | 28 | # Build 29 | 30 | ``` 31 | make clean hex 32 | make program 33 | ``` 34 | To build and flash this demo for ATtiny45 it's required to change `DEVICE` in `Makefile` to `attiny45`. 35 | -------------------------------------------------------------------------------- /demos/attiny861/README.md: -------------------------------------------------------------------------------- 1 | # Microsound demo for ATtiny861 / ATtiny461 2 | 3 | Minimalistic example of using microsound on ATtiny861 / ATtiny461. 4 | 5 | # Characteristics 6 | 7 | - MCU: ATtiny861 / ATtiny461 8 | - CPU frequency: 16MHz 9 | - Sound quality: 8bits, 32000Hz 10 | - Output: PWM on pin PB3 11 | - Channels: 5 wavetable + 1 noise 12 | 13 | # Circuit 14 | 15 | ``` 16 | +5V 17 | ^ ATtiny861 18 | | +--------+ 19 | +---+VCC | R1 20 | | PB3+---/\/\--+-----> OUT 21 | | | | 22 | +---+GND | === C1 23 | | +--------+ | 24 | | | 25 | --- Grnd --- Grnd 26 | ``` 27 | 28 | # Build 29 | 30 | ``` 31 | make clean hex 32 | make program 33 | ``` 34 | To build and flash this demo for ATtiny461 it's required to change `DEVICE` in `Makefile` to `attiny461`. 35 | -------------------------------------------------------------------------------- /microsound/globalSoundInterpolation.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Takes care about sound interpolation. 3 | * This implementation provides simple linear interpolation. 4 | * 5 | * Value INTERPOLATION_STRENGTH means interpolation of (2^N-1) intermediate points. 6 | * 7 | * Author: Aleksandr Maksymenko aka masyaman 8 | */ 9 | 10 | #if INTERPOLATION_STRENGTH > 0 11 | 12 | // Linear interpolation 13 | uint8_t interpolationCounter; 14 | uint16_t interpolationValue; 15 | int16_t interpolationDiff; 16 | inline uint8_t getNextInterpolatedSample() { 17 | interpolationCounter = (interpolationCounter + 1) & ((1 << INTERPOLATION_STRENGTH) - 1); 18 | if (!interpolationCounter) { 19 | uint16_t next = sampleToUint16(readFromBuffer()); 20 | interpolationDiff = ((int16_t)(next - interpolationValue)) >> INTERPOLATION_STRENGTH; 21 | } 22 | interpolationValue += interpolationDiff; 23 | return toSample(interpolationValue); 24 | } 25 | 26 | #else 27 | 28 | #define getNextInterpolatedSample readFromBuffer 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /microsound/wavechannel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Wave channel. 3 | * Generates wave of specific form with specific volume changed over time. 4 | * 5 | * Author: Aleksandr Maksymenko aka masyaman 6 | */ 7 | 8 | #include "../utils/concat.h" 9 | 10 | // functions 11 | #define channelData CONCAT2(CHANNEL_ID, ChannelData) 12 | #define nextSample CONCAT2(CHANNEL_ID, NextSample) 13 | 14 | #ifndef INLINE_WAVETABLE_SOUND_GENERATOR 15 | #define INLINE_WAVETABLE_SOUND_GENERATOR inline /* inline by default */ 16 | #endif 17 | 18 | waveChannel channelData; 19 | 20 | INLINE_WAVETABLE_SOUND_GENERATOR 21 | int16_t nextSample() { 22 | // Get wave 23 | uint16_t sample = channelData.waveSample; 24 | uint8_t sampleId = ((uint8_t)(sample >> 8)) & SAMPLE_MASK; 25 | int8_t tone = pgm_read_byte(&channelData.waveForm[sampleId]); 26 | #ifdef INTERPOLATE_WAVE 27 | uint8_t subsampleTone = sample; 28 | tone += (( (int8_t) pgm_read_byte(&channelData.waveForm[(uint8_t)(sampleId + 1)]) - tone) * subsampleTone) >> 8; 29 | #endif 30 | channelData.waveSample += channelData.waveStep; 31 | 32 | return mulSignedUnsigned(tone, channelData.currentVolume); 33 | } 34 | 35 | 36 | // undef functions 37 | #undef channelData 38 | #undef nextSample 39 | 40 | #undef CHANNEL_ID 41 | -------------------------------------------------------------------------------- /buttons/buttons.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Library for controlling up to 8 buttons on a single port. 3 | * 4 | * Author: Aleksandr Maksymenko aka masyaman 5 | */ 6 | 7 | #define BUTTONS_DDR_REGISTER CONCAT2(DDR, BUTTONS_PORT) 8 | #define BUTTONS_PIN_REGISTER CONCAT2(PIN, BUTTONS_PORT) 9 | #define BUTTONS_PORT_REGISTER CONCAT2(PORT, BUTTONS_PORT) 10 | 11 | #ifndef BUTTONS_MASK 12 | #define BUTTONS_MASK 0xFF 13 | #endif 14 | 15 | uint8_t buttonsPreviousState; 16 | uint8_t buttonsClicked; 17 | 18 | #define isButtonPressed(mask) (!(BUTTONS_PIN_REGISTER & (mask))) 19 | 20 | inline void initButtons() { 21 | BUTTONS_DDR_REGISTER &= ~BUTTONS_MASK; 22 | BUTTONS_PORT_REGISTER |= BUTTONS_MASK; 23 | buttonsPreviousState = BUTTONS_PIN_REGISTER; 24 | buttonsClicked = 0; 25 | } 26 | 27 | 28 | inline void updateButtons() { 29 | // TODO skip in case of short delay 30 | 31 | uint8_t buttonsCurrentState = BUTTONS_PIN_REGISTER; 32 | buttonsClicked |= (~buttonsCurrentState) & buttonsPreviousState; 33 | buttonsPreviousState = buttonsCurrentState; 34 | } 35 | 36 | uint8_t isButtonClicked(uint8_t buttonMask) { 37 | updateButtons(); 38 | 39 | uint8_t clicked = buttonsClicked & buttonMask; 40 | buttonsClicked &= ~buttonMask; 41 | return clicked; 42 | } 43 | 44 | 45 | -------------------------------------------------------------------------------- /microsound/devices/attiny861timers01.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 8 bits PWM driver for ATtiny261/461/861. 3 | * 4 | * It uses timer1 for high frequency PWM and timer0 for overflow interrupt. 5 | * 6 | * This implementation supports custom sample rates. Interrupt frequency will be 7 | * calculated according to MICROSOUND_FREQUENCY. 8 | * 9 | * Output pin is PB3. 10 | * 11 | * Author: Aleksandr Maksymenko aka masyaman 12 | */ 13 | 14 | #include "../microsound.h" 15 | 16 | #include "../globalSoundInterpolation.h" 17 | 18 | inline void initSound() { 19 | 20 | // Enable PLL for timer 1 21 | PLLCSR = (1 << PLLE); 22 | while (!(PLLCSR & (1< OUT 23 | | | | 24 | | | R2 | 25 | | PB2/D10+---/\/\--+ 26 | | | | 27 | +---+GND | === C1 28 | | +--------+ | 29 | | | 30 | --- Grnd --- Grnd 31 | ``` 32 | 33 | Example uses 2 output pins. 34 | Pin PB1/D9 corresponds to higher byte of 16bits output. 35 | Pin PB2/D10 corresponds to lower byte of 16bits output. 36 | Outputs should be mixed in this proportion: R2 = 256 * R1. 37 | 38 | Resistor R2 can be omit. In this case output will be 8bits. 39 | If 8bits mode is used then it's recommended to use 8bits driver `atmega328Ptimer1.h` to free up pin PB2/D10 and some CPU and memory resources. 40 | 41 | # Build 42 | 43 | 1. Copy `microsound.ino` to the root of microsound library. 44 | 2. Open sketch in Arduino IDE. 45 | 3. Upload to Arduino. 46 | 47 | Sketch was tested on a clone of Arduino Nano. It may not work on other clones. -------------------------------------------------------------------------------- /microsound/declick.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Experimental piece of code which eliminates clicks when playing of wave sample is interrupted by new note. 3 | * 4 | * Author: Aleksandr Maksymenko aka masyaman 5 | */ 6 | 7 | #ifdef ENABLE_DECLICK 8 | 9 | uint8_t currentZeroSampleValue; 10 | 11 | inline uint16_t getZeroSample() { 12 | return currentZeroSampleValue << 8; 13 | } 14 | 15 | inline void addToZeroSampleValue(int16_t value) { 16 | currentZeroSampleValue += (value >> 8); 17 | } 18 | 19 | inline void addChannelToZeroSample(waveChannel* channelData) { 20 | // Get wave 21 | uint16_t sample = channelData->waveSample; 22 | uint8_t sampleId = ((uint8_t)(sample >> 8)) & SAMPLE_MASK; 23 | int8_t tone = pgm_read_byte(&channelData->waveForm[sampleId]); 24 | 25 | addToZeroSampleValue(mulSignedUnsigned(tone, channelData->currentVolume)); 26 | } 27 | 28 | 29 | inline void moveToZeroSampleValue() { 30 | if (currentZeroSampleValue > 0x80) { 31 | currentZeroSampleValue--; 32 | } else if (currentZeroSampleValue < 0x80) { 33 | currentZeroSampleValue++; 34 | } 35 | 36 | //#define DECLICK_STRENGTH 8 37 | // if (currentZeroSampleValue > 0x80 + DECLICK_STRENGTH - 1) { 38 | // currentZeroSampleValue -= DECLICK_STRENGTH; 39 | // } else if (currentZeroSampleValue < 0x80 - DECLICK_STRENGTH + 1) { 40 | // currentZeroSampleValue += DECLICK_STRENGTH; 41 | // } 42 | } 43 | 44 | #else 45 | 46 | #define getZeroSample() 0x8000 47 | //#define addToZeroSampleValue(value) 48 | #define addChannelToZeroSample(channelData) 49 | #define moveToZeroSampleValue() 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /microsound/instruments/bassGuitar.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include "common/expneg.h" 6 | 7 | const int8_t bassGuitarWaveTable[] PROGMEM = { 8 | 4, 19, 33, 47, 60, 72, 83, 92, 101, 108, 114, 119, 122, 125, 126, 127, 9 | 126, 125, 123, 120, 116, 112, 108, 103, 98, 92, 87, 81, 75, 70, 64, 59, 10 | 54, 49, 44, 40, 36, 32, 29, 25, 23, 20, 18, 16, 14, 13, 11, 10, 11 | 8, 7, 6, 5, 3, 2, 1, 0, -1, -2, -4, -5, -6, -7, -9, -10, 12 | -11, -11, -12, -13, -13, -13, -13, -14, -14, -13, -13, -13, -12, -12, -12, -11, 13 | -11, -10, -9, -9, -8, -8, -7, -6, -5, -4, -4, -3, -2, -1, 0, 0, 14 | 0, 1, 2, 2, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 15 | 4, 3, 3, 2, 1, 1, 0, 0, -1, -2, -3, -4, -4, -5, -6, -6, 16 | -7, -7, -7, -7, -7, -7, -7, -6, -6, -6, -5, -5, -4, -4, -3, -3, 17 | -2, -2, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18 | 0, 0, 0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -3, -3, -3, -3, 19 | -3, -3, -3, -3, -3, -2, -2, -2, -1, -1, -1, 0, 0, 0, -1, -1, 20 | -2, -3, -4, -5, -7, -8, -10, -12, -14, -16, -18, -20, -21, -23, -24, -25, 21 | -26, -26, -26, -26, -25, -24, -23, -22, -20, -19, -17, -16, -16, -16, -17, -18, 22 | -20, -23, -27, -31, -36, -42, -49, -56, -63, -70, -78, -85, -92, -98, -104, -108, 23 | -112, -115, -116, -116, -115, -113, -109, -103, -96, -88, -78, -67, -55, -41, -26, -11 24 | }; 25 | 26 | void playBassGuitar(waveChannel* channel, uint8_t data) { 27 | setChannelWave(bassGuitarWaveTable, data); 28 | setChannelVolume(expNegTable, 4); 29 | channel->currentVolume = channel->instrumentVolume; 30 | } 31 | -------------------------------------------------------------------------------- /microsound/devices/attiny26timers01.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 8 bits PWM driver for ATtiny26. 3 | * 4 | * It uses timer1 for high frequency PWM and timer0 for overflow interrupt. 5 | * 6 | * Sample rate is F_CPU / 256 which is equal to 31250 Hz for 8MHz clock or 62500 Hz for 16MHz clock. 7 | * Sample rate can be lowered by 2, 4 or 8 by using MICROSOUND_FREQUENCY_DIVIDER. 8 | * Lowered sample rate can be extrapolated back to it's original frequency using 9 | * INTERPOLATION_STRENGTH values 1, 2 or 3 accordingly. 10 | * 11 | * This implementation does not support custom sample rates. 12 | * 13 | * Output pin is PB3. 14 | * 15 | * Author: Aleksandr Maksymenko aka masyaman 16 | */ 17 | 18 | #ifndef MICROSOUND_FREQUENCY_DIVIDER 19 | #define MICROSOUND_FREQUENCY_DIVIDER 1 // 2^n 20 | #endif 21 | 22 | #include "../microsound.h" 23 | 24 | #include "../globalSoundInterpolation.h" 25 | 26 | inline void initSound() { 27 | 28 | // Enable PLL for timer 1 29 | PLLCSR = (1 << PLLE); 30 | while (!(PLLCSR & (1<waveStep = pgm_read_word(&frequencies[data]) << 1; // transpose 1 octave up 37 | channel->waveForm = musicboxWaveTable; 38 | 39 | channel->volumeForm = musicboxVolumeTable; 40 | channel->volumeFormLength = 72 - 1; 41 | channel->volumeTicksPerSample = 4; 42 | channel->volumeTicksCounter = 4; 43 | 44 | channel->currentVolume = channel->instrumentVolume; 45 | } 46 | -------------------------------------------------------------------------------- /demos/atmega8lcd/README.md: -------------------------------------------------------------------------------- 1 | # Microsound demo for ATmega8 2 | 3 | Example project with usage microsound on ATmega8. 4 | 5 | This project shows how 16x2 characters LCD display can be used simultaneously with 6 | playing sound. 7 | Some buttons are used to play samples. 8 | 9 | # Characteristics 10 | 11 | - MCU: ATmega8 / ATmega8a 12 | - CPU frequency: 8MHz 13 | - Sound quality: 8bits, 31250Hz 14 | - Output: PWM on pin PB1 15 | - Channels: 5 wavetable + 1 noise 16 | 17 | # Circuit 18 | 19 | ``` 20 | +5V 21 | ^ ATmega8 22 | | +---------+ 23 | +---+VCC | 24 | Buttons | PD0+-----> to LCD D4 25 | _ | PD1+-----> to LCD D5 26 | +-----_`---------+PC0 PD2+-----> to LCD D6 27 | +-----_`---------+PC1 PD3+-----> to LCD D7 28 | +-----_`---------+PC2 PD5+-----> to LCD RS 29 | +-----_`---------+PC3 PD6+-----> to LCD E 30 | +-----_`---------+PC4 | 31 | +----- `---------+PC5 | R1 32 | | | PB1+---/\/\--+-----> OUT 33 | | +---+GND | | 34 | | | +---------+ === C1 35 | | | | 36 | --- Grnd --- Grnd --- Grnd 37 | ``` 38 | 39 | MCU pinout: 40 | * PC0-PC5: buttons 41 | * PD0-PD3, PD5-PD6: LCD display 42 | * PB1: PWM output 43 | 44 | LCD display pinout: 45 | * VSS: Grnd 46 | * VDD: +5V 47 | * VO: to variable resistor for contrast adjustment 48 | * RS: PD5 49 | * RW: Grnd 50 | * E: PD6 51 | * D4-D7: PD0-PD3 52 | * A: +5V via resistor 53 | * K: Grnd 54 | 55 | 56 | # Build 57 | 58 | ``` 59 | make clean hex 60 | make program 61 | ``` 62 | -------------------------------------------------------------------------------- /microsound/devices/atmega328Ptimer1out16bits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 16 bits PWM driver for ATmega48/88/168/328p. 3 | * It uses two PWM output pins which should be mixed in proportion 1/256. 4 | * 5 | * It uses timer1 both for PWM and overflow interrupt. 6 | * 7 | * Sample rate is F_CPU / 256 which is equal to 31250 Hz for 8MHz clock or 62500 Hz for 16MHz clock. 8 | * Sample rate can be lowered by 2, 4 or 8 by using MICROSOUND_FREQUENCY_DIVIDER. 9 | * Lowered sample rate can be extrapolated back to it's original frequency using 10 | * INTERPOLATION_STRENGTH values 1, 2 or 3 accordingly. 11 | * 12 | * This implementation does not support custom sample rates. 13 | * 14 | * Output pins are PB1 (high), PB2 (low). 15 | * Resistor connected to PB2 should have 256 times higher resistance comparing to resistor connected to PB1. 16 | * 17 | * Author: Aleksandr Maksymenko aka masyaman 18 | */ 19 | 20 | #ifndef BUFFER_BITS 21 | #define BUFFER_BITS 16 22 | #endif 23 | 24 | #ifndef MICROSOUND_FREQUENCY_DIVIDER 25 | #define MICROSOUND_FREQUENCY_DIVIDER 1 // 2^n 26 | #endif 27 | 28 | #include "../microsound.h" 29 | 30 | #include "../globalSoundInterpolation.h" 31 | 32 | inline void initSound() { 33 | // Enable timer overflow interrupt 34 | TIMSK1 |= (1<> 8; 51 | OCR1BL = output & 0xFF; 52 | } 53 | -------------------------------------------------------------------------------- /microsound/instruments/overdrivenGuitar.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include "common/expneg.h" 6 | 7 | const int8_t overdrivenGuitarWaveTable[] PROGMEM = { 8 | 0, 3, 6, 6, 3, -2, -14, -29, -43, -55, -64, -69, -69, -65, -59, -52, 9 | -45, -41, -38, -39, -42, -48, -55, -63, -70, -75, -77, -78, -77, -75, -71, -68, 10 | -66, -65, -66, -68, -71, -75, -79, -83, -86, -88, -89, -89, -88, -86, -85, -84, 11 | -84, -84, -85, -87, -89, -92, -94, -96, -97, -98, -98, -97, -97, -96, -96, -96, 12 | -96, -97, -98, -99, -98, -95, -90, -82, -73, -65, -58, -53, -52, -54, -57, -62, 13 | -68, -73, -76, -78, -78, -76, -72, -68, -64, -60, -58, -57, -57, -59, -62, -64, 14 | -67, -69, -69, -69, -68, -66, -64, -62, -60, -58, -57, -57, -56, -54, -50, -43, 15 | -35, -26, -18, -12, -10, -9, -11, -14, -19, -23, -26, -28, -28, -26, -23, -19, 16 | -15, -11, -8, -6, -4, -4, -4, -3, -3, -1, 0, 4, 7, 11, 15, 19, 17 | 21, 22, 32, 39, 44, 45, 44, 40, 35, 30, 26, 24, 24, 26, 30, 35, 18 | 40, 45, 50, 54, 58, 65, 73, 81, 89, 94, 97, 99, 98, 96, 94, 91, 19 | 89, 89, 90, 92, 95, 99, 103, 107, 110, 112, 113, 113, 113, 112, 111, 111, 20 | 111, 111, 113, 115, 117, 120, 122, 124, 125, 126, 127, 125, 122, 116, 107, 96, 21 | 87, 80, 76, 76, 79, 84, 91, 98, 103, 107, 108, 107, 100, 90, 76, 60, 22 | 47, 38, 33, 32, 36, 44, 52, 61, 68, 72, 73, 70, 65, 58, 51, 44, 23 | 39, 36, 35, 36, 37, 36, 32, 25, 16, 8, 1, -3, -6, -7, -5, -2 24 | }; 25 | 26 | void playOverdrivenGuitar(waveChannel* channel, uint8_t data) { 27 | setChannelWave(overdrivenGuitarWaveTable, (data & 0b00111111)); 28 | setChannelVolume(expNegTable, 8); 29 | channel->currentVolume = channel->instrumentVolume; 30 | 31 | } 32 | -------------------------------------------------------------------------------- /microsound/instruments/harmonica.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | const int8_t harmonicaWaveTable[] PROGMEM = { 6 | 0, -11, -29, -39, -39, -37, -37, -45, -53, -53, -49, -43, -34, -24, -22, -17, 7 | -6, 6, 22, 39, 55, 69, 72, 72, 76, 78, 83, 85, 81, 79, 74, 63, 8 | 52, 47, 36, 17, 0, -19, -33, -40, -42, -48, -60, -75, -86, -94, -98, -95, 9 | -87, -75, -66, -55, -43, -27, -13, -2, 9, 18, 25, 31, 36, 40, 45, 48, 10 | 44, 36, 26, 19, 13, 7, 3, -4, -14, -26, -40, -51, -56, -61, -72, -78, 11 | -77, -77, -77, -73, -67, -61, -57, -52, -42, -31, -20, -9, 1, 10, 17, 27, 12 | 37, 44, 50, 52, 52, 50, 49, 50, 51, 45, 31, 14, 2, 0, -4, -13, 13 | -20, -24, -30, -32, -28, -26, -27, -22, -16, -10, 0, 14, 27, 30, 28, 26, 14 | 27, 33, 34, 34, 40, 42, 36, 33, 39, 41, 32, 22, 12, 5, 1, -1, 15 | -1, -6, -13, -14, -15, -16, -16, -20, -24, -27, -26, -24, -19, -14, -12, -13, 16 | -11, -12, -14, -15, -18, -23, -30, -35, -36, -35, -39, -46, -49, -52, -57, -63, 17 | -68, -65, -56, -50, -50, -51, -41, -28, -18, -12, -8, -2, 2, 5, 13, 25, 18 | 34, 37, 37, 35, 34, 35, 36, 30, 18, 7, 0, -7, -14, -18, -20, -26, 19 | -36, -44, -48, -48, -47, -44, -37, -32, -26, -17, -7, 5, 18, 32, 50, 70, 20 | 91, 111, 127, 124, 106, 87, 70, 64, 58, 54, 59, 53, 35, 20, 12, 1, 21 | -2, 12, 21, 22, 22, 27, 33, 33, 35, 45, 46, 34, 24, 17, 7, 3 22 | }; 23 | 24 | const uint8_t harmonicaVolumeTable[] PROGMEM = { 25 | 16, 86, 142, 177, 199, 212, 220, 224, 225, 226, 225, 224, 222, 220, 218, 216 26 | }; 27 | 28 | void playHarmonica(waveChannel* channel, uint8_t data) { 29 | setChannelWave(harmonicaWaveTable, data - 12); 30 | setChannelVolume(harmonicaVolumeTable, 1); 31 | channel->currentVolume = 0; 32 | } 33 | -------------------------------------------------------------------------------- /microsound/commands.h: -------------------------------------------------------------------------------- 1 | #ifndef MICROMUSIC_COMMANDS_INIT 2 | #define MICROMUSIC_COMMANDS_INIT 3 | 4 | /* 5 | * Commands for music data. 6 | * This command set supports up to 256 samples (instruments, SAMPLES_SIZE) and 16 channels (voices, CHANNELS_SIZE). 7 | * There is some limitation on wait length: 8 | * - COMMAND_PLAY handles 3 bits for wait time, up to 7 beats before next command; 9 | * - COMMAND_WAIT handles 6 bits for wait time, up to 63 beats before next command; 10 | * For longer pauses COMMAND_WAIT should be used multiple times. 11 | * 12 | * Author: Aleksandr Maksymenko aka masyaman 13 | */ 14 | 15 | #define COMMAND_PLAY 0b10000000 // 2 bytes: [CWWWHHHH][NNNNNNNN]: C: command, HHHH: channelId, NNNNNNNN: note, WWW: wait 16 | #define COMMAND_WAIT 0b01000000 // 1 byte: [CCWWWWWW]: CC: command, WWWWWW: wait 17 | #define COMMAND_VOLUME 0b00100000 // 2 bytes: [CCC_HHHH][VVVVVVVV]: CCC: command, HHHH: channelId, VVVVVVVV: volume 18 | #define COMMAND_INSTRUMENT 0b00010000 // 2 bytes: [CCCCHHHH][SSSSSSSS]: CCCC: command, HHHH: channelId, SSSSSSSS: sample 19 | #define COMMAND_TEMPO 0b00000001 // 3 bytes: [CCCCCCCC][TTTTTTTT][TTTTTTTT]: C: command, T: bpm increment counter 20 | #define COMMAND_END 0b00000000 21 | 22 | #define DATA_PLAY(channel, note, wait) (COMMAND_PLAY | ((wait & 0b00000111) << 4) | (channel)), (note) 23 | #define DATA_WAIT(wait) (COMMAND_WAIT | (wait & 0b00111111)) 24 | #define DATA_VOLUME(channel, vol) (COMMAND_VOLUME | (channel)), (vol) 25 | #define DATA_INSTRUMENT(channel, instrument) (COMMAND_INSTRUMENT | (channel)), (instrument) 26 | #define DATA_TEMPO(bpm) (COMMAND_TEMPO), ((fromBpm(bpm) >> 8) & 0xFF), (fromBpm(bpm) & 0xFF) 27 | #define DATA_END() (COMMAND_END) 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /microsound/instruments/accordion.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | const int8_t accordionWaveTable[] PROGMEM = { 6 | 0, 5, 11, 11, 10, 10, 14, 18, 22, 24, 26, 29, 30, 32, 34, 34, 7 | 34, 33, 33, 33, 33, 32, 31, 30, 30, 29, 29, 29, 29, 29, 30, 32, 8 | 33, 37, 40, 44, 48, 52, 56, 62, 69, 75, 82, 90, 97, 105, 112, 119, 9 | 122, 124, 127, 126, 125, 124, 121, 119, 116, 112, 107, 102, 96, 91, 85, 79, 10 | 72, 66, 61, 56, 51, 48, 45, 41, 40, 40, 39, 39, 40, 41, 41, 42, 11 | 43, 43, 43, 44, 43, 42, 40, 39, 37, 35, 32, 28, 25, 22, 19, 17, 12 | 16, 15, 14, 15, 15, 16, 18, 21, 24, 26, 27, 29, 29, 29, 29, 29, 13 | 30, 31, 33, 34, 35, 36, 37, 38, 38, 37, 37, 37, 37, 38, 38, 39, 14 | 40, 40, 39, 38, 37, 36, 34, 32, 30, 28, 25, 22, 18, 15, 10, 6, 15 | 2, -3, -9, -15, -21, -27, -34, -41, -47, -53, -58, -62, -66, -69, -72, -75, 16 | -79, -83, -86, -87, -89, -90, -90, -90, -89, -86, -84, -82, -80, -78, -77, -75, 17 | -73, -72, -72, -72, -72, -73, -74, -75, -76, -77, -79, -81, -83, -86, -88, -91, 18 | -94, -95, -97, -97, -96, -94, -92, -89, -86, -83, -78, -74, -69, -65, -61, -57, 19 | -55, -52, -49, -48, -47, -46, -46, -47, -48, -49, -51, -52, -54, -57, -59, -58, 20 | -57, -55, -51, -46, -42, -40, -38, -36, -35, -34, -33, -33, -33, -33, -33, -34, 21 | -35, -34, -33, -33, -31, -29, -27, -26, -25, -24, -22, -20, -18, -14, -10, -6 22 | }; 23 | 24 | const uint8_t accordionVolumeTable[] PROGMEM = { 25 | 6, 14, 24, 40, 58, 81, 100, 124, 148, 177, 187, 186, 189, 193, 206, 215, 26 | 213, 211, 209, 217, 235, 225, 223, 227, 232, 240, 238, 233, 230, 233, 245, 232}; 27 | 28 | void playAccordion(waveChannel* channel, uint8_t data) { 29 | setChannelWave(accordionWaveTable, data); 30 | setChannelVolume(accordionVolumeTable, 1); 31 | channel->currentVolume = 0; 32 | } 33 | -------------------------------------------------------------------------------- /microsound/delay.h: -------------------------------------------------------------------------------- 1 | #ifndef MICROMUSIC_DALAY_INIT 2 | #define MICROMUSIC_DALAY_INIT 3 | 4 | /* 5 | * Control delays using function similar to . 6 | * During delay sound buffer is filled with sound data. 7 | * 8 | * Currently delay is not too accurate, especially with small values. 9 | * It's recommended to use delays in range [0.2 ... 1000] milliseconds. If longer delays are needed it's possible 10 | * to use 32 bits sample counter: 11 | * #define DELAY_SAMPLE_COUNTER_TYPE uint32_t 12 | * 13 | * Author: Aleksandr Maksymenko aka masyaman 14 | */ 15 | 16 | 17 | #include "micromusic.h" 18 | 19 | 20 | // For delays longer than 1 second use uint32_t 21 | #ifndef DELAY_SAMPLE_COUNTER_TYPE 22 | #define DELAY_SAMPLE_COUNTER_TYPE uint16_t 23 | #endif 24 | 25 | // Init function similar to 26 | #ifndef MANUAL_DELAY_INIT 27 | #define _delay_ms(ms) delaySamples((DELAY_SAMPLE_COUNTER_TYPE) ((ms) * (MICROSOUND_FREQUENCY) / 1000)) 28 | #endif 29 | 30 | //void delaySamples8bits(uint8_t samples) { 31 | // fillBuffer(samples); 32 | // updateMusicData(); 33 | //} 34 | 35 | static uint8_t noUpdatesCounter; 36 | 37 | void delaySamples(DELAY_SAMPLE_COUNTER_TYPE samples) { 38 | uint8_t prevSampleCounter = bufferReadCounter; 39 | 40 | while (1) { 41 | fillBuffer((samples > SAMPLES_PER_TICK) ? SAMPLES_PER_TICK : samples); 42 | 43 | uint8_t samplesPassed = bufferReadCounter - prevSampleCounter; 44 | prevSampleCounter += samplesPassed; 45 | 46 | noUpdatesCounter -= (uint8_t) samplesPassed; 47 | // Overflow, too long time passed since last buffer update 48 | if (noUpdatesCounter >= SAMPLES_PER_TICK) { 49 | updateMusicData(); 50 | noUpdatesCounter = SAMPLES_PER_TICK - 1; 51 | } 52 | 53 | if (samplesPassed >= samples) { 54 | return; 55 | } 56 | samples -= samplesPassed; 57 | } 58 | } 59 | 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /microsound/buffer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Control sound buffer. 3 | * 4 | * By default buffer is 8 samples long but this value can be increased via BUFFER_SIZE for longer user code execution. 5 | * Buffer size is 8 bits and is 2^n. Max buffer size is 256 samples. 6 | * 7 | * By default buffer contains 8 bits values but it can be switched to 16 bits. 8 | * 9 | * Additionally code allows to measure small periods of time via bufferReadCounter. On each buffer read value is incremented. 10 | * 11 | * Author: Aleksandr Maksymenko aka masyaman 12 | */ 13 | 14 | // Length of a buffer, samples, valid values are 2^n 15 | #ifndef BUFFER_SIZE 16 | #define BUFFER_SIZE 8 17 | #endif 18 | 19 | // Bit depth: 8 or 16 20 | #ifndef BUFFER_BITS 21 | #define BUFFER_BITS 8 22 | #endif 23 | 24 | 25 | #if BUFFER_BITS == 8 26 | typedef uint8_t soundSample; 27 | #define toSample(uint16) ((soundSample) (uint16 >> 8)) 28 | #define sampleToUint8(sample) ((uint8_t) (sample)) 29 | #define sampleToUint16(sample) ((uint16_t) (sample << 8)) 30 | #elif BUFFER_BITS == 16 31 | typedef uint16_t soundSample; 32 | #define toSample(uint16) ((soundSample) (uint16)) 33 | #define sampleToUint8(sample) ((uint8_t) (sample >> 8)) 34 | #define sampleToUint16(sample) ((uint16_t) (sample)) 35 | #endif 36 | 37 | 38 | #define BUFFER_MASK ((uint8_t)(BUFFER_SIZE - 1)) 39 | volatile soundSample soundBuffer[BUFFER_SIZE]; 40 | volatile uint8_t bufferReadCounter; 41 | uint8_t bufferWrite; 42 | 43 | #define bufferRead (bufferReadCounter & BUFFER_MASK) 44 | #define isBufferFull (bufferRead == bufferWrite) 45 | #define isBufferNotFull (bufferRead != bufferWrite) 46 | #define samplesToWrite (((uint8_t)(bufferRead - bufferWrite)) & BUFFER_MASK) 47 | #define samplesInBuffer (((uint8_t)BUFFER_SIZE) - samplesToWrite) 48 | 49 | 50 | inline void writeToBuffer(soundSample value) { 51 | bufferWrite = (bufferWrite + 1) & BUFFER_MASK; 52 | soundBuffer[bufferWrite] = (value); 53 | } 54 | 55 | inline soundSample readFromBuffer() { 56 | return soundBuffer[(++bufferReadCounter) & BUFFER_MASK]; 57 | } 58 | -------------------------------------------------------------------------------- /demos/atmega8/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include 6 | #include 7 | //#include 8 | #include 9 | #include 10 | 11 | #ifndef F_CPU 12 | #define F_CPU 8000000 13 | #endif 14 | 15 | #define SAMPLE_PERCUSSION 0 16 | #define SAMPLE_PIANO 1 17 | #define SAMPLE_HARMONICA 2 18 | #define SAMPLE_BASS 3 19 | #define SAMPLE_OVERDRIVE 4 20 | #define SAMPLE_MUSICBOX 5 21 | 22 | #define NOISE_CALCULATION_WHEN_UNUSED // Use full calculation of noise channel on each sample to test performance 23 | //#define BUFFER_BITS 16 24 | //#define BUFFER_SIZE 128 25 | //#define MICROSOUND_FREQUENCY_DIVIDER 4 26 | //#define INTERPOLATION_STRENGTH 2 27 | //#define INTERPOLATE_WAVE 28 | #define CHANNELS_SIZE 5 29 | #define SAMPLES_SIZE 16 30 | #define USE_NOISE_CHANNEL 31 | 32 | #include "../../microsound/devices/atmega8timer1.h" 33 | #include "../../microsound/micromusic.h" 34 | 35 | #include "../../microsound/instruments/piano.h" 36 | #include "../../microsound/instruments/bassGuitar.h" 37 | //#include "../../microsound/instruments/accordion.h" 38 | #include "../../microsound/instruments/harmonica.h" 39 | #include "../../microsound/instruments/overdrivenGuitarChord.h" 40 | #include "../../microsound/instruments/percussion.h" 41 | #include "../../microsound/instruments/musicbox.h" 42 | 43 | #include "../../microsound/samples/oh_susanna.h" 44 | #include "../../microsound/samples/for_elise.h" 45 | 46 | 47 | int main(void) 48 | { 49 | initMusic(); 50 | setSample(SAMPLE_PERCUSSION, playPercussion); 51 | setSample(SAMPLE_PIANO, playPiano); 52 | setSample(SAMPLE_HARMONICA, playHarmonica); 53 | setSample(SAMPLE_BASS, playBassGuitar); 54 | setSample(SAMPLE_OVERDRIVE, playOverdrivenGuitarChord); 55 | setSample(SAMPLE_MUSICBOX, playMusicbox); 56 | 57 | sei(); 58 | 59 | DDRB |= 0x01; 60 | while (1) { 61 | 62 | PORTB |= 0x01; 63 | fillMusicBuffer(); 64 | PORTB &= ~0x01; 65 | 66 | // Simulate other CPU usage 67 | while (samplesInBuffer > 4) {}; 68 | 69 | if (isMusicStopped) { 70 | playMusic(ohSusannaSong); 71 | } 72 | 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /demos/attiny85/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef F_CPU 11 | #define F_CPU 16000000 12 | #endif 13 | 14 | #define SAMPLE_PERCUSSION 0 15 | #define SAMPLE_PIANO 1 16 | #define SAMPLE_HARMONICA 2 17 | #define SAMPLE_BASS 3 18 | #define SAMPLE_OVERDRIVE 4 19 | #define SAMPLE_MUSICBOX 5 20 | 21 | #define SPEED_OPTIMIZED_MULTIPLICATION 22 | //#define SIMPLIFIED_MULTIPLICATION 23 | #define MICROSOUND_FREQUENCY 32000 24 | //#define MICROSOUND_STATIC_VOLUME 2 25 | //#define BUFFER_BITS 16 26 | #define BUFFER_SIZE 64 27 | #define CHANNELS_SIZE 5 28 | #define SAMPLES_SIZE 16 29 | #define USE_NOISE_CHANNEL 30 | 31 | #include "../../microsound/devices/attiny85timers01.h" 32 | #include "../../microsound/micromusic.h" 33 | 34 | //#include "../../microsound/instruments/piano.h" 35 | //#include "../../microsound/instruments/bassGuitar.h" 36 | ////#include "../../microsound/instruments/accordion.h" 37 | //#include "../../microsound/instruments/harmonica.h" 38 | //#include "../../microsound/instruments/overdrivenGuitarChord.h" 39 | //#include "../../microsound/instruments/percussion.h" 40 | #include "../../microsound/instruments/musicbox.h" 41 | 42 | 43 | //#include "../../microsound/samples/notifications_single_channel.h" 44 | //#include "../../microsound/samples/oh_susanna.h" 45 | #include "../../microsound/samples/for_elise.h" 46 | 47 | int main(void) 48 | { 49 | initMusic(); 50 | // setSample(SAMPLE_PERCUSSION, playPercussion); 51 | // setSample(SAMPLE_PIANO, playPiano); 52 | // setSample(SAMPLE_HARMONICA, playHarmonica); 53 | // setSample(SAMPLE_BASS, playBassGuitar); 54 | // setSample(SAMPLE_OVERDRIVE, playOverdrivenGuitarChord); 55 | setSample(SAMPLE_MUSICBOX, playMusicbox); 56 | 57 | sei(); 58 | 59 | DDRB |= 0x01; 60 | while (1) { 61 | 62 | PORTB |= 0x01; 63 | fillMusicBuffer(); 64 | PORTB &= ~0x01; 65 | 66 | // Simulate other CPU usage 67 | // while (samplesInBuffer > 4) {}; 68 | 69 | if (isMusicStopped) { 70 | playMusic(forElise); 71 | } 72 | 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /demos/attiny861/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef F_CPU 11 | #define F_CPU 16000000 12 | #endif 13 | 14 | #define SAMPLE_PERCUSSION 0 15 | #define SAMPLE_PIANO 1 16 | #define SAMPLE_HARMONICA 2 17 | #define SAMPLE_BASS 3 18 | #define SAMPLE_OVERDRIVE 4 19 | #define SAMPLE_MUSICBOX 5 20 | 21 | #define SPEED_OPTIMIZED_MULTIPLICATION 22 | //#define SIMPLIFIED_MULTIPLICATION 23 | #define MICROSOUND_FREQUENCY 32000 24 | //#define MICROSOUND_STATIC_VOLUME 2 25 | //#define BUFFER_BITS 16 26 | #define BUFFER_SIZE 64 27 | #define CHANNELS_SIZE 5 28 | #define SAMPLES_SIZE 16 29 | #define USE_NOISE_CHANNEL 30 | 31 | #include "../../microsound/devices/attiny861timers01.h" 32 | #include "../../microsound/micromusic.h" 33 | 34 | //#include "../../microsound/instruments/piano.h" 35 | //#include "../../microsound/instruments/bassGuitar.h" 36 | ////#include "../../microsound/instruments/accordion.h" 37 | //#include "../../microsound/instruments/harmonica.h" 38 | //#include "../../microsound/instruments/overdrivenGuitarChord.h" 39 | //#include "../../microsound/instruments/percussion.h" 40 | #include "../../microsound/instruments/musicbox.h" 41 | 42 | 43 | //#include "../../microsound/samples/notifications_single_channel.h" 44 | //#include "../../microsound/samples/oh_susanna.h" 45 | #include "../../microsound/samples/for_elise.h" 46 | 47 | int main(void) 48 | { 49 | initMusic(); 50 | // setSample(SAMPLE_PERCUSSION, playPercussion); 51 | // setSample(SAMPLE_PIANO, playPiano); 52 | // setSample(SAMPLE_HARMONICA, playHarmonica); 53 | // setSample(SAMPLE_BASS, playBassGuitar); 54 | // setSample(SAMPLE_OVERDRIVE, playOverdrivenGuitarChord); 55 | setSample(SAMPLE_MUSICBOX, playMusicbox); 56 | 57 | sei(); 58 | 59 | DDRB |= 0x01; 60 | while (1) { 61 | 62 | PORTB |= 0x01; 63 | fillMusicBuffer(); 64 | PORTB &= ~0x01; 65 | 66 | // Simulate other CPU usage 67 | // while (samplesInBuffer > 4) {}; 68 | 69 | if (isMusicStopped) { 70 | playMusic(forElise); 71 | } 72 | 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /microsound/globalSoundInterpolationExperimental2.h: -------------------------------------------------------------------------------- 1 | 2 | // Experimental interpolation using quadratic function 3 | 4 | #if INTERPOLATION_STRENGTH > 0 5 | 6 | #if INTERPOLATION_STRENGTH == 1 7 | #define INTERPOLATION_DIFF_MULTIPLIER 85 8 | #elif INTERPOLATION_STRENGTH == 2 9 | #define INTERPOLATION_DIFF_MULTIPLIER 26 10 | #elif INTERPOLATION_STRENGTH == 3 11 | #define INTERPOLATION_DIFF_MULTIPLIER 7 12 | #elif INTERPOLATION_STRENGTH == 4 13 | #define INTERPOLATION_DIFF_MULTIPLIER 2 14 | #endif 15 | 16 | uint8_t interpolationCounter; 17 | uint8_t interpolationPrevValue; 18 | int8_t interpolationPrevDiff; 19 | // int16_t prevDiff; 20 | 21 | uint16_t interpolationValue; 22 | int16_t interpolationDiff, interpolationDiffDiff; 23 | 24 | 25 | // Quadratic interpolation with distortion 26 | inline uint8_t getNextInterpolatedSample() { 27 | interpolationCounter = (interpolationCounter + 1) & ((1 << INTERPOLATION_STRENGTH) - 1); 28 | 29 | if (!interpolationCounter) { 30 | 31 | // interpolationDiff = interpolationPrevDiff << 8 >> INTERPOLATION_STRENGTH; 32 | // uint8_t nextValue = INTERPOLATION_SOURCE_FUNCTION(); 33 | // interpolationPrevDiff = nextValue - (interpolationValue >> 8) - interpolationPrevDiff; 34 | //// prevValue = nextValue; 35 | // interpolationDiffDiff = interpolationPrevDiff * INTERPOLATION_DIFF_MULTIPLIER; 36 | //// interpolationValue = nextValue << 8; 37 | //// return nextValue; 38 | 39 | interpolationDiff = ((int16_t) interpolationPrevDiff) << 8 >> (INTERPOLATION_STRENGTH); 40 | uint8_t nextValue = readFromBuffer(); 41 | interpolationPrevDiff = nextValue - interpolationPrevValue; 42 | interpolationPrevValue = nextValue; 43 | interpolationDiffDiff = interpolationPrevDiff * INTERPOLATION_DIFF_MULTIPLIER; 44 | interpolationValue = nextValue << 8; 45 | 46 | // interpolationDiff = ((int16_t) prevDiff) << 8 >> (INTERPOLATION_STRENGTH); 47 | return nextValue; 48 | } 49 | interpolationDiff += interpolationDiffDiff; 50 | interpolationValue += interpolationDiff; 51 | return interpolationValue >> 8; 52 | } 53 | 54 | #else 55 | 56 | #define getNextInterpolatedSample readFromBuffer 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /demos/atmega328p/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include 6 | #include 7 | //#include 8 | #include 9 | #include 10 | 11 | #ifndef F_CPU 12 | #define F_CPU 8000000 13 | #endif 14 | 15 | #define SAMPLE_PERCUSSION 0 16 | #define SAMPLE_PIANO 1 17 | #define SAMPLE_HARMONICA 2 18 | #define SAMPLE_BASS 3 19 | #define SAMPLE_OVERDRIVE 4 20 | #define SAMPLE_MUSICBOX 5 21 | 22 | #define NOISE_CALCULATION_WHEN_UNUSED // Use full calculation of noise channel on each sample to test performance 23 | //#define BUFFER_BITS 16 24 | //#define BUFFER_SIZE 128 25 | //#define MICROSOUND_FREQUENCY_DIVIDER 4 26 | //#define INTERPOLATION_STRENGTH 2 27 | //#define INTERPOLATE_WAVE 28 | #define CHANNELS_SIZE 5 29 | #define SAMPLES_SIZE 16 30 | #define USE_NOISE_CHANNEL 31 | 32 | #include "../../microsound/devices/atmega328Ptimer1.h" 33 | #include "../../microsound/micromusic.h" 34 | 35 | #include "../../microsound/instruments/piano.h" 36 | #include "../../microsound/instruments/bassGuitar.h" 37 | //#include "../../microsound/instruments/accordion.h" 38 | #include "../../microsound/instruments/harmonica.h" 39 | #include "../../microsound/instruments/overdrivenGuitarChord.h" 40 | #include "../../microsound/instruments/percussion.h" 41 | #include "../../microsound/instruments/musicbox.h" 42 | 43 | 44 | //#include "../../microsound/samples/notifications_single_channel.h" 45 | #include "../../microsound/samples/oh_susanna.h" 46 | #include "../../microsound/samples/for_elise.h" 47 | 48 | 49 | int main(void) 50 | { 51 | initMusic(); 52 | setSample(SAMPLE_PERCUSSION, playPercussion); 53 | setSample(SAMPLE_PIANO, playPiano); 54 | setSample(SAMPLE_HARMONICA, playHarmonica); 55 | setSample(SAMPLE_BASS, playBassGuitar); 56 | setSample(SAMPLE_OVERDRIVE, playOverdrivenGuitarChord); 57 | setSample(SAMPLE_MUSICBOX, playMusicbox); 58 | 59 | sei(); 60 | 61 | DDRB |= 0x01; 62 | while (1) { 63 | 64 | PORTB |= 0x01; 65 | fillMusicBuffer(); 66 | PORTB &= ~0x01; 67 | 68 | // Simulate other CPU usage 69 | while (samplesInBuffer > 4) {}; 70 | 71 | if (isMusicStopped) { 72 | playMusic(ohSusannaSong); 73 | } 74 | 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /demos/atmega8/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DEVICE = atmega8 3 | F_CPU = 8000000 # in Hz 4 | FUSE_L = 0xE4 5 | FUSE_H = 0xD9 6 | AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer 7 | 8 | CFLAGS = -I. -DDEBUG_LEVEL=0 9 | OBJECTS = main.c 10 | 11 | COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) 12 | 13 | # symbolic targets: 14 | help: 15 | @echo "This Makefile has no default rule. Use one of the following:" 16 | @echo "make hex ....... to build main.hex" 17 | @echo "make program ... to flash fuses and firmware" 18 | @echo "make fuse ...... to flash the fuses" 19 | @echo "make flash ..... to flash the firmware (use this on metaboard)" 20 | @echo "make clean ..... to delete objects and hex file" 21 | 22 | hex: clean main.hex 23 | 24 | program: flash fuse 25 | 26 | # rule for programming fuse bits: 27 | fuse: 28 | @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ 29 | { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } 30 | $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m 31 | 32 | # rule for uploading firmware: 33 | flash: main.hex 34 | $(AVRDUDE) -U flash:w:main.hex:i 35 | 36 | # rule for uploading firmware without verifying: 37 | flashNoVerify: main.hex 38 | $(AVRDUDE) -V -U flash:w:main.hex:i 39 | 40 | # rule for deleting dependent files (those which can be built by Make): 41 | clean: 42 | rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o main.s 43 | 44 | # Generic rule for compiling C files: 45 | .c.o: 46 | $(COMPILE) -c $< -o $@ 47 | 48 | # Generic rule for assembling Assembler source files: 49 | .S.o: 50 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 51 | # "-x assembler-with-cpp" should not be necessary since this is the default 52 | # file type for the .S (with capital S) extension. However, upper case 53 | # characters are not always preserved on Windows. To ensure WinAVR 54 | # compatibility define the file type manually. 55 | 56 | # Generic rule for compiling C to assembler, used for debugging only. 57 | .c.s: 58 | $(COMPILE) -S $< -o $@ 59 | 60 | # file targets: 61 | 62 | main.elf: 63 | $(COMPILE) -o main.elf $(OBJECTS) 64 | 65 | main.hex: main.elf 66 | rm -f main.hex main.eep.hex 67 | avr-objcopy -j .text -j .data -O ihex main.elf main.hex 68 | avr-size main.hex 69 | 70 | # debugging targets: 71 | 72 | disasm: main.elf 73 | avr-objdump -d main.elf 74 | 75 | cpp: 76 | $(COMPILE) -E main.c 77 | -------------------------------------------------------------------------------- /demos/atmega8lcd/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DEVICE = atmega8 3 | F_CPU = 8000000 # in Hz 4 | FUSE_L = 0xE4 5 | FUSE_H = 0xD9 6 | AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer 7 | 8 | CFLAGS = -I. -DDEBUG_LEVEL=0 9 | OBJECTS = main.c 10 | 11 | COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) 12 | 13 | # symbolic targets: 14 | help: 15 | @echo "This Makefile has no default rule. Use one of the following:" 16 | @echo "make hex ....... to build main.hex" 17 | @echo "make program ... to flash fuses and firmware" 18 | @echo "make fuse ...... to flash the fuses" 19 | @echo "make flash ..... to flash the firmware (use this on metaboard)" 20 | @echo "make clean ..... to delete objects and hex file" 21 | 22 | hex: clean main.hex 23 | 24 | program: flash fuse 25 | 26 | # rule for programming fuse bits: 27 | fuse: 28 | @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ 29 | { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } 30 | $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m 31 | 32 | # rule for uploading firmware: 33 | flash: main.hex 34 | $(AVRDUDE) -U flash:w:main.hex:i 35 | 36 | # rule for uploading firmware without verifying: 37 | flashNoVerify: main.hex 38 | $(AVRDUDE) -V -U flash:w:main.hex:i 39 | 40 | # rule for deleting dependent files (those which can be built by Make): 41 | clean: 42 | rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o main.s 43 | 44 | # Generic rule for compiling C files: 45 | .c.o: 46 | $(COMPILE) -c $< -o $@ 47 | 48 | # Generic rule for assembling Assembler source files: 49 | .S.o: 50 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 51 | # "-x assembler-with-cpp" should not be necessary since this is the default 52 | # file type for the .S (with capital S) extension. However, upper case 53 | # characters are not always preserved on Windows. To ensure WinAVR 54 | # compatibility define the file type manually. 55 | 56 | # Generic rule for compiling C to assembler, used for debugging only. 57 | .c.s: 58 | $(COMPILE) -S $< -o $@ 59 | 60 | # file targets: 61 | 62 | main.elf: 63 | $(COMPILE) -o main.elf $(OBJECTS) 64 | 65 | main.hex: main.elf 66 | rm -f main.hex main.eep.hex 67 | avr-objcopy -j .text -j .data -O ihex main.elf main.hex 68 | avr-size main.hex 69 | 70 | # debugging targets: 71 | 72 | disasm: main.elf 73 | avr-objdump -d main.elf 74 | 75 | cpp: 76 | $(COMPILE) -E main.c 77 | -------------------------------------------------------------------------------- /demos/attiny26/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DEVICE = attiny26 3 | F_CPU = 16000000 # in Hz 4 | FUSE_L = 0x71 5 | FUSE_H = 0xF7 6 | AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer 7 | 8 | CFLAGS = -I. -DDEBUG_LEVEL=0 9 | OBJECTS = main.c 10 | 11 | COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) 12 | 13 | # symbolic targets: 14 | help: 15 | @echo "This Makefile has no default rule. Use one of the following:" 16 | @echo "make hex ....... to build main.hex" 17 | @echo "make program ... to flash fuses and firmware" 18 | @echo "make fuse ...... to flash the fuses" 19 | @echo "make flash ..... to flash the firmware (use this on metaboard)" 20 | @echo "make clean ..... to delete objects and hex file" 21 | 22 | hex: clean main.hex 23 | 24 | program: flash fuse 25 | 26 | # rule for programming fuse bits: 27 | fuse: 28 | @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ 29 | { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } 30 | $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m 31 | 32 | # rule for uploading firmware: 33 | flash: main.hex 34 | $(AVRDUDE) -U flash:w:main.hex:i 35 | 36 | # rule for uploading firmware without verifying: 37 | flashNoVerify: main.hex 38 | $(AVRDUDE) -V -U flash:w:main.hex:i 39 | 40 | # rule for deleting dependent files (those which can be built by Make): 41 | clean: 42 | rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o main.s 43 | 44 | # Generic rule for compiling C files: 45 | .c.o: 46 | $(COMPILE) -c $< -o $@ 47 | 48 | # Generic rule for assembling Assembler source files: 49 | .S.o: 50 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 51 | # "-x assembler-with-cpp" should not be necessary since this is the default 52 | # file type for the .S (with capital S) extension. However, upper case 53 | # characters are not always preserved on Windows. To ensure WinAVR 54 | # compatibility define the file type manually. 55 | 56 | # Generic rule for compiling C to assembler, used for debugging only. 57 | .c.s: 58 | $(COMPILE) -S $< -o $@ 59 | 60 | # file targets: 61 | 62 | main.elf: 63 | $(COMPILE) -o main.elf $(OBJECTS) 64 | 65 | main.hex: main.elf 66 | rm -f main.hex main.eep.hex 67 | avr-objcopy -j .text -j .data -O ihex main.elf main.hex 68 | avr-size main.hex 69 | 70 | # debugging targets: 71 | 72 | disasm: main.elf 73 | avr-objdump -d main.elf 74 | 75 | cpp: 76 | $(COMPILE) -E main.c 77 | -------------------------------------------------------------------------------- /demos/arduino328p/microsound.ino: -------------------------------------------------------------------------------- 1 | /* 2 | * Sketch with microsound example for Arduino based on ATmega328P. 3 | * 4 | * Check demos/arduino328p/README.md for building instructions. 5 | * 6 | * Author: Aleksandr Maksymenko aka masyaman 7 | */ 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #ifndef F_CPU 15 | #define F_CPU 16000000 16 | #endif 17 | 18 | #define SAMPLE_PERCUSSION 0 19 | #define SAMPLE_PIANO 1 20 | #define SAMPLE_HARMONICA 2 21 | #define SAMPLE_BASS 3 22 | #define SAMPLE_OVERDRIVE 4 23 | #define SAMPLE_MUSICBOX 5 24 | 25 | //#define NOISE_CALCULATION_WHEN_UNUSED // Use full calculation of noise channel on each sample to test performance 26 | #define BUFFER_SIZE 128 27 | #define MICROSOUND_FREQUENCY_DIVIDER 2 // Divide frequency by 2 as Arduino typically runs on 16MHz and this gives frequency 62500Hz 28 | //#define INTERPOLATION_STRENGTH 2 29 | //#define INTERPOLATE_WAVE 30 | #define CHANNELS_SIZE 5 31 | #define SAMPLES_SIZE 16 32 | #define USE_NOISE_CHANNEL 33 | 34 | //#include "microsound/devices/atmega328Ptimer1.h" // Use this for 8-bits output 35 | #include "microsound/devices/atmega328Ptimer1out16bits.h" // Use this for 16-bits output 36 | #include "microsound/micromusic.h" 37 | 38 | #include "microsound/instruments/piano.h" 39 | #include "microsound/instruments/bassGuitar.h" 40 | //#include "microsound/instruments/accordion.h" 41 | #include "microsound/instruments/harmonica.h" 42 | #include "microsound/instruments/overdrivenGuitarChord.h" 43 | #include "microsound/instruments/percussion.h" 44 | #include "microsound/instruments/musicbox.h" 45 | 46 | 47 | //#include "microsound/samples/notifications_single_channel.h" 48 | #include "microsound/samples/oh_susanna.h" 49 | #include "microsound/samples/for_elise.h" 50 | 51 | 52 | void setup() { 53 | // put your setup code here, to run once: 54 | 55 | initMusic(); 56 | setSample(SAMPLE_PERCUSSION, playPercussion); 57 | setSample(SAMPLE_PIANO, playPiano); 58 | setSample(SAMPLE_HARMONICA, playHarmonica); 59 | setSample(SAMPLE_BASS, playBassGuitar); 60 | setSample(SAMPLE_OVERDRIVE, playOverdrivenGuitarChord); 61 | setSample(SAMPLE_MUSICBOX, playMusicbox); 62 | 63 | sei(); 64 | } 65 | 66 | void loop() { 67 | // put your main code here, to run repeatedly: 68 | 69 | fillMusicBuffer(); 70 | 71 | 72 | if (isMusicStopped) { 73 | playMusic(ohSusannaSong); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /demos/attiny85/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DEVICE = attiny85 3 | F_CPU = 16000000 # in Hz 4 | FUSE_L = 0xF1 5 | FUSE_H = 0xDF 6 | FUSE_E = 0xFF 7 | AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer 8 | 9 | CFLAGS = -I. -DDEBUG_LEVEL=0 10 | OBJECTS = main.c 11 | 12 | COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) 13 | 14 | # symbolic targets: 15 | help: 16 | @echo "This Makefile has no default rule. Use one of the following:" 17 | @echo "make hex ....... to build main.hex" 18 | @echo "make program ... to flash fuses and firmware" 19 | @echo "make fuse ...... to flash the fuses" 20 | @echo "make flash ..... to flash the firmware (use this on metaboard)" 21 | @echo "make clean ..... to delete objects and hex file" 22 | 23 | hex: clean main.hex 24 | 25 | program: flash fuse 26 | 27 | # rule for programming fuse bits: 28 | fuse: 29 | @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ 30 | { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } 31 | $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m -U efuse:w:$(FUSE_E):m 32 | 33 | # rule for uploading firmware: 34 | flash: main.hex 35 | $(AVRDUDE) -U flash:w:main.hex:i 36 | 37 | # rule for uploading firmware without verifying: 38 | flashNoVerify: main.hex 39 | $(AVRDUDE) -V -U flash:w:main.hex:i 40 | 41 | # rule for deleting dependent files (those which can be built by Make): 42 | clean: 43 | rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o main.s 44 | 45 | # Generic rule for compiling C files: 46 | .c.o: 47 | $(COMPILE) -c $< -o $@ 48 | 49 | # Generic rule for assembling Assembler source files: 50 | .S.o: 51 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 52 | # "-x assembler-with-cpp" should not be necessary since this is the default 53 | # file type for the .S (with capital S) extension. However, upper case 54 | # characters are not always preserved on Windows. To ensure WinAVR 55 | # compatibility define the file type manually. 56 | 57 | # Generic rule for compiling C to assembler, used for debugging only. 58 | .c.s: 59 | $(COMPILE) -S $< -o $@ 60 | 61 | # file targets: 62 | 63 | main.elf: 64 | $(COMPILE) -o main.elf $(OBJECTS) 65 | 66 | main.hex: main.elf 67 | rm -f main.hex main.eep.hex 68 | avr-objcopy -j .text -j .data -O ihex main.elf main.hex 69 | avr-size main.hex 70 | 71 | # debugging targets: 72 | 73 | disasm: main.elf 74 | avr-objdump -d main.elf 75 | 76 | cpp: 77 | $(COMPILE) -E main.c 78 | -------------------------------------------------------------------------------- /demos/attiny861/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DEVICE = attiny861 3 | F_CPU = 16000000 # in Hz 4 | FUSE_L = 0xF1 5 | FUSE_H = 0xDF 6 | FUSE_E = 0xFF 7 | AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer 8 | 9 | CFLAGS = -I. -DDEBUG_LEVEL=0 10 | OBJECTS = main.c 11 | 12 | COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) 13 | 14 | # symbolic targets: 15 | help: 16 | @echo "This Makefile has no default rule. Use one of the following:" 17 | @echo "make hex ....... to build main.hex" 18 | @echo "make program ... to flash fuses and firmware" 19 | @echo "make fuse ...... to flash the fuses" 20 | @echo "make flash ..... to flash the firmware (use this on metaboard)" 21 | @echo "make clean ..... to delete objects and hex file" 22 | 23 | hex: clean main.hex 24 | 25 | program: flash fuse 26 | 27 | # rule for programming fuse bits: 28 | fuse: 29 | @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ 30 | { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } 31 | $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m -U efuse:w:$(FUSE_E):m 32 | 33 | # rule for uploading firmware: 34 | flash: main.hex 35 | $(AVRDUDE) -U flash:w:main.hex:i 36 | 37 | # rule for uploading firmware without verifying: 38 | flashNoVerify: main.hex 39 | $(AVRDUDE) -V -U flash:w:main.hex:i 40 | 41 | # rule for deleting dependent files (those which can be built by Make): 42 | clean: 43 | rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o main.s 44 | 45 | # Generic rule for compiling C files: 46 | .c.o: 47 | $(COMPILE) -c $< -o $@ 48 | 49 | # Generic rule for assembling Assembler source files: 50 | .S.o: 51 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 52 | # "-x assembler-with-cpp" should not be necessary since this is the default 53 | # file type for the .S (with capital S) extension. However, upper case 54 | # characters are not always preserved on Windows. To ensure WinAVR 55 | # compatibility define the file type manually. 56 | 57 | # Generic rule for compiling C to assembler, used for debugging only. 58 | .c.s: 59 | $(COMPILE) -S $< -o $@ 60 | 61 | # file targets: 62 | 63 | main.elf: 64 | $(COMPILE) -o main.elf $(OBJECTS) 65 | 66 | main.hex: main.elf 67 | rm -f main.hex main.eep.hex 68 | avr-objcopy -j .text -j .data -O ihex main.elf main.hex 69 | avr-size main.hex 70 | 71 | # debugging targets: 72 | 73 | disasm: main.elf 74 | avr-objdump -d main.elf 75 | 76 | cpp: 77 | $(COMPILE) -E main.c 78 | -------------------------------------------------------------------------------- /demos/atmega328p/Makefile: -------------------------------------------------------------------------------- 1 | 2 | DEVICE = atmega328p 3 | F_CPU = 8000000 # in Hz 4 | FUSE_L = 0xE2 5 | FUSE_H = 0xD9 6 | FUSE_E = 0xFF 7 | AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer 8 | 9 | CFLAGS = -I. -DDEBUG_LEVEL=0 10 | OBJECTS = main.c 11 | 12 | COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE) 13 | 14 | # symbolic targets: 15 | help: 16 | @echo "This Makefile has no default rule. Use one of the following:" 17 | @echo "make hex ....... to build main.hex" 18 | @echo "make program ... to flash fuses and firmware" 19 | @echo "make fuse ...... to flash the fuses" 20 | @echo "make flash ..... to flash the firmware (use this on metaboard)" 21 | @echo "make clean ..... to delete objects and hex file" 22 | 23 | hex: clean main.hex 24 | 25 | program: flash fuse 26 | 27 | # rule for programming fuse bits: 28 | fuse: 29 | @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \ 30 | { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; } 31 | $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m -U efuse:w:$(FUSE_E):m 32 | 33 | # rule for uploading firmware: 34 | flash: main.hex 35 | $(AVRDUDE) -U flash:w:main.hex:i 36 | 37 | # rule for uploading firmware without verifying: 38 | flashNoVerify: main.hex 39 | $(AVRDUDE) -V -U flash:w:main.hex:i 40 | 41 | # rule for deleting dependent files (those which can be built by Make): 42 | clean: 43 | rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o main.s 44 | 45 | # Generic rule for compiling C files: 46 | .c.o: 47 | $(COMPILE) -c $< -o $@ 48 | 49 | # Generic rule for assembling Assembler source files: 50 | .S.o: 51 | $(COMPILE) -x assembler-with-cpp -c $< -o $@ 52 | # "-x assembler-with-cpp" should not be necessary since this is the default 53 | # file type for the .S (with capital S) extension. However, upper case 54 | # characters are not always preserved on Windows. To ensure WinAVR 55 | # compatibility define the file type manually. 56 | 57 | # Generic rule for compiling C to assembler, used for debugging only. 58 | .c.s: 59 | $(COMPILE) -S $< -o $@ 60 | 61 | # file targets: 62 | 63 | main.elf: 64 | $(COMPILE) -o main.elf $(OBJECTS) 65 | 66 | main.hex: main.elf 67 | rm -f main.hex main.eep.hex 68 | avr-objcopy -j .text -j .data -O ihex main.elf main.hex 69 | avr-size main.hex 70 | 71 | # debugging targets: 72 | 73 | disasm: main.elf 74 | avr-objdump -d main.elf 75 | 76 | cpp: 77 | $(COMPILE) -E main.c 78 | -------------------------------------------------------------------------------- /microsound/instruments/overdrivenGuitarChord.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include "common/expneg.h" 6 | 7 | #define OVERDRIVE_SHORT 0b10000000 // This bit indicates short play and mute 8 | 9 | const int8_t overdrivenGuitarChordWaveTable[] PROGMEM = { 10 | 0, 0, -5, -26, -47, -37, -23, -35, -51, -52, -58, -58, -51, -53, -74, -80, 11 | -74, -81, -93, -91, -84, -86, -93, -90, -82, -80, -85, -88, -87, -81, -66, -60, 12 | -63, -59, -49, -49, -55, -49, -37, -32, -22, -16, -17, -14, -6, -1, 5, 17, 13 | 25, 49, 44, 35, 39, 49, 66, 77, 86, 94, 101, 107, 115, 124, 127, 120, 14 | 105, 110, 124, 122, 100, 92, 98, 98, 96, 95, 71, 56, 65, 72, 49, 30, 15 | 28, 24, 13, 9, 13, 12, 3, -15, -38, -48, -39, -27, -27, -35, -32, -30, 16 | -38, -41, -40, -46, -55, -57, -57, -57, -45, -37, -46, -58, -61, -55, -45, -37, 17 | -34, -26, -32, -35, -33, -30, -18, -13, -13, -9, -2, 3, 5, 4, 4, 3, 18 | -5, -2, 4, -1, -18, -11, 5, 2, -11, -14, -19, -14, 1, 12, -3, -12, 19 | -9, -12, -16, -11, -5, -8, -12, -10, -10, -14, -25, -31, -26, -18, -4, -8, 20 | -23, -19, -3, 0, -12, -21, -18, -15, -10, -8, -11, -8, -5, -16, -22, -10, 21 | 1, 16, 5, -4, 0, 8, 19, 19, 17, 24, 35, 40, 42, 45, 47, 42, 22 | 27, 29, 46, 52, 36, 33, 40, 36, 32, 35, 24, 17, 24, 23, 1, -7, 23 | 4, 6, -1, -1, 5, 6, -1, -11, -17, -19, -12, 0, 7, 4, 7, 7, 24 | 3, 7, 21, 23, 13, 7, 9, 17, 33, 41, 32, 21, 19, 19, 22, 25, 25 | 23, 32, 30, 27, 23, 12, 19, 30, 36, 36, 30, 24, 22, 18, 13, 9 26 | }; 27 | 28 | const uint8_t overdrivenGuitarChordVolumeTableShort[] PROGMEM = { 29 | 255, 248, 244, 238, 233, 228, 223, 219, 214, 209, 205, 200, 196, 192, 128, 64, 30 | 0}; 31 | 32 | #ifdef ADD_GUITAR_NOISE 33 | const uint8_t overdrivenGuitarChordNoiseVolume[] PROGMEM = { 34 | 64, 96, 96, 64, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 35 | 64, 96, 96, 64, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36 | 64, 96, 96, 64, 32, 16, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 37 | 0}; 38 | #endif 39 | 40 | void playOverdrivenGuitarChord(waveChannel* channel, uint8_t data) { 41 | setChannelWave(overdrivenGuitarChordWaveTable, (data & 0b00111111) - 12); 42 | if (data & OVERDRIVE_SHORT) { 43 | setChannelVolume(overdrivenGuitarChordVolumeTableShort, 1); 44 | } else { 45 | setChannelVolumeWithLength(expNegTable, 64, 1); 46 | } 47 | 48 | channel->currentVolume = channel->instrumentVolume; 49 | 50 | #ifdef ADD_GUITAR_NOISE 51 | playNoise(overdrivenGuitarNoiseVolume, 48, channel->instrumentVolume); 52 | #endif 53 | } 54 | -------------------------------------------------------------------------------- /microsound/instruments/percussion.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include "common/sin.h" 6 | #include "common/expneg.h" 7 | 8 | 9 | #define PERCUSSION_HAT_H 0b00000000 10 | #define PERCUSSION_HAT_L 0b00000001 11 | #define PERCUSSION_BAR_H 0b00000010 12 | #define PERCUSSION_BAR_L 0b00000011 13 | 14 | #ifndef BAR_VOLUME_SKIP 15 | #define BAR_VOLUME_SKIP 24 16 | #endif 17 | #define BAR_L_VOLUME_SKIP 8 18 | #define BAR_VOLUME_LENGTH 64 19 | 20 | 21 | const uint8_t noiseVolumeH[] PROGMEM = { 22 | 102, 89, 78, 69, 60, 53, 46, 41, 36, 31, 27, 24, 21, 18, 16, 14, 23 | 12, 11, 9, 8, 7, 6, 5, 5, 4, 3, 3, 3, 2, 2, 2, 1, 24 | 0}; 25 | 26 | const uint8_t noiseVolumeM[] PROGMEM = { 27 | 153, 129, 108, 91, 76, 64, 54, 45, 38, 32, 27, 22, 19, 16, 13, 11, 28 | 9, 8, 6, 5, 4, 4, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 29 | 0}; 30 | 31 | const uint8_t noiseVolumeL[] PROGMEM = { 32 | 51, 43, 36, 30, 25, 21, 18, 15, 12, 10, 9, 7, 6, 5, 4, 3, 33 | 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34 | 0}; 35 | 36 | const uint8_t barVolume[] PROGMEM = { 37 | 184, 176, 168, 161, 154, 148, 141, 135, 130, 124, 119, 114, 109, 104, 100, 96, 38 | 92, 88, 84, 80, 77, 74, 70, 67, 65, 62, 59, 57, 54, 52, 50, 48, 39 | 46, 44, 42, 40, 38, 37, 35, 33, 32, 31, 29, 28, 27, 26, 25, 24, 40 | 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 14, 14, 13, 13, 12, 12, 41 | // 11, 11, 10, 10, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 6, 42 | // 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 43 | // 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 44 | // 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 45 | 0}; 46 | 47 | void playPercussion(waveChannel* channel, uint8_t data) { 48 | 49 | if (data == PERCUSSION_BAR_H) { 50 | playNoise(noiseVolumeM, 32, channel->instrumentVolume); 51 | 52 | channel->waveStep = freqStep(55.000); 53 | channel->waveForm = sinTable; 54 | 55 | channel->volumeForm = barVolume + BAR_VOLUME_SKIP; 56 | channel->volumeFormLength = BAR_VOLUME_LENGTH - BAR_VOLUME_SKIP; 57 | channel->volumeTicksPerSample = 2; 58 | channel->volumeTicksCounter = 2; 59 | 60 | channel->currentVolume = channel->instrumentVolume; 61 | } else if (data == PERCUSSION_BAR_L) { 62 | playNoise(noiseVolumeL, 32, channel->instrumentVolume); 63 | 64 | channel->waveStep = freqStep(55.000); 65 | channel->waveForm = sinTable; 66 | 67 | channel->volumeForm = barVolume + BAR_L_VOLUME_SKIP + BAR_VOLUME_SKIP; 68 | channel->volumeFormLength = BAR_VOLUME_LENGTH - BAR_L_VOLUME_SKIP - BAR_VOLUME_SKIP; 69 | channel->volumeTicksPerSample = 1; 70 | channel->volumeTicksCounter = 1; 71 | 72 | channel->currentVolume = channel->instrumentVolume; 73 | } else if (data == PERCUSSION_HAT_H) { 74 | playNoise(noiseVolumeH, 32, channel->instrumentVolume); 75 | channel->currentVolume = 0; 76 | } else { 77 | playNoise(noiseVolumeL, 32, channel->instrumentVolume); 78 | channel->currentVolume = 0; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /microsound/instruments/piano.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include "common/expneg.h" 6 | 7 | const int8_t pianoWaveTable[] PROGMEM = { 8 | 0, 1, 3, 7, 12, 17, 24, 31, 38, 44, 50, 55, 58, 60, 60, 59, 9 | 56, 52, 49, 45, 43, 42, 43, 45, 48, 50, 51, 52, 51, 48, 45, 40, 10 | 36, 31, 26, 21, 16, 11, 6, 3, 0, -1, -3, -5, -8, -11, -15, -19, 11 | -24, -28, -31, -34, -35, -36, -34, -30, -26, -20, -15, -10, -6, -4, -2, 4, 12 | 10, 17, 21, 25, 27, 29, 31, 32, 32, 31, 29, 27, 24, 23, 24, 26, 13 | 30, 34, 38, 41, 44, 47, 50, 54, 58, 65, 72, 80, 88, 96, 104, 111, 14 | 118, 122, 125, 127, 125, 123, 119, 115, 109, 104, 98, 92, 86, 80, 75, 70, 15 | 67, 64, 61, 58, 55, 50, 46, 42, 38, 35, 33, 32, 32, 31, 30, 29, 16 | 28, 25, 22, 18, 13, 7, 0, -5, -10, -13, -13, -12, -10, -8, -6, -5, 17 | -6, -8, -12, -17, -24, -31, -38, -44, -48, -50, -51, -50, -48, -45, -41, -37, 18 | -33, -30, -27, -26, -26, -28, -30, -33, -36, -40, -43, -46, -50, -53, -56, -59, 19 | -61, -64, -67, -70, -72, -73, -73, -72, -71, -68, -64, -60, -55, -50, -45, -41, 20 | -39, -38, -37, -37, -38, -39, -40, -41, -41, -42, -43, -43, -45, -47, -49, -53, 21 | -58, -62, -67, -71, -73, -74, -74, -71, -66, -59, -52, -44, -37, -31, -27, -24, 22 | -24, -26, -29, -34, -40, -46, -53, -59, -65, -68, -70, -69, -66, -62, -56, -50, 23 | -44, -39, -36, -33, -31, -29, -26, -22, -17, -12, -8, -5, -3, -2, -1, -1 24 | }; 25 | 26 | //// Removed high frequency harmonics 27 | //const int8_t pianoWaveTable[] PROGMEM = { 28 | // 8, 10, 13, 16, 18, 20, 22, 24, 27, 29, 31, 32, 34, 36, 37, 38, 29 | // 39, 40, 41, 42, 42, 42, 42, 41, 40, 39, 37, 36, 34, 32, 29, 27, 30 | // 24, 22, 19, 17, 14, 12, 10, 8, 5, 3, 1, 0, -1, -3, -4, -6, 31 | // -7, -7, -7, -7, -7, -7, -6, -6, -5, -4, -3, -2, -1, 0, 0, 1, 32 | // 3, 5, 7, 9, 11, 14, 16, 19, 21, 24, 27, 30, 33, 36, 39, 43, 33 | // 46, 50, 53, 56, 59, 62, 65, 67, 70, 72, 74, 76, 77, 79, 81, 82, 34 | // 83, 84, 85, 86, 86, 86, 86, 86, 86, 85, 84, 83, 81, 80, 78, 75, 35 | // 73, 70, 67, 64, 60, 57, 53, 49, 45, 42, 38, 35, 32, 29, 26, 24, 36 | // 22, 19, 17, 15, 12, 10, 7, 4, 1, 0, -3, -5, -8, -10, -12, -14, 37 | // -16, -18, -20, -21, -22, -24, -25, -26, -27, -28, -28, -29, -31, -32, -33, -35, 38 | // -37, -38, -40, -42, -44, -45, -46, -47, -48, -49, -49, -50, -50, -50, -50, -50, 39 | // -50, -50, -50, -51, -51, -51, -52, -52, -52, -52, -52, -52, -52, -52, -52, -52, 40 | // -52, -52, -52, -52, -52, -53, -53, -52, -52, -52, -51, -51, -50, -49, -49, -48, 41 | // -48, -47, -47, -47, -47, -47, -48, -48, -49, -50, -51, -51, -52, -53, -53, -53, 42 | // -53, -52, -51, -50, -49, -48, -46, -45, -43, -41, -40, -38, -37, -36, -35, -34, 43 | // -34, -33, -32, -31, -30, -28, -26, -23, -20, -17, -13, -10, -6, -2, 1, 4, 44 | // }; 45 | 46 | 47 | void playPiano(waveChannel* channel, uint8_t data) { 48 | setChannelWave(pianoWaveTable, data); 49 | setChannelVolume(expNegTable, 4); 50 | channel->currentVolume = channel->instrumentVolume; 51 | } 52 | -------------------------------------------------------------------------------- /lcd/lcd1602.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Library for 16x2 characters LCD displays. 3 | * 4 | * Author: Aleksandr Maksymenko aka masyaman 5 | */ 6 | 7 | #include "../utils/concat.h" 8 | 9 | #define LCD_DDR_REGISTER CONCAT2(DDR, LCD_PORT) 10 | #define LCD_PORT_REGISTER CONCAT2(PORT, LCD_PORT) 11 | 12 | #if !defined LCD_PIN_D4 && !defined LCD_PIN_RS && !defined LCD_PIN_EN 13 | #define LCD_PIN_D4 0 14 | #define LCD_PIN_RS 5 15 | #define LCD_PIN_EN 6 16 | #endif 17 | 18 | #define LCD_PIN_DATA_MASK ((1 << LCD_PIN_D4) | (1 << (LCD_PIN_D4 + 1)) | (1 << (LCD_PIN_D4 + 2)) | (1 << (LCD_PIN_D4 + 3))) 19 | #define LCD_PIN_MASK (LCD_PIN_DATA_MASK | (1 << LCD_PIN_EN) | (1 << LCD_PIN_RS)) 20 | 21 | 22 | inline static void __lcd_delay() { 23 | _delay_ms(0.3); 24 | } 25 | 26 | inline static void __lcd_longDelay() { 27 | _delay_ms(4.1); 28 | } 29 | 30 | inline static void __lcd_initDelay() { 31 | _delay_ms(15); 32 | } 33 | 34 | 35 | 36 | inline static void pulseLcd() 37 | { 38 | LCD_PORT_REGISTER |= (1 << LCD_PIN_EN); 39 | LCD_PORT_REGISTER &= ~(1 << LCD_PIN_EN); 40 | __lcd_delay(); 41 | } 42 | 43 | void sendByte(uint8_t byteToSend, uint8_t isData) 44 | { 45 | uint8_t clear = ~LCD_PIN_MASK; 46 | uint8_t dataBit = 0; 47 | if (isData) { 48 | clear |= (1 << LCD_PIN_RS); 49 | dataBit |= (1 << LCD_PIN_RS); 50 | } 51 | 52 | LCD_PORT_REGISTER &= clear; 53 | LCD_PORT_REGISTER |= ((byteToSend >> 4) << LCD_PIN_D4) | dataBit; 54 | pulseLcd(); 55 | 56 | LCD_PORT_REGISTER &= clear; 57 | LCD_PORT_REGISTER |= ((byteToSend & 0x0F) << LCD_PIN_D4) | dataBit; 58 | pulseLcd(); 59 | } 60 | 61 | void cursor(uint8_t row, uint8_t col) 62 | { 63 | uint8_t address; 64 | if (row == 0) { 65 | address = 0; 66 | } else { 67 | address = 0x40; 68 | } 69 | 70 | address |= col; 71 | sendByte(0x80 | address, 0); 72 | // __lcd_longDelay(); 73 | } 74 | 75 | void clearLcdScreen() 76 | { 77 | sendByte(0x01, 0); 78 | __lcd_longDelay(); 79 | sendByte(0x02, 0); 80 | __lcd_longDelay(); 81 | } 82 | 83 | inline static void initLCD() { 84 | 85 | LCD_DDR_REGISTER |= LCD_PIN_MASK; 86 | 87 | __lcd_initDelay(); 88 | 89 | // Send 3 times 8-bit mode and 1 time 4-bit mode 90 | sendByte(0b00110011, 0); 91 | sendByte(0b00110010, 0); 92 | 93 | // Init rest of settings in 4-bit mode 94 | sendByte(0b00101000, 0); 95 | sendByte(0b00001100, 0); 96 | sendByte(0b00000110, 0); 97 | 98 | clearLcdScreen(); 99 | } 100 | 101 | void initChar(uint8_t c, uint8_t* tile) 102 | { 103 | sendByte(0b01000000 | (c << 3), 0); 104 | for (int i = 0; i < 8; i++) { 105 | sendByte(*tile, 1); 106 | tile++; 107 | } 108 | } 109 | 110 | void initCharProgmem(uint8_t c, const uint8_t* tile) 111 | { 112 | sendByte(0b01000000 | (c << 3), 0); 113 | for (int i = 0; i < 8; i++) { 114 | sendByte(pgm_read_byte(tile), 1); 115 | tile++; 116 | } 117 | } 118 | 119 | inline void printChar(char c) 120 | { 121 | sendByte(c, 1); 122 | } 123 | 124 | // TODO add progmem? 125 | void printStr(char *text) 126 | { 127 | char *c; 128 | c = text; 129 | while ((c != 0) && (*c != 0)) { 130 | sendByte(*c, 1); 131 | c++; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /microsound/frequencies.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Constants for notes and frequencies. 3 | * Wave table sample length is required to be defined for correct calculations. 4 | * 5 | * Author: Aleksandr Maksymenko aka masyaman 6 | */ 7 | 8 | #ifndef SAMPLE_LENGTH 9 | #define SAMPLE_LENGTH 256 // Number of samples per period, 2^n 10 | #endif 11 | #define SAMPLE_MASK (SAMPLE_LENGTH - 1) 12 | 13 | #define freqStep(freq) ((uint16_t) (256L * freq * SAMPLE_LENGTH / MICROSOUND_FREQUENCY)) 14 | 15 | #define NOTE_SILENCE 0 16 | #define NOTE_C1 1 17 | #define NOTE_Db1 2 18 | #define NOTE_D1 3 19 | #define NOTE_Eb1 4 20 | #define NOTE_E1 5 21 | #define NOTE_F1 6 22 | #define NOTE_Gb1 7 23 | #define NOTE_G1 8 24 | #define NOTE_Ab1 9 25 | #define NOTE_A1 10 26 | #define NOTE_Bb1 11 27 | #define NOTE_B1 12 28 | #define NOTE_C2 13 29 | #define NOTE_Db2 14 30 | #define NOTE_D2 15 31 | #define NOTE_Eb2 16 32 | #define NOTE_E2 17 33 | #define NOTE_F2 18 34 | #define NOTE_Gb2 19 35 | #define NOTE_G2 20 36 | #define NOTE_Ab2 21 37 | #define NOTE_A2 22 38 | #define NOTE_Bb2 23 39 | #define NOTE_B2 24 40 | #define NOTE_C3 25 41 | #define NOTE_Db3 26 42 | #define NOTE_D3 27 43 | #define NOTE_Eb3 28 44 | #define NOTE_E3 29 45 | #define NOTE_F3 30 46 | #define NOTE_Gb3 31 47 | #define NOTE_G3 32 48 | #define NOTE_Ab3 33 49 | #define NOTE_A3 34 50 | #define NOTE_Bb3 35 51 | #define NOTE_B3 36 52 | #define NOTE_C4 37 53 | #define NOTE_Db4 38 54 | #define NOTE_D4 39 55 | #define NOTE_Eb4 40 56 | #define NOTE_E4 41 57 | #define NOTE_F4 42 58 | #define NOTE_Gb4 43 59 | #define NOTE_G4 44 60 | #define NOTE_Ab4 45 61 | #define NOTE_A4 46 62 | #define NOTE_Bb4 47 63 | #define NOTE_B4 48 64 | #define NOTE_C5 49 65 | #define NOTE_Db5 50 66 | #define NOTE_D5 51 67 | #define NOTE_Eb5 52 68 | #define NOTE_E5 53 69 | #define NOTE_F5 54 70 | #define NOTE_Gb5 55 71 | #define NOTE_G5 56 72 | #define NOTE_Ab5 57 73 | #define NOTE_A5 58 74 | #define NOTE_Bb5 59 75 | #define NOTE_B5 60 76 | #define NOTE_C6 61 77 | 78 | #define NOTE_ARRAY_SIZE 62 79 | const uint16_t frequencies[NOTE_ARRAY_SIZE] PROGMEM = { 80 | 0, 81 | freqStep(32.703), freqStep(34.648), freqStep(36.708), freqStep(38.891), freqStep(41.203), freqStep(43.654), freqStep(46.249), freqStep(48.999), freqStep(51.913), freqStep(55.000), freqStep(58.270), freqStep(61.735), 82 | freqStep(65.406), freqStep(69.296), freqStep(73.416), freqStep(77.782), freqStep(82.407), freqStep(87.307), freqStep(92.499), freqStep(97.999), freqStep(103.826), freqStep(110.000), freqStep(116.541), freqStep(123.471), 83 | freqStep(130.813), freqStep(138.591), freqStep(146.832), freqStep(155.563), freqStep(164.814), freqStep(174.614), freqStep(184.997), freqStep(195.998), freqStep(207.652), freqStep(220.000), freqStep(233.082), freqStep(246.942), 84 | freqStep(261.626), freqStep(277.183), freqStep(293.665), freqStep(311.127), freqStep(329.628), freqStep(349.228), freqStep(369.994), freqStep(391.995), freqStep(415.305), freqStep(440.000), freqStep(466.164), freqStep(493.883), 85 | freqStep(523.251), freqStep(554.365), freqStep(587.330), freqStep(622.254), freqStep(659.255), freqStep(698.456), freqStep(739.989), freqStep(783.991), freqStep(830.609), freqStep(880.000), freqStep(932.328), freqStep(987.767), 86 | freqStep(1046.502)}; 87 | 88 | #define frequency(note) (frequencies[note]) 89 | -------------------------------------------------------------------------------- /microsound/instruments/musicbox.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | const int8_t musicboxWaveTable[] PROGMEM = { 6 | 0, -5, -11, -18, -25, -33, -41, -46, -52, -56, -59, -62, -65, -69, -72, -75, 7 | -79, -83, -86, -88, -90, -90, -90, -90, -89, -89, -89, -90, -91, -91, -92, -92, 8 | -92, -91, -91, -90, -90, -89, -89, -89, -89, -89, -88, -87, -86, -84, -82, -80, 9 | -78, -77, -75, -73, -71, -69, -66, -62, -58, -55, -51, -47, -44, -41, -37, -33, 10 | -28, -23, -16, -9, -2, 4, 10, 15, 20, 25, 30, 36, 41, 48, 55, 62, 11 | 69, 75, 80, 85, 89, 91, 94, 96, 100, 103, 107, 112, 117, 120, 123, 125, 12 | 125, 125, 124, 124, 123, 122, 122, 122, 121, 121, 121, 118, 114, 111, 104, 97, 13 | 91, 85, 79, 73, 69, 65, 60, 54, 49, 41, 33, 25, 17, 9, 2, -2, 14 | -7, -11, -15, -19, -25, -31, -37, -44, -51, -57, -61, -65, -68, -70, -71, -73, 15 | -75, -77, -80, -83, -86, -87, -89, -90, -89, -88, -88, -88, -87, -88, -89, -90, 16 | -91, -92, -93, -92, -91, -91, -90, -89, -88, -88, -88, -87, -87, -86, -84, -81, 17 | -79, -77, -74, -72, -70, -69, -67, -64, -61, -57, -52, -48, -43, -38, -34, -30, 18 | -27, -22, -18, -13, -7, -1, 5, 10, 15, 20, 27, 34, 41, 48, 54, 59, 19 | 63, 67, 70, 74, 77, 82, 87, 92, 98, 104, 108, 112, 115, 116, 117, 118, 20 | 118, 119, 120, 122, 124, 125, 126, 127, 125, 123, 121, 116, 111, 106, 101, 96, 21 | 91, 87, 83, 79, 74, 69, 62, 55, 47, 40, 32, 24, 19, 14, 9, 4 22 | }; 23 | 24 | //// Removed high frequency harmonics 25 | //const int8_t musicboxWaveTable[] PROGMEM = { 26 | // 0, -4, -9, -15, -20, -25, -29, -34, -38, -43, -46, -50, -54, -57, -60, -63, 27 | // -66, -69, -72, -74, -76, -78, -80, -81, -83, -84, -85, -85, -86, -87, -87, -87, 28 | // -87, -87, -87, -87, -86, -86, -85, -84, -83, -82, -81, -80, -78, -77, -75, -73, 29 | // -71, -69, -67, -65, -62, -59, -56, -53, -50, -46, -42, -39, -35, -31, -27, -22, 30 | // -18, -13, -8, -3, 0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 31 | // 59, 64, 69, 73, 77, 81, 84, 88, 91, 94, 97, 99, 102, 104, 106, 107, 32 | // 108, 108, 108, 108, 108, 107, 106, 105, 103, 102, 99, 97, 94, 91, 87, 83, 33 | // 79, 75, 71, 67, 62, 58, 53, 48, 42, 37, 32, 26, 20, 15, 9, 4, 34 | // 0, -6, -11, -15, -20, -25, -30, -34, -39, -43, -47, -50, -54, -57, -60, -63, 35 | // -65, -68, -70, -73, -75, -77, -79, -80, -82, -83, -84, -84, -85, -86, -86, -86, 36 | // -87, -87, -86, -86, -86, -85, -85, -84, -83, -82, -81, -80, -78, -77, -75, -74, 37 | // -72, -70, -67, -65, -62, -60, -57, -54, -50, -47, -44, -40, -36, -32, -28, -23, 38 | // -19, -15, -10, -6, -1, 2, 7, 12, 17, 22, 27, 32, 37, 42, 46, 51, 39 | // 55, 60, 64, 68, 72, 76, 80, 84, 88, 91, 94, 97, 99, 101, 102, 104, 40 | // 105, 105, 106, 106, 106, 106, 105, 104, 103, 101, 99, 97, 94, 91, 87, 84, 41 | // 80, 77, 73, 69, 64, 59, 54, 49, 44, 38, 33, 27, 22, 16, 11, 5, 42 | // }; 43 | 44 | const uint8_t musicboxVolumeTable[] PROGMEM = { 45 | 255, 226, 199, 191, 184, 160, 163, 178, 177, 166, 158, 156, 147, 141, 135, 131, 46 | 124, 118, 113, 107, 100, 95, 90, 85, 80, 75, 71, 67, 63, 59, 55, 51, 47 | 48, 45, 43, 40, 39, 36, 34, 30, 28, 27, 25, 24, 23, 22, 22, 20, 48 | 18, 18, 17, 16, 16, 15, 14, 14, 13, 12, 12, 11, 11, 10, 9, 9, 49 | 8,7,6,5,4,3,2,1,0}; 50 | 51 | void playMusicbox(waveChannel* channel, uint8_t data) { 52 | setChannelWave(musicboxWaveTable, data); 53 | setChannelVolume(musicboxVolumeTable, 4); 54 | channel->currentVolume = channel->instrumentVolume; 55 | } 56 | -------------------------------------------------------------------------------- /microsound/micromusic.h: -------------------------------------------------------------------------------- 1 | #ifndef MICROMUSIC_INIT 2 | #define MICROMUSIC_INIT 3 | 4 | /* 5 | * Control flow of music data and translate this data to sound generator. 6 | * 7 | * Simplified usage: 8 | * initMusic(); // Init music data and sound control 9 | * sei(); // Enable interrupts, silence sound should be generated 10 | * setSample(0, instrument1); // Use instrument1 as sample 0 11 | * setSample(1, instrument2); // Init all other instruments... 12 | * 13 | * playMusic(mySong); // Start playing music at pointer mySong 14 | * while (!isMusicStopped) fillMusicBuffer(); // Fill music buffer in loop 15 | * 16 | * Author: Aleksandr Maksymenko aka masyaman 17 | */ 18 | 19 | #include "microsound.h" 20 | 21 | 22 | typedef void (*sampleSource)(waveChannel* channel, uint8_t data); 23 | 24 | // SAMPLES_SIZE - amount of different instruments 25 | // CHANNELS_SIZE - amount of simultaneously played channels, managed by microsound.h 26 | sampleSource samples[SAMPLES_SIZE]; 27 | sampleSource channelSamples[CHANNELS_SIZE]; 28 | 29 | const uint8_t *musicData; 30 | uint16_t nextBeat; 31 | uint8_t isMusicStopped; 32 | 33 | 34 | // Init music and sound 35 | inline void initMusic() { 36 | initSound(); 37 | nextBeat = 0; 38 | isMusicStopped = 1; 39 | } 40 | 41 | // Assign instrument to specific id 42 | inline void setSample(uint8_t id, sampleSource sample) { 43 | samples[id] = sample; 44 | } 45 | 46 | // Play music data from specified array 47 | INLINE_SOUND_CONTROL void playMusic(const uint8_t *data) { 48 | resetSound(); 49 | musicData = data; 50 | nextBeat = 0; 51 | isMusicStopped = 0; 52 | } 53 | 54 | inline void stopMusic() { 55 | isMusicStopped = 1; 56 | resetSound(); 57 | } 58 | 59 | #include "commands.h" 60 | 61 | // Update channels data from music array 62 | INLINE_BUFFER_FILL 63 | void updateMusicData() { 64 | if (isMusicStopped) { 65 | return; 66 | } 67 | while (beatCounter >= nextBeat) { 68 | uint8_t data = pgm_read_byte(musicData++); 69 | if (data & COMMAND_PLAY) { 70 | // 2 bytes [CWWWHHHH][NNNNNNNN]: C: command, HHHH: channelId, NNNNNNNN: note, WWW: wait 71 | uint8_t channel = data & 0b1111; 72 | uint8_t wait = (data >> 4) & 0b111; 73 | addChannelToZeroSample(channels[channel]); // Optional declick code 74 | data = pgm_read_byte(musicData++); 75 | channelSamples[channel](channels[channel], data); 76 | nextBeat += wait; 77 | } else if (data & COMMAND_WAIT) { 78 | // 1 byte [CCWWWWWW]: CC: command, WWWWWW: wait 79 | nextBeat += data & 0b00111111; 80 | } else if (data & COMMAND_VOLUME) { 81 | // 2 bytes [CCC_HHHH][VVVVVVVV]: CCC: command, HHHH: channelId, VVVVVVVV: volume 82 | setVolume(data & 0b00001111, pgm_read_byte(musicData++)); 83 | } else if (data & COMMAND_INSTRUMENT) { 84 | // 2 bytes [CCCCHHHH][SSSSSSSS]: CCCC: command, HHHH: channelId, SSSSSSSS: sample 85 | channelSamples[data & 0b00001111] = samples[pgm_read_byte(musicData++)]; 86 | } else if (data & COMMAND_TEMPO) { 87 | // 3 bytes [CCCCCCCC][TTTTTTTT][TTTTTTTT]: C: command, T: bpm increment counter 88 | uint16_t bpm = pgm_read_byte(musicData++) << 8; 89 | bpm += pgm_read_byte(musicData++); 90 | setBpm(bpm); 91 | } else { 92 | // COMMAND_END 93 | stopMusic(); 94 | break; 95 | } 96 | } 97 | } 98 | 99 | // Fill buffer until it's full 100 | inline void fillMusicBuffer() { 101 | // Smaller value requires bigger overhead for writing remain of the buffer 102 | while ((samplesToWrite) > 4) { 103 | fillBuffer(SAMPLES_PER_TICK); 104 | updateMusicData(); 105 | } 106 | } 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /microsound/samples/notifications_four_channels.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Various samples, used mostly for notifications. 3 | * All samples here used 3 or 4 sound channels. 4 | * 5 | * Author: Aleksandr Maksymenko aka masyaman 6 | */ 7 | 8 | #if CHANNELS_SIZE < 4 9 | #warning "Included music file requires 4 channels" 10 | #endif 11 | 12 | 13 | #if defined SAMPLE_MUSICBOX 14 | 15 | const uint8_t chordC4[] PROGMEM = { 16 | DATA_TEMPO(800), 17 | DATA_INSTRUMENT(0, SAMPLE_MUSICBOX), 18 | DATA_INSTRUMENT(1, SAMPLE_MUSICBOX), 19 | DATA_INSTRUMENT(2, SAMPLE_MUSICBOX), 20 | DATA_VOLUME(0, 80), 21 | DATA_VOLUME(1, 80), 22 | DATA_VOLUME(2, 80), 23 | 24 | DATA_PLAY(0, NOTE_C4, 1), 25 | DATA_PLAY(1, NOTE_E4, 1), 26 | DATA_PLAY(2, NOTE_G4, 1), 27 | 28 | DATA_WAIT(15), 29 | DATA_END() 30 | }; 31 | const uint8_t chordC4back[] PROGMEM = { 32 | DATA_TEMPO(800), 33 | DATA_INSTRUMENT(0, SAMPLE_MUSICBOX), 34 | DATA_INSTRUMENT(1, SAMPLE_MUSICBOX), 35 | DATA_INSTRUMENT(2, SAMPLE_MUSICBOX), 36 | DATA_VOLUME(0, 80), 37 | DATA_VOLUME(1, 80), 38 | DATA_VOLUME(2, 80), 39 | 40 | DATA_PLAY(2, NOTE_G4, 1), 41 | DATA_PLAY(1, NOTE_E4, 1), 42 | DATA_PLAY(0, NOTE_C4, 1), 43 | 44 | DATA_WAIT(15), 45 | DATA_END() 46 | }; 47 | 48 | const uint8_t chordC5[] PROGMEM = { 49 | DATA_TEMPO(800), 50 | DATA_INSTRUMENT(0, SAMPLE_MUSICBOX), 51 | DATA_INSTRUMENT(1, SAMPLE_MUSICBOX), 52 | DATA_INSTRUMENT(2, SAMPLE_MUSICBOX), 53 | DATA_VOLUME(0, 80), 54 | DATA_VOLUME(1, 80), 55 | DATA_VOLUME(2, 80), 56 | 57 | DATA_PLAY(0, NOTE_C5, 1), 58 | DATA_PLAY(1, NOTE_E5, 1), 59 | DATA_PLAY(2, NOTE_G5, 1), 60 | 61 | DATA_WAIT(15), 62 | DATA_END() 63 | }; 64 | const uint8_t chordC5back[] PROGMEM = { 65 | DATA_TEMPO(800), 66 | DATA_INSTRUMENT(0, SAMPLE_MUSICBOX), 67 | DATA_INSTRUMENT(1, SAMPLE_MUSICBOX), 68 | DATA_INSTRUMENT(2, SAMPLE_MUSICBOX), 69 | DATA_VOLUME(0, 80), 70 | DATA_VOLUME(1, 80), 71 | DATA_VOLUME(2, 80), 72 | 73 | DATA_PLAY(0, NOTE_G5, 1), 74 | DATA_PLAY(1, NOTE_E5, 1), 75 | DATA_PLAY(2, NOTE_C5, 1), 76 | 77 | DATA_WAIT(15), 78 | DATA_END() 79 | }; 80 | 81 | const uint8_t harp[] PROGMEM = { 82 | DATA_TEMPO(480), 83 | DATA_INSTRUMENT(0, SAMPLE_MUSICBOX), 84 | DATA_INSTRUMENT(1, SAMPLE_MUSICBOX), 85 | DATA_INSTRUMENT(2, SAMPLE_MUSICBOX), 86 | DATA_INSTRUMENT(3, SAMPLE_MUSICBOX), 87 | DATA_VOLUME(0, 64), 88 | DATA_VOLUME(1, 64), 89 | DATA_VOLUME(2, 64), 90 | DATA_VOLUME(3, 64), 91 | 92 | DATA_PLAY(0, NOTE_G5, 1), 93 | DATA_PLAY(1, NOTE_E5, 1), 94 | DATA_PLAY(2, NOTE_D5, 1), 95 | DATA_PLAY(3, NOTE_C5, 1), 96 | DATA_PLAY(1, NOTE_A4, 1), 97 | DATA_PLAY(2, NOTE_G4, 1), 98 | 99 | DATA_PLAY(0, NOTE_E5, 1), 100 | DATA_PLAY(3, NOTE_D5, 1), 101 | DATA_PLAY(1, NOTE_C5, 1), 102 | DATA_PLAY(2, NOTE_A4, 1), 103 | DATA_PLAY(3, NOTE_G4, 1), 104 | DATA_PLAY(1, NOTE_E4, 1), 105 | 106 | DATA_PLAY(0, NOTE_D5, 1), 107 | DATA_PLAY(2, NOTE_C5, 1), 108 | DATA_PLAY(3, NOTE_A4, 1), 109 | DATA_PLAY(1, NOTE_G4, 1), 110 | 111 | DATA_PLAY(0, NOTE_G5, 1), 112 | DATA_PLAY(2, NOTE_E5, 1), 113 | DATA_PLAY(3, NOTE_D5, 1), 114 | DATA_PLAY(1, NOTE_C5, 1), 115 | DATA_PLAY(2, NOTE_A4, 1), 116 | 117 | DATA_PLAY(0, NOTE_E5, 1), 118 | DATA_PLAY(3, NOTE_D5, 1), 119 | DATA_PLAY(1, NOTE_C5, 1), 120 | DATA_PLAY(2, NOTE_A4, 1), 121 | DATA_PLAY(3, NOTE_G4, 1), 122 | DATA_PLAY(1, NOTE_E4, 1), 123 | 124 | DATA_PLAY(0, NOTE_D5, 1), 125 | DATA_PLAY(2, NOTE_C5, 1), 126 | DATA_PLAY(3, NOTE_A4, 1), 127 | DATA_PLAY(1, NOTE_G4, 1), 128 | DATA_PLAY(2, NOTE_E4, 1), 129 | DATA_PLAY(3, NOTE_D4, 1), 130 | DATA_PLAY(1, NOTE_C4, 1), 131 | 132 | DATA_PLAY(0, NOTE_A4, 1), 133 | DATA_PLAY(2, NOTE_G4, 1), 134 | DATA_PLAY(3, NOTE_E4, 1), 135 | DATA_PLAY(1, NOTE_D4, 1), 136 | DATA_PLAY(2, NOTE_C4, 1), 137 | DATA_PLAY(3, NOTE_A3, 1), 138 | 139 | DATA_WAIT(8), 140 | DATA_END() 141 | }; 142 | #endif 143 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Microsound 2 | 3 | Microsound is a sound generation engine for 8-bits AVR microcontroller based on wave table. 4 | 5 | Engine is designed for small firmware size (2-8 kBytes depending on included instruments) and 6 | is able to play up to 5 notes simultaneously plus one noise channel on 8MHz MCU with hardware 7 | multiplication. ATtiny MCUs does not have hardware multiplication so performance is approximately 8 | 2 times slower. This means that ATtiny should use less channels or use higher frequency. 9 | 10 | Supported MCUs are: 11 | - ATmega8 12 | - ATmega328p (usually used in Arduino) 13 | - ATmega48/88/168 (compatible with 328p) 14 | - ATtiny25/45/85 15 | - ATtiny261/461/861 16 | - ATtiny26 17 | 18 | Even through 2kBytes MCUs are supported it's strongly recommended to use 4+kBytes MCUs. 19 | 20 | # Software requirements 21 | 22 | Code is writtenn in c with some inline assebler for ATtiny devices. Tools are used to build demos: 23 | - `make` as build system 24 | - `avr-gcc` as compiler 25 | - `avrdude` as MCU flashing tool 26 | 27 | To build and flash MCU: 28 | ``` 29 | make clean hex 30 | make program 31 | ``` 32 | 33 | # Dir structure 34 | 35 | Project has the following dir structure: 36 | - microsound: main codebase for sound generator. 37 | - - devices: different drivers for MCUs. There can be several different drivers for the same MCU, e.g. 38 | for different timer usage. 39 | - - instruments: wavetable samples. 40 | - - samples: examples of sound effects and melodies. 41 | - utils: various utils used by microsound engine. 42 | - demos: demos for different MCUs. Most of demos contain minimal examples for building working example. 43 | - lcd: driver for LCD display used in some demos. 44 | - buttons: driver for buttons used in some demos. 45 | 46 | # Usage 47 | 48 | Basic usage contains of several steps: 49 | ``` 50 | // Include driver for your MCU and micromusic engine: 51 | #include "../../microsound/devices/atmega8timer1.h" 52 | #include "../../microsound/micromusic.h" 53 | 54 | // Make some settings 55 | #define CHANNELS_SIZE 5 56 | #define SAMPLES_SIZE 16 57 | #define USE_NOISE_CHANNEL 58 | 59 | initMusic(); // Init music data and sound control 60 | sei(); // Enable interrupts, silence sound should be generated 61 | setSample(0, instrument1); // Use instrument1 as sample 0 62 | setSample(1, instrument2); // Init all other instruments... 63 | 64 | playMusic(mySong); // Start playing music at pointer mySong 65 | while (!isMusicStopped) { 66 | fillMusicBuffer(); // Fill music buffer in loop 67 | // Do some other stuff 68 | } 69 | 70 | ``` 71 | 72 | Song data should contain the following: 73 | ``` 74 | // Init byte array in PROGMEM memory space: 75 | const uint8_t demoSample[] PROGMEM = { 76 | DATA_TEMPO(160), // Set beats per minute 77 | DATA_INSTRUMENT(0, 1), // Assign instrument 1 (see setSample) to channel 0 78 | DATA_INSTRUMENT(1, 1), // Assign instrument 1 (see setSample) to channel 1 79 | DATA_VOLUME(0, 128), // Set volume 128 to channel 0 80 | DATA_VOLUME(1, 128), // Set volume 128 to channel 1 81 | DATA_PLAY(0, NOTE_A4, 1), // Play note A4 on channel 0 and wait 1 beat 82 | DATA_PLAY(1, NOTE_A3, 1), // Play note A3 on channel 1 and wait 1 beat 83 | DATA_WAIT(63), // Wait 63 beats 84 | DATA_END() // End of data stream 85 | }; 86 | ``` 87 | 88 | Commands are packed into 1-3 bytes and has some limitations: 89 | - DATA_VOLUME accepts volume values in range [0..255] or [0..127] in some software 90 | multiplication implementations for ATtiny. 91 | - DATA_PLAY accepts wait values in range [0..7]. 92 | - DATA_WAIT accepts wait values in range [0..63]. 93 | 94 | For more detailed information see `demos` and `micromusic/commands.h`. 95 | 96 | # Writing own melodies 97 | 98 | There is a port of microsound engine to JavaScript `demos/wavepot.js`. 99 | This port can be used to play byte stream on site wavepot.com. This port does *not* have limitations 100 | described above, so stream may not be played properly on MCU if these limitations does not meet requirements. 101 | Also this port may produce slightly better sound quality. To simulate 8-bits sound similar to c engine 102 | set variable `simulate8bits` to `true`. 103 | -------------------------------------------------------------------------------- /microsound/samples/notifications_single_channel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Various samples, used mostly for notifications. 3 | * All samples here used only one sound channel. 4 | * 5 | * Author: Aleksandr Maksymenko aka masyaman 6 | */ 7 | 8 | #ifndef SINGLE_CHANNEL_VOLUME 9 | #define SINGLE_CHANNEL_VOLUME 255 10 | #endif 11 | 12 | #if defined SAMPLE_PIANO 13 | const uint8_t phonecall[] PROGMEM = { 14 | DATA_TEMPO(1600), 15 | DATA_INSTRUMENT(0, SAMPLE_PIANO), 16 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME), 17 | DATA_PLAY(0, NOTE_A3, 1), 18 | DATA_PLAY(0, NOTE_A4, 1), 19 | DATA_PLAY(0, NOTE_A3, 1), 20 | DATA_PLAY(0, NOTE_A4, 1), 21 | DATA_PLAY(0, NOTE_A3, 1), 22 | DATA_PLAY(0, NOTE_A4, 1), 23 | DATA_PLAY(0, NOTE_A3, 1), 24 | DATA_PLAY(0, NOTE_A4, 1), 25 | DATA_PLAY(0, NOTE_A3, 1), 26 | DATA_PLAY(0, NOTE_A4, 1), 27 | DATA_PLAY(0, NOTE_A3, 1), 28 | DATA_PLAY(0, NOTE_A4, 1), 29 | DATA_PLAY(0, NOTE_A3, 1), 30 | DATA_PLAY(0, NOTE_A4, 1), 31 | DATA_PLAY(0, NOTE_A3, 1), 32 | DATA_PLAY(0, NOTE_A4, 1), 33 | DATA_PLAY(0, NOTE_A3, 1), 34 | DATA_PLAY(0, NOTE_A4, 1), 35 | DATA_PLAY(0, NOTE_A3, 1), 36 | DATA_PLAY(0, NOTE_A4, 1), 37 | DATA_PLAY(0, NOTE_A3, 1), 38 | DATA_PLAY(0, NOTE_A4, 1), 39 | DATA_PLAY(0, NOTE_A3, 1), 40 | DATA_PLAY(0, NOTE_A4, 1), 41 | DATA_PLAY(0, NOTE_A3, 1), 42 | DATA_PLAY(0, NOTE_A4, 1), 43 | DATA_PLAY(0, NOTE_A3, 1), 44 | DATA_PLAY(0, NOTE_A4, 1), 45 | DATA_PLAY(0, NOTE_A3, 1), 46 | DATA_PLAY(0, NOTE_A4, 1), 47 | DATA_PLAY(0, NOTE_A3, 1), 48 | DATA_PLAY(0, NOTE_A4, 1), 49 | DATA_PLAY(0, NOTE_A3, 1), 50 | DATA_PLAY(0, NOTE_A4, 1), 51 | DATA_PLAY(0, NOTE_A3, 1), 52 | DATA_PLAY(0, NOTE_A4, 1), 53 | DATA_PLAY(0, NOTE_A3, 1), 54 | DATA_PLAY(0, NOTE_A4, 1), 55 | DATA_PLAY(0, NOTE_A3, 1), 56 | DATA_PLAY(0, NOTE_A4, 1), 57 | DATA_VOLUME(0, 0), 58 | DATA_WAIT(63), 59 | DATA_END() 60 | }; 61 | #endif 62 | 63 | 64 | #if defined SAMPLE_SYNTH_PIANO 65 | const uint8_t attentionNotification[] PROGMEM = { 66 | DATA_TEMPO(140), 67 | DATA_INSTRUMENT(0, SAMPLE_SYNTH_PIANO), 68 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME), 69 | 70 | DATA_PLAY(0, NOTE_D5, 1), 71 | DATA_PLAY(0, NOTE_C5, 1), 72 | DATA_PLAY(0, NOTE_A4, 4), 73 | 74 | // DATA_VOLUME(0, 0), 75 | // DATA_WAIT(4), 76 | DATA_END() 77 | }; 78 | #endif 79 | 80 | #if defined SAMPLE_HARMONICA 81 | const uint8_t harmonicaNotification[] PROGMEM = { 82 | DATA_TEMPO(800), 83 | DATA_INSTRUMENT(0, SAMPLE_HARMONICA), 84 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME), 85 | DATA_PLAY(0, NOTE_C5, 1), 86 | DATA_PLAY(0, NOTE_E5, 1), 87 | DATA_PLAY(0, NOTE_G5, 1), 88 | DATA_PLAY(0, NOTE_E5, 1), 89 | DATA_PLAY(0, NOTE_C5, 1), 90 | // DATA_VOLUME(0, 0), 91 | // DATA_WAIT(16), 92 | DATA_END() 93 | }; 94 | 95 | const uint8_t looserNotification[] PROGMEM = { 96 | DATA_TEMPO(320), 97 | DATA_INSTRUMENT(0, SAMPLE_HARMONICA), 98 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME), 99 | 100 | DATA_PLAY(0, NOTE_A4, 1), 101 | DATA_PLAY(0, NOTE_G4, 1), 102 | DATA_PLAY(0, NOTE_F4, 1), 103 | DATA_PLAY(0, NOTE_E4, 1), 104 | 105 | DATA_TEMPO(640), 106 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.8), 107 | DATA_WAIT(1), 108 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.81), 109 | DATA_WAIT(1), 110 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.6), 111 | DATA_WAIT(1), 112 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.61), 113 | DATA_WAIT(1), 114 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.4), 115 | DATA_WAIT(1), 116 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.41), 117 | DATA_WAIT(1), 118 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.2), 119 | DATA_WAIT(1), 120 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.21), 121 | DATA_WAIT(1), 122 | 123 | // DATA_VOLUME(0, 0), 124 | // DATA_WAIT(16), 125 | DATA_END() 126 | }; 127 | #endif 128 | 129 | #if defined SAMPLE_OVERDRIVE 130 | const uint8_t guitarNotification[] PROGMEM = { 131 | DATA_TEMPO(240), 132 | DATA_INSTRUMENT(0, SAMPLE_OVERDRIVE), 133 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME), 134 | DATA_PLAY(0, NOTE_A2 | OVERDRIVE_SHORT, 1), 135 | DATA_PLAY(0, NOTE_A2 | OVERDRIVE_SHORT, 1), 136 | DATA_PLAY(0, NOTE_A2, 1), 137 | DATA_PLAY(0, NOTE_C3 | OVERDRIVE_SHORT, 1), 138 | DATA_PLAY(0, NOTE_A2 | OVERDRIVE_SHORT, 1), 139 | DATA_PLAY(0, NOTE_C3, 2), 140 | 141 | DATA_TEMPO(1600), 142 | 143 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.8), 144 | DATA_WAIT(1), 145 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.6), 146 | DATA_WAIT(1), 147 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.4), 148 | DATA_WAIT(1), 149 | DATA_VOLUME(0, SINGLE_CHANNEL_VOLUME * 0.2), 150 | DATA_WAIT(1), 151 | 152 | // DATA_VOLUME(0, 0), 153 | // DATA_TEMPO(240), 154 | // DATA_WAIT(8), 155 | DATA_END() 156 | }; 157 | #endif 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /demos/attiny26/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef F_CPU 11 | #define F_CPU 16000000 12 | #endif 13 | 14 | //#define SAMPLE_LENGTH 64 15 | 16 | #define SAMPLE_MUSICBOX 0 17 | 18 | #define INLINE_BUFFER_FILL inline 19 | #define INLINE_SOUND_CONTROL inline 20 | #define INLINE_MULTIPLICATION_SIGNED_UNSIGNED // do not inline 21 | #define INLINE_WAVETABLE_SOUND_GENERATOR // do not inline 22 | #define SPEED_OPTIMIZED_MULTIPLICATION 23 | #define SIMPLIFIED_MULTIPLICATION 24 | 25 | #define MICROSOUND_STATIC_VOLUME 2 // Use simplified sound control with common volume for all channels 26 | //#define BUFFER_BITS 16 27 | //#define BUFFER_SIZE 64 28 | #define MICROSOUND_FREQUENCY_DIVIDER 2 29 | //#define INTERPOLATION_STRENGTH 2 30 | //#define INTERPOLATE_WAVE 31 | #define CHANNELS_SIZE 4 32 | #define SAMPLES_SIZE 1 33 | //#define USE_NOISE_CHANNEL 34 | 35 | #include "../../microsound/devices/attiny26timers01.h" 36 | #include "../../microsound/micromusic.h" 37 | 38 | #include "../../microsound/instruments/musicbox.h" 39 | 40 | const uint8_t test[] PROGMEM = { 41 | DATA_TEMPO(480), 42 | DATA_INSTRUMENT(0, SAMPLE_MUSICBOX), 43 | DATA_INSTRUMENT(1, SAMPLE_MUSICBOX), 44 | DATA_INSTRUMENT(2, SAMPLE_MUSICBOX), 45 | DATA_INSTRUMENT(3, SAMPLE_MUSICBOX), 46 | // DATA_VOLUME(0, 80), 47 | // DATA_VOLUME(1, 80), 48 | // DATA_VOLUME(2, 80), 49 | // DATA_VOLUME(3, 80), 50 | 51 | DATA_PLAY(0, NOTE_E5, 2), 52 | DATA_PLAY(1, NOTE_Eb5, 2), 53 | // 10 54 | DATA_PLAY(0, NOTE_E5, 2), 55 | DATA_PLAY(1, NOTE_Eb5, 2), 56 | DATA_PLAY(0, NOTE_E5, 2), 57 | DATA_PLAY(2, NOTE_B4, 2), 58 | DATA_PLAY(3, NOTE_D5, 2), 59 | DATA_PLAY(0, NOTE_C5, 2), 60 | // 11 61 | DATA_PLAY(1, NOTE_A4, 0), 62 | DATA_PLAY(2, NOTE_A2, 2), 63 | DATA_PLAY(3, NOTE_E3, 2), 64 | DATA_PLAY(0, NOTE_A3, 2), 65 | DATA_PLAY(1, NOTE_C4, 2), 66 | DATA_PLAY(2, NOTE_E4, 2), 67 | DATA_PLAY(3, NOTE_A4, 2), 68 | // 12 69 | DATA_PLAY(0, NOTE_B4, 0), 70 | DATA_PLAY(1, NOTE_E2, 2), 71 | DATA_PLAY(2, NOTE_E3, 2), 72 | DATA_PLAY(3, NOTE_Ab3, 2), 73 | DATA_PLAY(0, NOTE_E4, 2), 74 | DATA_PLAY(1, NOTE_Ab4, 2), 75 | DATA_PLAY(2, NOTE_B4, 2), 76 | // 13 77 | DATA_PLAY(3, NOTE_C5, 0), 78 | DATA_PLAY(0, NOTE_A2, 2), 79 | DATA_PLAY(1, NOTE_E3, 2), 80 | DATA_PLAY(2, NOTE_A3, 2), 81 | DATA_PLAY(3, NOTE_E4, 2), 82 | DATA_PLAY(0, NOTE_E5, 2), 83 | DATA_PLAY(1, NOTE_Eb5, 2), 84 | // 14 85 | DATA_PLAY(0, NOTE_E5, 2), 86 | DATA_PLAY(1, NOTE_Eb5, 2), 87 | DATA_PLAY(0, NOTE_E5, 2), 88 | DATA_PLAY(2, NOTE_B4, 2), 89 | DATA_PLAY(3, NOTE_D5, 2), 90 | DATA_PLAY(0, NOTE_C5, 2), 91 | // 15 92 | DATA_PLAY(1, NOTE_A4, 0), 93 | DATA_PLAY(2, NOTE_A2, 2), 94 | DATA_PLAY(3, NOTE_E3, 2), 95 | DATA_PLAY(0, NOTE_A3, 2), 96 | DATA_PLAY(1, NOTE_C4, 2), 97 | DATA_PLAY(2, NOTE_E4, 2), 98 | DATA_PLAY(3, NOTE_A4, 2), 99 | // 16 100 | DATA_PLAY(0, NOTE_B4, 0), 101 | DATA_PLAY(1, NOTE_E2, 2), 102 | DATA_PLAY(2, NOTE_E3, 2), 103 | DATA_PLAY(3, NOTE_Ab3, 2), 104 | DATA_PLAY(0, NOTE_E4, 2), 105 | DATA_PLAY(1, NOTE_C5, 2), 106 | DATA_PLAY(2, NOTE_B4, 2), 107 | // 17 108 | DATA_PLAY(3, NOTE_A4, 0), 109 | DATA_PLAY(0, NOTE_A2, 2), 110 | DATA_PLAY(1, NOTE_E3, 2), 111 | DATA_PLAY(2, NOTE_A3, 2), 112 | DATA_PLAY(3, NOTE_B4, 2), 113 | DATA_PLAY(0, NOTE_C5, 2), 114 | DATA_PLAY(1, NOTE_D5, 2), 115 | // 18 116 | DATA_PLAY(2, NOTE_E5, 0), 117 | DATA_PLAY(3, NOTE_C3, 2), 118 | DATA_PLAY(0, NOTE_G3, 2), 119 | DATA_PLAY(1, NOTE_C4, 2), 120 | DATA_PLAY(2, NOTE_G4, 2), 121 | DATA_PLAY(3, NOTE_F5, 2), 122 | DATA_PLAY(0, NOTE_E5, 2), 123 | // 19 124 | DATA_PLAY(1, NOTE_D5, 0), 125 | DATA_PLAY(2, NOTE_G2, 2), 126 | DATA_PLAY(3, NOTE_G3, 2), 127 | DATA_PLAY(0, NOTE_A3, 2), 128 | DATA_PLAY(1, NOTE_F4, 2), 129 | DATA_PLAY(2, NOTE_E5, 2), 130 | DATA_PLAY(3, NOTE_D5, 2), 131 | // 20 132 | DATA_PLAY(0, NOTE_C5, 0), 133 | DATA_PLAY(1, NOTE_A2, 2), 134 | DATA_PLAY(2, NOTE_E3, 2), 135 | DATA_PLAY(3, NOTE_A3, 2), 136 | DATA_PLAY(0, NOTE_E4, 2), 137 | DATA_PLAY(1, NOTE_D5, 2), 138 | DATA_PLAY(2, NOTE_C5, 2), 139 | // 21 140 | DATA_PLAY(3, NOTE_B4, 0), 141 | DATA_PLAY(0, NOTE_E2, 2), 142 | DATA_PLAY(1, NOTE_E3, 2), 143 | DATA_PLAY(2, NOTE_E4, 2), 144 | DATA_PLAY(2, NOTE_E4, 2), 145 | DATA_PLAY(3, NOTE_E5, 2), 146 | DATA_PLAY(2, NOTE_E4, 2), 147 | 148 | // DATA_WAIT(16), 149 | 150 | DATA_END() 151 | }; 152 | 153 | int main(void) 154 | { 155 | initMusic(); 156 | setSample(SAMPLE_MUSICBOX, playMusicbox); 157 | 158 | sei(); 159 | 160 | // DDRB |= 0x10; 161 | while (1) { 162 | 163 | // PORTB |= 0x10; 164 | fillMusicBuffer(); 165 | // PORTB &= ~0x10; 166 | 167 | // Simulate other CPU usage 168 | // while (samplesInBuffer > 4) {}; 169 | 170 | if (isMusicStopped) { 171 | playMusic(test); 172 | } 173 | 174 | 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /microsound/samples/oh_susanna.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #if CHANNELS_SIZE < 4 6 | #warning "Included music file requires 4 channels" 7 | #endif 8 | 9 | #define PERC 0 10 | #define HRMN 1 11 | #define BASS 2 12 | #define OVRD 3 13 | 14 | const uint8_t ohSusannaSong[] PROGMEM = { 15 | DATA_TEMPO(480), 16 | DATA_INSTRUMENT(PERC, SAMPLE_PERCUSSION), 17 | DATA_INSTRUMENT(BASS, SAMPLE_BASS), 18 | DATA_INSTRUMENT(HRMN, SAMPLE_HARMONICA), 19 | DATA_INSTRUMENT(OVRD, SAMPLE_OVERDRIVE), 20 | DATA_VOLUME(PERC, 100), 21 | DATA_VOLUME(HRMN, 64), 22 | DATA_VOLUME(BASS, 32), 23 | DATA_VOLUME(OVRD, 64), 24 | 25 | 26 | // DATA_PLAY(PERC, PERCUSSION_HAT_H, 1), 27 | // DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 28 | // DATA_PLAY(PERC, PERCUSSION_BAR_H, 1), 29 | // DATA_PLAY(PERC, PERCUSSION_BAR_L, 1), 30 | // DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 31 | // DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 32 | // DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 33 | // DATA_PLAY(PERC, PERCUSSION_BAR_L, 2), 34 | // DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 35 | // DATA_END(), 36 | 37 | DATA_PLAY(HRMN, NOTE_C4, 1), 38 | DATA_PLAY(HRMN, NOTE_D4, 0), 39 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 40 | 41 | DATA_PLAY(HRMN, NOTE_E4, 0), 42 | DATA_PLAY(BASS, NOTE_C2, 0), 43 | DATA_PLAY(PERC, PERCUSSION_BAR_L, 2), 44 | DATA_PLAY(HRMN, NOTE_G4, 0), 45 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 46 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 47 | DATA_PLAY(HRMN, NOTE_G4, 0), 48 | DATA_PLAY(OVRD, NOTE_C3, 0), 49 | DATA_PLAY(BASS, NOTE_E2, 0), 50 | DATA_PLAY(PERC, PERCUSSION_BAR_L, 3), 51 | DATA_PLAY(HRMN, NOTE_A4, 0), 52 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 53 | 54 | DATA_PLAY(HRMN, NOTE_G4, 0), 55 | DATA_PLAY(BASS, NOTE_C2, 0), 56 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 57 | DATA_PLAY(HRMN, NOTE_E4, 0), 58 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 59 | DATA_PLAY(PERC, PERCUSSION_BAR_L, 2), 60 | DATA_PLAY(HRMN, NOTE_C4, 0), 61 | DATA_PLAY(OVRD, NOTE_C3, 0), 62 | DATA_PLAY(BASS, NOTE_G1, 0), 63 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 3), 64 | DATA_PLAY(HRMN, NOTE_D4, 1), 65 | 66 | DATA_PLAY(HRMN, NOTE_E4, 0), 67 | DATA_PLAY(BASS, NOTE_C2, 0), 68 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 69 | DATA_PLAY(HRMN, NOTE_E4, 0), 70 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 71 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 72 | DATA_PLAY(HRMN, NOTE_D4, 0), 73 | DATA_PLAY(OVRD, NOTE_C3, 0), 74 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 75 | DATA_PLAY(HRMN, NOTE_C4, 0), 76 | DATA_PLAY(OVRD, NOTE_G3 | OVERDRIVE_SHORT, 0), 77 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 78 | 79 | 80 | DATA_PLAY(HRMN, NOTE_D4, 0), 81 | DATA_PLAY(OVRD, NOTE_G3, 0), // check this 82 | DATA_PLAY(BASS, NOTE_G2, 0), 83 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 84 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 85 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 86 | DATA_PLAY(HRMN, NOTE_C4, 1), 87 | DATA_PLAY(HRMN, NOTE_D4, 0), 88 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 89 | 90 | DATA_PLAY(HRMN, NOTE_E4, 0), 91 | DATA_PLAY(BASS, NOTE_C2, 0), 92 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 93 | DATA_PLAY(HRMN, NOTE_G4, 0), 94 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 95 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 96 | DATA_PLAY(HRMN, NOTE_G4, 0), 97 | DATA_PLAY(OVRD, NOTE_C3, 0), 98 | DATA_PLAY(BASS, NOTE_E2, 0), 99 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 3), 100 | DATA_PLAY(HRMN, NOTE_A4, 0), 101 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 102 | 103 | DATA_PLAY(HRMN, NOTE_G4, 0), 104 | DATA_PLAY(BASS, NOTE_C2, 0), 105 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 106 | DATA_PLAY(HRMN, NOTE_E4, 0), 107 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 108 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 109 | DATA_PLAY(HRMN, NOTE_C4, 0), 110 | DATA_PLAY(OVRD, NOTE_C3, 0), 111 | DATA_PLAY(BASS, NOTE_G1, 0), 112 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 3), 113 | DATA_PLAY(HRMN, NOTE_D4, 0), 114 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 115 | 116 | DATA_PLAY(HRMN, NOTE_E4, 0), 117 | DATA_PLAY(OVRD, NOTE_G3 | OVERDRIVE_SHORT, 0), 118 | DATA_PLAY(BASS, NOTE_C2, 0), 119 | DATA_PLAY(PERC, PERCUSSION_BAR_L, 2), 120 | DATA_PLAY(HRMN, NOTE_E4, 0), 121 | DATA_PLAY(OVRD, NOTE_G3 | OVERDRIVE_SHORT, 0), 122 | DATA_PLAY(BASS, NOTE_C2, 0), 123 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 124 | DATA_PLAY(HRMN, NOTE_D4, 0), 125 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 126 | DATA_PLAY(BASS, NOTE_A1, 0), 127 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 128 | DATA_PLAY(HRMN, NOTE_D4, 0), 129 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 130 | DATA_PLAY(BASS, NOTE_G1, 0), 131 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 132 | 133 | DATA_PLAY(HRMN, NOTE_C4, 0), 134 | DATA_PLAY(OVRD, NOTE_C3, 0), 135 | DATA_PLAY(BASS, NOTE_C2, 0), 136 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 137 | DATA_PLAY(BASS, NOTE_G2, 0), 138 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 139 | DATA_PLAY(BASS, NOTE_C3, 0), 140 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 6), 141 | 142 | 143 | DATA_TEMPO(480 * 4), 144 | DATA_VOLUME(HRMN, 56), 145 | DATA_VOLUME(OVRD, 28), 146 | DATA_VOLUME(BASS, 56), 147 | DATA_WAIT(1), 148 | DATA_VOLUME(HRMN, 56), 149 | DATA_VOLUME(OVRD, 24), 150 | DATA_VOLUME(BASS, 48), 151 | DATA_WAIT(1), 152 | DATA_VOLUME(HRMN, 40), 153 | DATA_VOLUME(OVRD, 20), 154 | DATA_VOLUME(BASS, 40), 155 | DATA_WAIT(1), 156 | DATA_VOLUME(HRMN, 32), 157 | DATA_VOLUME(OVRD, 16), 158 | DATA_VOLUME(BASS, 32), 159 | DATA_WAIT(1), 160 | DATA_VOLUME(HRMN, 24), 161 | DATA_VOLUME(OVRD, 12), 162 | DATA_VOLUME(BASS, 24), 163 | DATA_WAIT(1), 164 | DATA_VOLUME(HRMN, 16), 165 | DATA_VOLUME(OVRD, 8), 166 | DATA_VOLUME(BASS, 16), 167 | DATA_WAIT(1), 168 | DATA_VOLUME(HRMN, 8), 169 | DATA_VOLUME(OVRD, 4), 170 | DATA_VOLUME(BASS, 8), 171 | DATA_WAIT(1), 172 | DATA_VOLUME(HRMN, 0), 173 | DATA_VOLUME(OVRD, 0), 174 | DATA_VOLUME(BASS, 0), 175 | DATA_WAIT(16), 176 | 177 | DATA_END() 178 | }; 179 | 180 | 181 | 182 | #undef PERC 183 | #undef HRMN 184 | #undef BASS 185 | #undef OVRD 186 | 187 | -------------------------------------------------------------------------------- /demos/atmega8lcd/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Aleksandr Maksymenko aka masyaman 3 | */ 4 | 5 | #include 6 | #include 7 | //#include 8 | #include 9 | #include 10 | 11 | #ifndef F_CPU 12 | #define F_CPU 8000000 13 | #endif 14 | 15 | #define SAMPLE_PERCUSSION 0 16 | #define SAMPLE_PIANO 1 17 | #define SAMPLE_HARMONICA 2 18 | #define SAMPLE_BASS 3 19 | #define SAMPLE_OVERDRIVE 4 20 | #define SAMPLE_MUSICBOX 5 21 | #define SAMPLE_SYNTH_PIANO 6 22 | 23 | //#define ENABLE_DECLICK 24 | //#define BUFFER_BITS 16 25 | #define BUFFER_SIZE 64 26 | //#define MICROSOUND_FREQUENCY_DIVIDER 4 27 | //#define INTERPOLATION_STRENGTH 2 28 | //#define INTERPOLATE_WAVE 29 | #define CHANNELS_SIZE 5 30 | #define SAMPLES_SIZE 16 31 | #define USE_NOISE_CHANNEL 32 | 33 | 34 | #include "../../microsound/devices/atmega8timer1.h" 35 | #include "../../microsound/micromusic.h" 36 | 37 | #include "../../microsound/instruments/piano.h" 38 | #include "../../microsound/instruments/synthPiano.h" 39 | #include "../../microsound/instruments/bassGuitar.h" 40 | //#include "../../microsound/instruments/accordion.h" 41 | #include "../../microsound/instruments/harmonica.h" 42 | #include "../../microsound/instruments/overdrivenGuitarChord.h" 43 | #include "../../microsound/instruments/percussion.h" 44 | #include "../../microsound/instruments/musicbox.h" 45 | 46 | 47 | #include "../../microsound/samples/notifications_single_channel.h" 48 | #include "../../microsound/samples/notifications_four_channels.h" 49 | #include "../../microsound/samples/oh_susanna.h" 50 | #include "../../microsound/samples/for_elise.h" 51 | 52 | #include "../../microsound/delay.h" 53 | 54 | #define LCD_PORT D 55 | #include "../../lcd/lcd1602.h" 56 | 57 | #define BUTTONS_PORT C 58 | #include "../../buttons/buttons.h" 59 | 60 | const uint8_t PIANO_CHAR_A[] PROGMEM = { 61 | 0b10001, 62 | 0b10101, 63 | 0b10001, 64 | 0b10101, 65 | 0b10001, 66 | 0b11011, 67 | 0b11011, 68 | 0b11011 69 | }; 70 | const uint8_t PIANO_CHAR_B[] PROGMEM = { 71 | 0b00101, 72 | 0b10101, 73 | 0b00101, 74 | 0b10101, 75 | 0b00101, 76 | 0b01101, 77 | 0b01101, 78 | 0b01101 79 | }; 80 | const uint8_t PIANO_CHAR_C[] PROGMEM = { 81 | 0b00100, 82 | 0b10101, 83 | 0b00100, 84 | 0b10101, 85 | 0b00100, 86 | 0b01110, 87 | 0b01110, 88 | 0b01110 89 | }; 90 | 91 | #define DISPLAY_WIDTH 16 92 | #define CUSTOM_CHARS 5 93 | 94 | int main(void) 95 | { 96 | initMusic(); 97 | sei(); 98 | initLCD(); 99 | initButtons(); 100 | 101 | initCharProgmem(5, PIANO_CHAR_A); 102 | initCharProgmem(6, PIANO_CHAR_B); 103 | initCharProgmem(7, PIANO_CHAR_C); 104 | cursor(1, 0); 105 | uint8_t i; 106 | for(i = 0; i < DISPLAY_WIDTH / 4; i++) { 107 | printChar(5); 108 | printChar(6); 109 | printChar(7); 110 | printChar(5); 111 | } 112 | 113 | setSample(SAMPLE_PERCUSSION, playPercussion); 114 | setSample(SAMPLE_PIANO, playPiano); 115 | setSample(SAMPLE_HARMONICA, playHarmonica); 116 | setSample(SAMPLE_BASS, playBassGuitar); 117 | setSample(SAMPLE_OVERDRIVE, playOverdrivenGuitarChord); 118 | setSample(SAMPLE_MUSICBOX, playMusicbox); 119 | setSample(SAMPLE_SYNTH_PIANO, playSynthPiano); 120 | 121 | 122 | static uint8_t freeCustomCharsIndex; 123 | static uint8_t freeCustomChars[CUSTOM_CHARS]; 124 | static uint8_t displayString[DISPLAY_WIDTH]; 125 | 126 | for (freeCustomCharsIndex = 0; freeCustomCharsIndex < CUSTOM_CHARS; freeCustomCharsIndex++) { 127 | freeCustomChars[freeCustomCharsIndex] = freeCustomCharsIndex; 128 | } 129 | for (i = 0; i < DISPLAY_WIDTH; i++) { 130 | displayString[i] = ' '; 131 | } 132 | 133 | uint8_t startNote = NOTE_C1; 134 | 135 | uint8_t soundBank = 0; 136 | 137 | // static uint8_t a = 0; 138 | // static uint8_t b = 0; 139 | while (1) { 140 | 141 | fillMusicBuffer(); 142 | 143 | cursor(0, 0); 144 | 145 | // for (i = 0; i < 100; i++) { 146 | // _delay_ms(1); 147 | // } 148 | // // delaySamples(MICROSOUND_FREQUENCY); 149 | // printChar('0' + b); 150 | // printChar('0' + a); 151 | // a++; 152 | // if (a >= 10) { 153 | // a = 0; 154 | // b++; 155 | // } 156 | 157 | if (isMusicStopped) { 158 | 159 | if (isButtonClicked(1 << 0)) { // B 160 | soundBank += 1; 161 | } else if (isButtonClicked(1 << 1)) { // A 162 | soundBank += 2; 163 | } 164 | if (soundBank >= 3) { 165 | soundBank -= 3; 166 | } 167 | 168 | if (soundBank == 0) { 169 | printStr("> Music samples "); 170 | 171 | if (isButtonClicked(1 << 2)) { // Right 172 | startNote = NOTE_C1; 173 | playMusic(ohSusannaSong); 174 | // } else if (isButtonClicked(1 << 3)) { // Up 175 | // playMusic(harp); 176 | // } else if (isButtonClicked(1 << 4)) { // Down 177 | // playMusic(chordC5); 178 | } else if (isButtonClicked(1 << 5)) { // Left 179 | startNote = NOTE_C2; 180 | playMusic(forElise); 181 | } 182 | } else if (soundBank == 1) { 183 | printStr("> Sound effects "); 184 | startNote = NOTE_C2; 185 | 186 | if (isButtonClicked(1 << 2)) { // Right 187 | playMusic(chordC5); 188 | } else if (isButtonClicked(1 << 3)) { // Up 189 | playMusic(harp); 190 | } else if (isButtonClicked(1 << 4)) { // Down 191 | playMusic(chordC4); 192 | } else if (isButtonClicked(1 << 5)) { // Left 193 | playMusic(chordC5back); 194 | } 195 | } else if (soundBank == 2) { 196 | printStr("> Single channel"); 197 | startNote = NOTE_C2; 198 | 199 | if (isButtonClicked(1 << 2)) { // Right 200 | playMusic(harmonicaNotification); 201 | } else if (isButtonClicked(1 << 3)) { // Up 202 | playMusic(attentionNotification); 203 | } else if (isButtonClicked(1 << 4)) { // Down 204 | playMusic(looserNotification); 205 | } else if (isButtonClicked(1 << 5)) { // Left 206 | startNote = NOTE_C1; 207 | playMusic(guitarNotification); 208 | } 209 | } 210 | 211 | continue; 212 | } 213 | 214 | if (isButtonClicked(0xFF)) { 215 | stopMusic(); 216 | } 217 | 218 | uint8_t pos; 219 | for (pos = 0; pos < DISPLAY_WIDTH; pos++) { 220 | fillMusicBuffer(); 221 | 222 | uint8_t note1 = 0; 223 | uint8_t note2 = 0; 224 | uint8_t note3 = 0; 225 | for (i = 0; i < CHANNELS_SIZE; i++) { 226 | if (channels[i]->waveStep == pgm_read_word(&frequencies[startNote + pos * 3])) { 227 | note1 += channels[i]->currentVolume; 228 | } 229 | if (channels[i]->waveStep == pgm_read_word(&frequencies[startNote + pos * 3 + 1])) { 230 | note2 += channels[i]->currentVolume; 231 | } 232 | if (channels[i]->waveStep == pgm_read_word(&frequencies[startNote + pos * 3 + 2])) { 233 | note3 += channels[i]->currentVolume; 234 | } 235 | } 236 | 237 | if (note1 + note2 + note3 > 0) { 238 | uint8_t currentChar = displayString[pos]; 239 | if (currentChar >= CUSTOM_CHARS && freeCustomCharsIndex > 0) { 240 | currentChar = freeCustomChars[--freeCustomCharsIndex]; 241 | } 242 | 243 | if (currentChar < CUSTOM_CHARS) { 244 | static uint8_t customChar[8]; 245 | uint8_t k; 246 | for (k = 0; k < 8; k++) { 247 | customChar[7 - k] = ((note1 > (k << 3)) ? 0b10000 : 0) | 248 | ((note2 > (k << 3)) ? 0b00100 : 0) | 249 | ((note3 > (k << 3)) ? 0b00001 : 0); 250 | } 251 | initChar(currentChar, customChar); 252 | cursor(0, pos); 253 | } 254 | printChar(currentChar); 255 | displayString[pos] = currentChar; 256 | } else { 257 | printChar(' '); 258 | if (displayString[pos] < CUSTOM_CHARS) { 259 | freeCustomChars[freeCustomCharsIndex++] = displayString[pos]; 260 | displayString[pos] = ' '; 261 | } 262 | } 263 | 264 | } 265 | 266 | } 267 | } 268 | -------------------------------------------------------------------------------- /utils/multiply.h: -------------------------------------------------------------------------------- 1 | 2 | // Can be useful for attiny MCUs which does not have hardware multiplication 3 | 4 | #ifndef INLINE_MULTIPLICATION_SIGNED_UNSIGNED 5 | #define INLINE_MULTIPLICATION_SIGNED_UNSIGNED inline /* inline by default */ 6 | #endif 7 | #ifndef INLINE_MULTIPLICATION_UNSIGNED_UNSIGNED 8 | #define INLINE_MULTIPLICATION_UNSIGNED_UNSIGNED inline /* inline by default */ 9 | #endif 10 | 11 | #if !defined SPEED_OPTIMIZED_MULTIPLICATION 12 | 13 | // Use hardware multiplication if possible 14 | 15 | #define mulSignedUnsigned(ms, mu) ((ms) * (mu)) 16 | #define mulUnsigned8bits(a, b) ((uint8_t) (((a) * (b)) >> 8)) 17 | 18 | #elif !defined SIMPLIFIED_MULTIPLICATION 19 | 20 | // Use software speed optimized multiplication 21 | 22 | // LIMIT: ms = [-127..127], mu = [0..255] 23 | INLINE_MULTIPLICATION_SIGNED_UNSIGNED 24 | int16_t mulSignedUnsigned(int8_t ms, uint8_t mu) { 25 | // This implementation returns 16 bits result in 40ck 26 | // No need to use it for atmega MCUs or others which has hardware multiplication 27 | int16_t result; 28 | asm( 29 | "clr %B[result]" "\n\r" 30 | "mov %A[result], %[muls]" "\n\r" 31 | "sbrc %A[result], 7" "\n\r" 32 | "neg %A[result]" "\n\r" 33 | 34 | "lsr %A[result]" "\n\r" 35 | 36 | "brcc .+2" "\n\r" 37 | "add %B[result], %[mulu]" "\n\r" 38 | "ror %B[result]" "\n\r" 39 | "ror %A[result]" "\n\r" 40 | 41 | "brcc .+2" "\n\r" 42 | "add %B[result], %[mulu]" "\n\r" 43 | "ror %B[result]" "\n\r" 44 | "ror %A[result]" "\n\r" 45 | 46 | "brcc .+2" "\n\r" 47 | "add %B[result], %[mulu]" "\n\r" 48 | "ror %B[result]" "\n\r" 49 | "ror %A[result]" "\n\r" 50 | 51 | "brcc .+2" "\n\r" 52 | "add %B[result], %[mulu]" "\n\r" 53 | "ror %B[result]" "\n\r" 54 | "ror %A[result]" "\n\r" 55 | 56 | "brcc .+2" "\n\r" 57 | "add %B[result], %[mulu]" "\n\r" 58 | "ror %B[result]" "\n\r" 59 | "ror %A[result]" "\n\r" 60 | 61 | "brcc .+2" "\n\r" 62 | "add %B[result], %[mulu]" "\n\r" 63 | "ror %B[result]" "\n\r" 64 | "ror %A[result]" "\n\r" 65 | 66 | "brcc .+2" "\n\r" 67 | "add %B[result], %[mulu]" "\n\r" 68 | "ror %B[result]" "\n\r" 69 | "ror %A[result]" "\n\r" 70 | 71 | // Bit7 is 0. This optimized block will cause issue on muls = -128. To avoid this use block similar to above. 72 | "lsr %B[result]" "\n\r" 73 | "ror %A[result]" "\n\r" 74 | 75 | // Invert result sign 76 | "tst %[muls]" "\n\r" 77 | "brlt .+6" "\n\r" 78 | "com %B[result]" "\n\r" 79 | "neg %A[result]" "\n\r" 80 | "sbci %B[result], 255" "\n\r" 81 | 82 | 83 | : [result] "=&d" (result) 84 | : [muls] "r" (ms), [mulu] "r" (mu) 85 | ); 86 | return result; 87 | } 88 | 89 | INLINE_MULTIPLICATION_UNSIGNED_UNSIGNED uint16_t mulUnsigned(uint8_t a, uint8_t b) { 90 | // This implementation returns 16 bits result in 35ck 91 | // No need to use it for atmega MCUs or others which has hardware multiplication 92 | uint16_t result; 93 | asm( 94 | "clr %B[result]" "\n\r" 95 | "mov %A[result], %[mulu]" "\n\r" 96 | 97 | "lsr %A[result]" "\n\r" 98 | 99 | "brcc .+2" "\n\r" 100 | "add %B[result], %[muls]" "\n\r" 101 | "ror %B[result]" "\n\r" 102 | "ror %A[result]" "\n\r" 103 | 104 | "brcc .+2" "\n\r" 105 | "add %B[result], %[muls]" "\n\r" 106 | "ror %B[result]" "\n\r" 107 | "ror %A[result]" "\n\r" 108 | 109 | "brcc .+2" "\n\r" 110 | "add %B[result], %[muls]" "\n\r" 111 | "ror %B[result]" "\n\r" 112 | "ror %A[result]" "\n\r" 113 | 114 | "brcc .+2" "\n\r" 115 | "add %B[result], %[muls]" "\n\r" 116 | "ror %B[result]" "\n\r" 117 | "ror %A[result]" "\n\r" 118 | 119 | "brcc .+2" "\n\r" 120 | "add %B[result], %[muls]" "\n\r" 121 | "ror %B[result]" "\n\r" 122 | "ror %A[result]" "\n\r" 123 | 124 | "brcc .+2" "\n\r" 125 | "add %B[result], %[muls]" "\n\r" 126 | "ror %B[result]" "\n\r" 127 | "ror %A[result]" "\n\r" 128 | 129 | "brcc .+2" "\n\r" 130 | "add %B[result], %[muls]" "\n\r" 131 | "ror %B[result]" "\n\r" 132 | "ror %A[result]" "\n\r" 133 | 134 | "brcc .+2" "\n\r" 135 | "add %B[result], %[muls]" "\n\r" 136 | "ror %B[result]" "\n\r" 137 | "ror %A[result]" "\n\r" 138 | 139 | : [result] "=&r" (result) 140 | : [muls] "r" (a), [mulu] "r" (b) 141 | ); 142 | return result; 143 | } 144 | 145 | inline uint8_t mulUnsigned8bits(uint8_t a, uint8_t b) { 146 | return mulUnsigned(a, b) >> 8; 147 | } 148 | 149 | #else 150 | 151 | // Use simplified multiplication with limitations. It's slightly faster and has requires less program memory but gives worse sound quality. 152 | // Also it requires instruments to have volume 127 or less. 153 | 154 | // LIMIT: return only high byte of multiplication result, low byte is 0 155 | INLINE_MULTIPLICATION_SIGNED_UNSIGNED 156 | int16_t mulSignedUnsigned(int8_t ms, uint8_t mu) { 157 | // This implementation returns high byte of 16 bits result in 31ck 158 | // No need to use it for atmega MCUs or others which has hardware multiplication 159 | int16_t result; 160 | asm( 161 | 162 | // invert sign if needed 163 | "mov __tmp_reg__, %[muls]" "\n\r" 164 | "sbrc __tmp_reg__, 7" "\n\r" 165 | "neg __tmp_reg__" "\n\r" 166 | 167 | // multiply unsigned 168 | "clr %A[result]" "\n\r" 169 | "clr %B[result]" "\n\r" 170 | 171 | "sbrc %[mulu], 0" "\n\r" 172 | "add %B[result], __tmp_reg__" "\n\r" 173 | "lsr %B[result]" "\n\r" 174 | "sbrc %[mulu], 1" "\n\r" 175 | "add %B[result], __tmp_reg__" "\n\r" 176 | "lsr %B[result]" "\n\r" 177 | "sbrc %[mulu], 2" "\n\r" 178 | "add %B[result], __tmp_reg__" "\n\r" 179 | "lsr %B[result]" "\n\r" 180 | "sbrc %[mulu], 3" "\n\r" 181 | "add %B[result], __tmp_reg__" "\n\r" 182 | "lsr %B[result]" "\n\r" 183 | "sbrc %[mulu], 4" "\n\r" 184 | "add %B[result], __tmp_reg__" "\n\r" 185 | "lsr %B[result]" "\n\r" 186 | "sbrc %[mulu], 5" "\n\r" 187 | "add %B[result], __tmp_reg__" "\n\r" 188 | "lsr %B[result]" "\n\r" 189 | "sbrc %[mulu], 6" "\n\r" 190 | "add %B[result], __tmp_reg__" "\n\r" 191 | "lsr %B[result]" "\n\r" 192 | "sbrc %[mulu], 7" "\n\r" 193 | "add %B[result], __tmp_reg__" "\n\r" 194 | "lsr %B[result]" "\n\r" 195 | 196 | // invert result sign 197 | "sbrc %[muls], 7" "\n\r" 198 | "neg %B[result]" "\n\r" 199 | 200 | 201 | : [result] "=&d" (result) 202 | : [muls] "r" (ms), [mulu] "r" (mu) 203 | ); 204 | return result; 205 | } 206 | 207 | // LIMIT: a = [0..255], b = [0..127] 208 | INLINE_MULTIPLICATION_UNSIGNED_UNSIGNED 209 | uint8_t mulUnsigned8bits(uint8_t a, uint8_t b) { 210 | // This is a simplified implementation returns high byte 8 bits result in 25ck 211 | // No need to use it for atmega MCUs or others which has hardware multiplication 212 | uint8_t result; 213 | asm( 214 | "clr %[result]" "\n\r" 215 | 216 | "sbrc %[mulu], 0" "\n\r" 217 | "add %[result], %[muls]" "\n\r" 218 | "lsr %[result]" "\n\r" 219 | "sbrc %[mulu], 1" "\n\r" 220 | "add %[result],%[muls]" "\n\r" 221 | "lsr %[result]" "\n\r" 222 | "sbrc %[mulu], 2" "\n\r" 223 | "add %[result], %[muls]" "\n\r" 224 | "lsr %[result]" "\n\r" 225 | "sbrc %[mulu], 3" "\n\r" 226 | "add %[result], %[muls]" "\n\r" 227 | "lsr %[result]" "\n\r" 228 | "sbrc %[mulu], 4" "\n\r" 229 | "add %[result], %[muls]" "\n\r" 230 | "lsr %[result]" "\n\r" 231 | "sbrc %[mulu], 5" "\n\r" 232 | "add %[result], %[muls]" "\n\r" 233 | "lsr %[result]" "\n\r" 234 | "sbrc %[mulu], 6" "\n\r" 235 | "add %[result], %[muls]" "\n\r" 236 | "lsr %[result]" "\n\r" 237 | "sbrc %[mulu], 7" "\n\r" 238 | "add %[result], %[muls]" "\n\r" 239 | "lsr %[result]" "\n\r" 240 | 241 | : [result] "=&r" (result) 242 | : [muls] "r" (b), [mulu] "r" (a) 243 | ); 244 | return result; 245 | 246 | } 247 | 248 | #endif 249 | -------------------------------------------------------------------------------- /microsound/microsound.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef MICROSOUND_INIT 3 | #define MICROSOUND_INIT 4 | 5 | /* 6 | * Generates multi-channel sound. 7 | * 8 | * Generated sound contains of several wave channels and optionally single noise channel. 9 | * Wave channel is a repeated wave of specified form and it's volume changed over time. 10 | * Noise channel is a randomized values changing it's volume over time. 11 | * 12 | * All channels are mixed up according to channel volumes. 13 | * 14 | * Author: Aleksandr Maksymenko aka masyaman 15 | */ 16 | 17 | // Amount of wave channels 18 | #ifndef CHANNELS_SIZE 19 | #define CHANNELS_SIZE 1 20 | #endif 21 | 22 | #if CHANNELS_SIZE > 8 23 | #warning "Currently maximum amount of channels is 8" 24 | #endif 25 | 26 | // Divide default PCM sample rate onto this value 27 | #ifndef MICROSOUND_FREQUENCY_DIVIDER 28 | #define MICROSOUND_FREQUENCY_DIVIDER 1 29 | #endif 30 | 31 | // Default PCM sample rate onto this value. May have issues if sample rate > 65k. 32 | #ifndef MICROSOUND_FREQUENCY 33 | #define MICROSOUND_FREQUENCY (F_CPU / 256 / MICROSOUND_FREQUENCY_DIVIDER) // PCM sample rate 34 | #endif 35 | 36 | #define toByteConstant(x) ((x >= 255) ? 255 : ((uint8_t) (x))) 37 | 38 | // 1 tick = 4ms. 8-bit divider of frequency should handle up to 65kHz (up to 16MHz CPU). 8-bit multiplier can handle up to 1 second. 39 | #define TICKS_PER_SECOND 250 40 | #define SAMPLES_PER_TICK toByteConstant(MICROSOUND_FREQUENCY / TICKS_PER_SECOND) 41 | 42 | #if (MICROSOUND_FREQUENCY / TICKS_PER_SECOND >= 255) 43 | #warning "Sampling frequency is too high. It should be lower than 65kHz. Incorrect timings are possible." 44 | #endif 45 | 46 | // Support up to 1 beat per second 47 | #define fromBpm(beatsPerMinute) toByteConstant(60L * TICKS_PER_SECOND / (beatsPerMinute)) 48 | 49 | // Control code inlining. To inline use `#define INLINE_... inline` 50 | #ifndef INLINE_BUFFER_FILL 51 | #define INLINE_BUFFER_FILL /* do not inline by default */ 52 | #endif 53 | #ifndef INLINE_SOUND_CONTROL 54 | #define INLINE_SOUND_CONTROL /* do not inline by default */ 55 | #endif 56 | 57 | 58 | uint8_t tickSampleCounter; 59 | uint8_t beatTickCounter; 60 | uint8_t beatIncrementAt; 61 | uint16_t beatCounter; 62 | 63 | uint8_t volumeRecalculationId; 64 | 65 | typedef struct 66 | { 67 | // Info about wave 68 | const int8_t* waveForm; // Wave table array 69 | uint16_t waveSample; // High byte is an index in waveForm array 70 | uint16_t waveStep; // Frequency, how waveSample is changed in time 71 | 72 | // Info about volume envelope 73 | const uint8_t* volumeForm; // Array of volume change in time 74 | uint8_t volumeFormLength; // Length of volumeForm 75 | uint8_t volumeTicksPerSample; // How many ticks should pass before index of volumeForm is changed 76 | uint8_t volumeTicksCounter; // Counter for volumeTicksPerSample 77 | 78 | // Info about volume 79 | uint8_t currentVolume; // Precalculated volume for current tick 80 | uint8_t instrumentVolume; // Volume of channel 81 | } waveChannel; 82 | 83 | waveChannel* channels[CHANNELS_SIZE]; 84 | 85 | #include "../utils/multiply.h" 86 | #include "buffer.h" 87 | #include "frequencies.h" 88 | #include "declick.h" 89 | #include "instruments/common/commonWave.h" 90 | 91 | // Set volume for specified wave channel 92 | inline void setVolume(uint8_t channel, uint8_t volume) { 93 | channels[channel]->instrumentVolume = volume; 94 | } 95 | 96 | // Add noise channel 97 | #ifdef USE_NOISE_CHANNEL 98 | #include "noisechannel.h" 99 | #endif 100 | // Add wave channels 101 | #if CHANNELS_SIZE >= 1 102 | #define CHANNEL_ID channel0 103 | #include "wavechannel.h" 104 | #endif 105 | #if CHANNELS_SIZE >= 2 106 | #define CHANNEL_ID channel1 107 | #include "wavechannel.h" 108 | #endif 109 | #if CHANNELS_SIZE >= 3 110 | #define CHANNEL_ID channel2 111 | #include "wavechannel.h" 112 | #endif 113 | #if CHANNELS_SIZE >= 4 114 | #define CHANNEL_ID channel3 115 | #include "wavechannel.h" 116 | #endif 117 | #if CHANNELS_SIZE >= 5 118 | #define CHANNEL_ID channel4 119 | #include "wavechannel.h" 120 | #endif 121 | #if CHANNELS_SIZE >= 6 122 | #define CHANNEL_ID channel5 123 | #include "wavechannel.h" 124 | #endif 125 | #if CHANNELS_SIZE >= 7 126 | #define CHANNEL_ID channel6 127 | #include "wavechannel.h" 128 | #endif 129 | #if CHANNELS_SIZE >= 8 130 | #define CHANNEL_ID channel7 131 | #include "wavechannel.h" 132 | #endif 133 | 134 | 135 | // Set beats per minute value. For example: 136 | // setBpm(fromBpm(180)); 137 | // will increment beatCounter 180 times per minute or 3 times per second. 138 | inline void setBpm(uint8_t counter) { 139 | beatIncrementAt = counter; 140 | beatTickCounter = counter; 141 | } 142 | 143 | // Clean data for wave channel 144 | inline void resetChannel(waveChannel* channel) { 145 | channel->waveSample = 0; 146 | channel->waveStep = 0; 147 | channel->volumeFormLength = 0; 148 | channel->volumeTicksCounter = channel->volumeTicksPerSample; 149 | channel->currentVolume = 0; 150 | channel->instrumentVolume = 0; 151 | } 152 | 153 | // Clean data for all channels 154 | void resetSound() { 155 | setBpm(fromBpm(60)); // Avoid too high BPM at MCU start 156 | beatCounter = 0; 157 | 158 | #if CHANNELS_SIZE >= 1 159 | channels[0] = &channel0ChannelData; 160 | #endif 161 | #if CHANNELS_SIZE >= 2 162 | channels[1] = &channel1ChannelData; 163 | #endif 164 | #if CHANNELS_SIZE >= 3 165 | channels[2] = &channel2ChannelData; 166 | #endif 167 | #if CHANNELS_SIZE >= 4 168 | channels[3] = &channel3ChannelData; 169 | #endif 170 | #if CHANNELS_SIZE >= 5 171 | channels[4] = &channel4ChannelData; 172 | #endif 173 | #if CHANNELS_SIZE >= 6 174 | channels[5] = &channel5ChannelData; 175 | #endif 176 | #if CHANNELS_SIZE >= 7 177 | channels[6] = &channel6ChannelData; 178 | #endif 179 | #if CHANNELS_SIZE >= 8 180 | channels[7] = &channel7ChannelData; 181 | #endif 182 | 183 | uint8_t i; 184 | for (i = 0; i < CHANNELS_SIZE; i++) { 185 | resetChannel(channels[i]); 186 | } 187 | 188 | #ifdef USE_NOISE_CHANNEL 189 | resetNoise(); 190 | #endif 191 | } 192 | 193 | // Recalculate volume for a channel 194 | inline void recalculateVolume(waveChannel* channel) { 195 | 196 | if ((channel->volumeTicksCounter--) == 0 && channel->volumeFormLength > 0) { 197 | channel->volumeTicksCounter = channel->volumeTicksPerSample; 198 | channel->volumeFormLength--; 199 | channel->volumeForm++; 200 | } 201 | 202 | #ifdef MICROSOUND_STATIC_VOLUME 203 | channel->currentVolume = (pgm_read_byte(channel->volumeForm)) >> MICROSOUND_STATIC_VOLUME; 204 | #else 205 | channel->currentVolume = mulUnsigned8bits(pgm_read_byte(channel->volumeForm), channel->instrumentVolume); 206 | #endif 207 | 208 | } 209 | 210 | 211 | // Calculate next sample on all channels 212 | inline soundSample getNextSample() { 213 | 214 | if ((tickSampleCounter--) == 0) { 215 | tickSampleCounter = SAMPLES_PER_TICK - 1; 216 | if ((beatTickCounter--) == 0) { 217 | beatTickCounter = beatIncrementAt; 218 | beatCounter++; 219 | } 220 | } 221 | 222 | // volume recalculation should no be done so often for all channels 223 | if (tickSampleCounter < CHANNELS_SIZE) { 224 | recalculateVolume(channels[tickSampleCounter]); 225 | } 226 | 227 | uint16_t val = getZeroSample(); // Optional declick code 228 | 229 | 230 | #ifdef USE_NOISE_CHANNEL 231 | val += noiseNextSample(); 232 | #endif 233 | 234 | #if CHANNELS_SIZE >= 1 235 | val += channel0NextSample(); 236 | #endif 237 | #if CHANNELS_SIZE >= 2 238 | val += channel1NextSample(); 239 | #endif 240 | #if CHANNELS_SIZE >= 3 241 | val += channel2NextSample(); 242 | #endif 243 | #if CHANNELS_SIZE >= 4 244 | val += channel3NextSample(); 245 | #endif 246 | #if CHANNELS_SIZE >= 5 247 | val += channel4NextSample(); 248 | #endif 249 | #if CHANNELS_SIZE >= 6 250 | val += channel5NextSample(); 251 | #endif 252 | #if CHANNELS_SIZE >= 7 253 | val += channel6NextSample(); 254 | #endif 255 | #if CHANNELS_SIZE >= 8 256 | val += channel7NextSample(); 257 | #endif 258 | 259 | 260 | return toSample(val); 261 | 262 | } 263 | 264 | // Fill buffer until maxSamples is read or buffer is full. May cause bugs if maxSamples is too close to 255. 265 | INLINE_BUFFER_FILL 266 | void fillBuffer(uint8_t maxSamples) { 267 | uint8_t sampleCounterAtStart = bufferReadCounter; 268 | 269 | // Less code but slower 270 | // while (1) { 271 | // uint8_t currentCounter = bufferReadCounter; 272 | // if (((uint8_t)(currentCounter - sampleCounterAtStart)) > maxSamples || (currentCounter & BUFFER_MASK) == bufferWrite) { 273 | // return; 274 | // } 275 | // writeToBuffer(getNextSample()); 276 | // } 277 | 278 | uint8_t limit = maxSamples; 279 | uint8_t currentCounter = sampleCounterAtStart; 280 | while ((currentCounter & BUFFER_MASK) != bufferWrite) { 281 | writeToBuffer(getNextSample()); 282 | currentCounter = bufferReadCounter; 283 | 284 | if (!(--limit)) { 285 | limit = currentCounter - sampleCounterAtStart; 286 | if (limit > maxSamples) { // overflow 287 | moveToZeroSampleValue(); // Optional declick code 288 | return; 289 | } 290 | } 291 | } 292 | } 293 | 294 | #endif 295 | -------------------------------------------------------------------------------- /microsound/samples/for_elise.h: -------------------------------------------------------------------------------- 1 | /* 2 | * http://elm-chan.org/works/mxb/report.html 3 | */ 4 | 5 | #if CHANNELS_SIZE < 5 6 | #warning "Included music file requires 5 channels" 7 | #endif 8 | 9 | const uint8_t forElise[] PROGMEM = { 10 | DATA_TEMPO(480), 11 | 12 | DATA_INSTRUMENT(0, SAMPLE_MUSICBOX), 13 | DATA_INSTRUMENT(1, SAMPLE_MUSICBOX), 14 | DATA_INSTRUMENT(2, SAMPLE_MUSICBOX), 15 | DATA_INSTRUMENT(3, SAMPLE_MUSICBOX), 16 | DATA_INSTRUMENT(4, SAMPLE_MUSICBOX), 17 | DATA_VOLUME(0, 51), 18 | DATA_VOLUME(1, 51), 19 | DATA_VOLUME(2, 51), 20 | DATA_VOLUME(3, 51), 21 | DATA_VOLUME(4, 51), 22 | 23 | // 1 24 | DATA_PLAY(1, NOTE_E5, 2), 25 | DATA_PLAY(2, NOTE_Eb5, 2), 26 | // 2 27 | DATA_PLAY(1, NOTE_E5, 2), 28 | DATA_PLAY(2, NOTE_Eb5, 2), 29 | DATA_PLAY(1, NOTE_E5, 2), 30 | DATA_PLAY(3, NOTE_B4, 2), 31 | DATA_PLAY(4, NOTE_D5, 2), 32 | DATA_PLAY(0, NOTE_C5, 2), 33 | // 3 34 | DATA_PLAY(1, NOTE_A4, 0), 35 | DATA_PLAY(2, NOTE_A2, 2), 36 | DATA_PLAY(3, NOTE_E3, 2), 37 | DATA_PLAY(4, NOTE_A3, 2), 38 | DATA_PLAY(0, NOTE_C4, 2), 39 | DATA_PLAY(1, NOTE_E4, 2), 40 | DATA_PLAY(2, NOTE_A4, 2), 41 | // 4 42 | DATA_PLAY(3, NOTE_B4, 0), 43 | DATA_PLAY(4, NOTE_E2, 2), 44 | DATA_PLAY(0, NOTE_E3, 2), 45 | DATA_PLAY(1, NOTE_Ab3, 2), 46 | DATA_PLAY(2, NOTE_E4, 2), 47 | DATA_PLAY(3, NOTE_Ab4, 2), 48 | DATA_PLAY(4, NOTE_B4, 2), 49 | // 5 50 | DATA_PLAY(0, NOTE_C5, 0), 51 | DATA_PLAY(1, NOTE_A2, 2), 52 | DATA_PLAY(2, NOTE_E3, 2), 53 | DATA_PLAY(3, NOTE_A3, 2), 54 | DATA_PLAY(4, NOTE_E4, 2), 55 | DATA_PLAY(0, NOTE_E5, 2), 56 | DATA_PLAY(1, NOTE_Eb5, 2), 57 | // 6 58 | DATA_PLAY(0, NOTE_E5, 2), 59 | DATA_PLAY(1, NOTE_Eb5, 2), 60 | DATA_PLAY(0, NOTE_E5, 2), 61 | DATA_PLAY(2, NOTE_B4, 2), 62 | DATA_PLAY(3, NOTE_D5, 2), 63 | DATA_PLAY(4, NOTE_C5, 2), 64 | // 7 65 | DATA_PLAY(0, NOTE_A4, 0), 66 | DATA_PLAY(1, NOTE_A2, 2), 67 | DATA_PLAY(2, NOTE_E3, 2), 68 | DATA_PLAY(3, NOTE_A3, 2), 69 | DATA_PLAY(4, NOTE_C4, 2), 70 | DATA_PLAY(0, NOTE_E4, 2), 71 | DATA_PLAY(1, NOTE_A4, 2), 72 | // 8 73 | DATA_PLAY(2, NOTE_B4, 0), 74 | DATA_PLAY(3, NOTE_E2, 2), 75 | DATA_PLAY(4, NOTE_E3, 2), 76 | DATA_PLAY(0, NOTE_Ab3, 2), 77 | DATA_PLAY(1, NOTE_E4, 2), 78 | DATA_PLAY(2, NOTE_C5, 2), 79 | DATA_PLAY(3, NOTE_B4, 2), 80 | // 9 81 | DATA_PLAY(4, NOTE_A4, 0), 82 | DATA_PLAY(0, NOTE_A2, 2), 83 | DATA_PLAY(1, NOTE_E3, 2), 84 | DATA_PLAY(2, NOTE_A3, 4), 85 | DATA_PLAY(3, NOTE_E5, 2), 86 | DATA_PLAY(4, NOTE_Eb5, 2), 87 | // 10 88 | DATA_PLAY(3, NOTE_E5, 2), 89 | DATA_PLAY(4, NOTE_Eb5, 2), 90 | DATA_PLAY(3, NOTE_E5, 2), 91 | DATA_PLAY(0, NOTE_B4, 2), 92 | DATA_PLAY(1, NOTE_D5, 2), 93 | DATA_PLAY(2, NOTE_C5, 2), 94 | // 11 95 | DATA_PLAY(3, NOTE_A4, 0), 96 | DATA_PLAY(4, NOTE_A2, 2), 97 | DATA_PLAY(0, NOTE_E3, 2), 98 | DATA_PLAY(1, NOTE_A3, 2), 99 | DATA_PLAY(2, NOTE_C4, 2), 100 | DATA_PLAY(3, NOTE_E4, 2), 101 | DATA_PLAY(4, NOTE_A4, 2), 102 | // 12 103 | DATA_PLAY(0, NOTE_B4, 0), 104 | DATA_PLAY(1, NOTE_E2, 2), 105 | DATA_PLAY(2, NOTE_E3, 2), 106 | DATA_PLAY(3, NOTE_Ab3, 2), 107 | DATA_PLAY(4, NOTE_E4, 2), 108 | DATA_PLAY(0, NOTE_Ab4, 2), 109 | DATA_PLAY(1, NOTE_B4, 2), 110 | // 13 111 | DATA_PLAY(2, NOTE_C5, 0), 112 | DATA_PLAY(3, NOTE_A2, 2), 113 | DATA_PLAY(4, NOTE_E3, 2), 114 | DATA_PLAY(0, NOTE_A3, 2), 115 | DATA_PLAY(1, NOTE_E4, 2), 116 | DATA_PLAY(2, NOTE_E5, 2), 117 | DATA_PLAY(3, NOTE_Eb5, 2), 118 | // 14 119 | DATA_PLAY(2, NOTE_E5, 2), 120 | DATA_PLAY(3, NOTE_Eb5, 2), 121 | DATA_PLAY(2, NOTE_E5, 2), 122 | DATA_PLAY(4, NOTE_B4, 2), 123 | DATA_PLAY(0, NOTE_D5, 2), 124 | DATA_PLAY(1, NOTE_C5, 2), 125 | // 15 126 | DATA_PLAY(2, NOTE_A4, 0), 127 | DATA_PLAY(3, NOTE_A2, 2), 128 | DATA_PLAY(4, NOTE_E3, 2), 129 | DATA_PLAY(0, NOTE_A3, 2), 130 | DATA_PLAY(1, NOTE_C4, 2), 131 | DATA_PLAY(2, NOTE_E4, 2), 132 | DATA_PLAY(3, NOTE_A4, 2), 133 | // 16 134 | DATA_PLAY(4, NOTE_B4, 0), 135 | DATA_PLAY(0, NOTE_E2, 2), 136 | DATA_PLAY(1, NOTE_E3, 2), 137 | DATA_PLAY(2, NOTE_Ab3, 2), 138 | DATA_PLAY(3, NOTE_E4, 2), 139 | DATA_PLAY(4, NOTE_C5, 2), 140 | DATA_PLAY(0, NOTE_B4, 2), 141 | // 17 142 | DATA_PLAY(1, NOTE_A4, 0), 143 | DATA_PLAY(2, NOTE_A2, 2), 144 | DATA_PLAY(3, NOTE_E3, 2), 145 | DATA_PLAY(4, NOTE_A3, 2), 146 | DATA_PLAY(0, NOTE_B4, 2), 147 | DATA_PLAY(0, NOTE_C5, 2), 148 | DATA_PLAY(1, NOTE_D5, 2), 149 | // 18 150 | DATA_PLAY(2, NOTE_E5, 0), 151 | DATA_PLAY(3, NOTE_C3, 2), 152 | DATA_PLAY(4, NOTE_G3, 2), 153 | DATA_PLAY(0, NOTE_C4, 2), 154 | DATA_PLAY(1, NOTE_G4, 2), 155 | DATA_PLAY(2, NOTE_F5, 2), 156 | DATA_PLAY(3, NOTE_E5, 2), 157 | // 19 158 | DATA_PLAY(4, NOTE_D5, 0), 159 | DATA_PLAY(0, NOTE_G2, 2), 160 | DATA_PLAY(1, NOTE_G3, 2), 161 | DATA_PLAY(2, NOTE_A3, 2), 162 | DATA_PLAY(3, NOTE_F4, 2), 163 | DATA_PLAY(4, NOTE_E5, 2), 164 | DATA_PLAY(0, NOTE_D5, 2), 165 | // 20 166 | DATA_PLAY(1, NOTE_C5, 0), 167 | DATA_PLAY(2, NOTE_A2, 2), 168 | DATA_PLAY(3, NOTE_E3, 2), 169 | DATA_PLAY(4, NOTE_A3, 2), 170 | DATA_PLAY(0, NOTE_E4, 2), 171 | DATA_PLAY(1, NOTE_D5, 2), 172 | DATA_PLAY(2, NOTE_C5, 2), 173 | // 21 174 | DATA_PLAY(3, NOTE_B4, 0), 175 | DATA_PLAY(4, NOTE_E2, 2), 176 | DATA_PLAY(0, NOTE_E3, 2), 177 | DATA_PLAY(1, NOTE_E4, 2), 178 | DATA_PLAY(1, NOTE_E4, 2), 179 | DATA_PLAY(2, NOTE_E5, 2), 180 | DATA_PLAY(1, NOTE_E4, 2), 181 | // 22 182 | DATA_PLAY(2, NOTE_E5, 2), 183 | DATA_PLAY(2, NOTE_E5, 2), 184 | DATA_PLAY(2, NOTE_E5, 2), 185 | DATA_PLAY(3, NOTE_Eb5, 2), 186 | DATA_PLAY(2, NOTE_E5, 2), 187 | DATA_PLAY(3, NOTE_Eb5, 2), 188 | // 23 189 | DATA_PLAY(2, NOTE_E5, 2), 190 | DATA_PLAY(3, NOTE_Eb5, 2), 191 | DATA_PLAY(2, NOTE_E5, 2), 192 | DATA_PLAY(3, NOTE_Eb5, 2), 193 | DATA_PLAY(2, NOTE_E5, 2), 194 | DATA_PLAY(3, NOTE_Eb5, 2), 195 | // 24 196 | DATA_PLAY(2, NOTE_E5, 2), 197 | DATA_PLAY(3, NOTE_Eb5, 2), 198 | DATA_PLAY(2, NOTE_E5, 2), 199 | DATA_PLAY(4, NOTE_B4, 2), 200 | DATA_PLAY(0, NOTE_D5, 2), 201 | DATA_PLAY(1, NOTE_C5, 2), 202 | // 25 203 | DATA_PLAY(2, NOTE_A4, 0), 204 | DATA_PLAY(3, NOTE_A2, 2), 205 | DATA_PLAY(4, NOTE_E3, 2), 206 | DATA_PLAY(0, NOTE_A3, 2), 207 | DATA_PLAY(1, NOTE_C4, 2), 208 | DATA_PLAY(2, NOTE_E4, 2), 209 | DATA_PLAY(3, NOTE_A4, 2), 210 | // 26 211 | DATA_PLAY(4, NOTE_B4, 0), 212 | DATA_PLAY(0, NOTE_E2, 2), 213 | DATA_PLAY(1, NOTE_E3, 2), 214 | DATA_PLAY(2, NOTE_Ab3, 2), 215 | DATA_PLAY(3, NOTE_E4, 2), 216 | DATA_PLAY(4, NOTE_Ab4, 2), 217 | DATA_PLAY(0, NOTE_B4, 2), 218 | // 27 219 | DATA_PLAY(1, NOTE_C5, 0), 220 | DATA_PLAY(2, NOTE_A2, 2), 221 | DATA_PLAY(3, NOTE_E3, 2), 222 | DATA_PLAY(4, NOTE_A3, 2), 223 | DATA_PLAY(0, NOTE_E4, 2), 224 | DATA_PLAY(1, NOTE_E5, 2), 225 | DATA_PLAY(2, NOTE_Eb5, 2), 226 | // 28 227 | DATA_PLAY(1, NOTE_E5, 2), 228 | DATA_PLAY(2, NOTE_Eb5, 2), 229 | DATA_PLAY(1, NOTE_E5, 2), 230 | DATA_PLAY(3, NOTE_B4, 2), 231 | DATA_PLAY(4, NOTE_D5, 2), 232 | DATA_PLAY(0, NOTE_C5, 2), 233 | // 29 234 | DATA_PLAY(1, NOTE_A4, 0), 235 | DATA_PLAY(2, NOTE_A2, 2), 236 | DATA_PLAY(3, NOTE_E3, 2), 237 | DATA_PLAY(4, NOTE_A3, 2), 238 | DATA_PLAY(0, NOTE_C4, 2), 239 | DATA_PLAY(1, NOTE_E4, 2), 240 | DATA_PLAY(2, NOTE_A4, 2), 241 | // 30 242 | DATA_PLAY(3, NOTE_B4, 0), 243 | DATA_PLAY(4, NOTE_E2, 2), 244 | DATA_PLAY(0, NOTE_E3, 2), 245 | DATA_PLAY(1, NOTE_Ab3, 2), 246 | DATA_PLAY(2, NOTE_E4, 2), 247 | DATA_PLAY(3, NOTE_C5, 2), 248 | DATA_PLAY(4, NOTE_B4, 2), 249 | // 31 250 | DATA_PLAY(0, NOTE_A4, 0), 251 | DATA_PLAY(1, NOTE_A2, 2), 252 | DATA_PLAY(2, NOTE_E3, 2), 253 | DATA_PLAY(3, NOTE_A3, 2), 254 | DATA_PLAY(4, NOTE_B4, 2), 255 | DATA_PLAY(4, NOTE_C5, 2), 256 | DATA_PLAY(0, NOTE_D5, 2), 257 | // 32 258 | DATA_PLAY(1, NOTE_E5, 0), 259 | DATA_PLAY(2, NOTE_C3, 2), 260 | DATA_PLAY(3, NOTE_G3, 2), 261 | DATA_PLAY(4, NOTE_C4, 2), 262 | DATA_PLAY(0, NOTE_G4, 2), 263 | DATA_PLAY(1, NOTE_F5, 2), 264 | DATA_PLAY(2, NOTE_E5, 2), 265 | // 33 266 | DATA_PLAY(3, NOTE_D5, 0), 267 | DATA_PLAY(4, NOTE_G2, 2), 268 | DATA_PLAY(0, NOTE_G3, 2), 269 | DATA_PLAY(1, NOTE_A3, 2), 270 | DATA_PLAY(2, NOTE_F4, 2), 271 | DATA_PLAY(3, NOTE_E5, 2), 272 | DATA_PLAY(4, NOTE_D5, 2), 273 | // 34 274 | DATA_PLAY(0, NOTE_C5, 0), 275 | DATA_PLAY(1, NOTE_A2, 2), 276 | DATA_PLAY(2, NOTE_E3, 2), 277 | DATA_PLAY(3, NOTE_A3, 2), 278 | DATA_PLAY(4, NOTE_E4, 2), 279 | DATA_PLAY(0, NOTE_D5, 2), 280 | DATA_PLAY(1, NOTE_C5, 2), 281 | // 35 282 | DATA_PLAY(2, NOTE_B4, 0), 283 | DATA_PLAY(3, NOTE_E2, 2), 284 | DATA_PLAY(4, NOTE_E3, 2), 285 | DATA_PLAY(0, NOTE_E4, 2), 286 | DATA_PLAY(0, NOTE_E4, 2), 287 | DATA_PLAY(1, NOTE_E5, 2), 288 | DATA_PLAY(0, NOTE_E4, 2), 289 | // 36 290 | DATA_PLAY(1, NOTE_E5, 2), 291 | DATA_PLAY(1, NOTE_E5, 2), 292 | DATA_PLAY(1, NOTE_E5, 2), 293 | DATA_PLAY(2, NOTE_Eb5, 2), 294 | DATA_PLAY(1, NOTE_E5, 2), 295 | DATA_PLAY(2, NOTE_Eb5, 2), 296 | // 37 297 | DATA_PLAY(1, NOTE_E5, 2), 298 | DATA_PLAY(2, NOTE_Eb5, 2), 299 | DATA_PLAY(1, NOTE_E5, 2), 300 | DATA_PLAY(2, NOTE_Eb5, 2), 301 | DATA_PLAY(1, NOTE_E5, 2), 302 | DATA_PLAY(2, NOTE_Eb5, 2), 303 | // 38 304 | DATA_PLAY(1, NOTE_E5, 2), 305 | DATA_PLAY(2, NOTE_Eb5, 2), 306 | DATA_PLAY(1, NOTE_E5, 2), 307 | DATA_PLAY(3, NOTE_B4, 2), 308 | DATA_PLAY(4, NOTE_D5, 2), 309 | DATA_PLAY(0, NOTE_C5, 2), 310 | // 39 311 | DATA_PLAY(1, NOTE_A4, 0), 312 | DATA_PLAY(2, NOTE_A2, 2), 313 | DATA_PLAY(3, NOTE_E3, 2), 314 | DATA_PLAY(4, NOTE_A3, 2), 315 | DATA_PLAY(0, NOTE_C4, 2), 316 | DATA_PLAY(1, NOTE_E4, 2), 317 | DATA_PLAY(2, NOTE_A4, 2), 318 | // 40 319 | DATA_PLAY(3, NOTE_B4, 0), 320 | DATA_PLAY(4, NOTE_E2, 2), 321 | DATA_PLAY(0, NOTE_E3, 2), 322 | DATA_PLAY(1, NOTE_Ab3, 2), 323 | DATA_PLAY(2, NOTE_E4, 2), 324 | DATA_PLAY(3, NOTE_Ab4, 2), 325 | DATA_PLAY(4, NOTE_B4, 2), 326 | // 41 327 | DATA_PLAY(0, NOTE_C5, 0), 328 | DATA_PLAY(1, NOTE_A2, 2), 329 | DATA_PLAY(2, NOTE_E3, 2), 330 | DATA_PLAY(3, NOTE_A3, 2), 331 | DATA_PLAY(4, NOTE_E4, 2), 332 | DATA_PLAY(0, NOTE_E5, 2), 333 | DATA_PLAY(1, NOTE_Eb5, 2), 334 | // 42 335 | DATA_PLAY(0, NOTE_E5, 2), 336 | DATA_PLAY(1, NOTE_Eb5, 2), 337 | DATA_PLAY(0, NOTE_E5, 2), 338 | DATA_PLAY(2, NOTE_B4, 2), 339 | DATA_PLAY(3, NOTE_D5, 2), 340 | DATA_PLAY(4, NOTE_C5, 2), 341 | // 43 342 | DATA_PLAY(0, NOTE_A4, 0), 343 | DATA_PLAY(1, NOTE_A2, 2), 344 | DATA_PLAY(2, NOTE_E3, 2), 345 | DATA_PLAY(3, NOTE_A3, 2), 346 | DATA_PLAY(4, NOTE_C4, 2), 347 | DATA_PLAY(0, NOTE_E4, 2), 348 | DATA_PLAY(1, NOTE_A4, 2), 349 | // 44 350 | DATA_PLAY(2, NOTE_B4, 0), 351 | DATA_PLAY(3, NOTE_E2, 2), 352 | DATA_PLAY(4, NOTE_E3, 2), 353 | DATA_PLAY(0, NOTE_Ab3, 2), 354 | DATA_PLAY(1, NOTE_E4, 2), 355 | DATA_PLAY(2, NOTE_C5, 2), 356 | DATA_PLAY(3, NOTE_B4, 2), 357 | // 45 358 | DATA_PLAY(4, NOTE_A4, 0), 359 | DATA_PLAY(0, NOTE_A2, 2), 360 | DATA_PLAY(1, NOTE_E3, 2), 361 | DATA_PLAY(2, NOTE_A3, 2), 362 | DATA_PLAY(3, NOTE_C5, 0), 363 | DATA_PLAY(4, NOTE_E4, 0), 364 | DATA_PLAY(0, NOTE_C4, 0), 365 | DATA_PLAY(1, NOTE_Bb3, 2), 366 | DATA_PLAY(3, NOTE_C5, 0), 367 | DATA_PLAY(2, NOTE_F4, 0), 368 | DATA_PLAY(0, NOTE_C4, 0), 369 | DATA_PLAY(3, NOTE_A3, 2), 370 | DATA_PLAY(4, NOTE_C5, 0), 371 | DATA_PLAY(0, NOTE_G4, 0), 372 | DATA_PLAY(1, NOTE_E4, 0), 373 | DATA_PLAY(2, NOTE_Bb3, 0), 374 | DATA_PLAY(3, NOTE_G3, 2), 375 | // 46 376 | DATA_PLAY(4, NOTE_C5, 0), 377 | DATA_PLAY(4, NOTE_F3, 2), 378 | DATA_PLAY(0, NOTE_A3, 2), 379 | DATA_PLAY(1, NOTE_C4, 2), 380 | DATA_PLAY(0, NOTE_A3, 2), 381 | DATA_PLAY(2, NOTE_F5, 0), 382 | DATA_PLAY(1, NOTE_C4, 2), 383 | DATA_PLAY(0, NOTE_A3, 1), 384 | DATA_PLAY(3, NOTE_E5, 1), 385 | // 47 386 | DATA_PLAY(3, NOTE_E5, 0), 387 | DATA_PLAY(4, NOTE_F3, 2), 388 | DATA_PLAY(4, NOTE_Bb3, 2), 389 | DATA_PLAY(0, NOTE_D4, 2), 390 | DATA_PLAY(4, NOTE_Bb3, 2), 391 | DATA_PLAY(1, NOTE_Bb5, 0), 392 | DATA_PLAY(0, NOTE_D4, 2), 393 | DATA_PLAY(4, NOTE_Bb3, 1), 394 | DATA_PLAY(2, NOTE_A5, 1), 395 | // 48 396 | DATA_PLAY(2, NOTE_A5, 0), 397 | DATA_PLAY(3, NOTE_F3, 2), 398 | DATA_PLAY(4, NOTE_G5, 0), 399 | DATA_PLAY(0, NOTE_E4, 2), 400 | DATA_PLAY(1, NOTE_F5, 0), 401 | DATA_PLAY(2, NOTE_Bb3, 0), 402 | DATA_PLAY(3, NOTE_G3, 0), 403 | DATA_PLAY(4, NOTE_F3, 2), 404 | DATA_PLAY(0, NOTE_E5, 0), 405 | DATA_PLAY(1, NOTE_E4, 2), 406 | DATA_PLAY(2, NOTE_D5, 0), 407 | DATA_PLAY(3, NOTE_Bb3, 0), 408 | DATA_PLAY(4, NOTE_G3, 0), 409 | DATA_PLAY(0, NOTE_F3, 2), 410 | DATA_PLAY(1, NOTE_C5, 0), 411 | DATA_PLAY(2, NOTE_E4, 2), 412 | // 49 413 | DATA_PLAY(3, NOTE_Bb4, 0), 414 | DATA_PLAY(0, NOTE_F3, 2), 415 | DATA_PLAY(4, NOTE_A3, 2), 416 | DATA_PLAY(0, NOTE_A4, 0), 417 | DATA_PLAY(1, NOTE_C4, 2), 418 | DATA_PLAY(4, NOTE_A3, 2), 419 | DATA_PLAY(0, NOTE_A4, 0), 420 | DATA_PLAY(1, NOTE_C4, 1), 421 | DATA_PLAY(2, NOTE_G4, 1), 422 | DATA_PLAY(0, NOTE_A4, 0), 423 | DATA_PLAY(4, NOTE_A3, 1), 424 | DATA_PLAY(3, NOTE_Bb4, 1), 425 | // 50 426 | DATA_PLAY(3, NOTE_C5, 0), 427 | DATA_PLAY(4, NOTE_F3, 2), 428 | DATA_PLAY(0, NOTE_A3, 2), 429 | DATA_PLAY(1, NOTE_C4, 2), 430 | DATA_PLAY(0, NOTE_A3, 2), 431 | DATA_PLAY(1, NOTE_D5, 0), 432 | DATA_PLAY(2, NOTE_C4, 2), 433 | DATA_PLAY(3, NOTE_Eb5, 0), 434 | DATA_PLAY(0, NOTE_A3, 2), 435 | // 51 436 | DATA_PLAY(4, NOTE_E5, 0), 437 | DATA_PLAY(0, NOTE_E3, 2), 438 | DATA_PLAY(1, NOTE_A3, 2), 439 | DATA_PLAY(2, NOTE_C4, 2), 440 | DATA_PLAY(4, NOTE_E5, 0), 441 | DATA_PLAY(1, NOTE_A3, 2), 442 | DATA_PLAY(2, NOTE_F5, 0), 443 | DATA_PLAY(3, NOTE_D4, 0), 444 | DATA_PLAY(4, NOTE_D3, 2), 445 | DATA_PLAY(0, NOTE_A4, 0), 446 | DATA_PLAY(1, NOTE_F3, 2), 447 | // 52 448 | DATA_PLAY(2, NOTE_C5, 0), 449 | DATA_PLAY(3, NOTE_G3, 2), 450 | DATA_PLAY(4, NOTE_E4, 2), 451 | DATA_PLAY(3, NOTE_G3, 2), 452 | DATA_PLAY(4, NOTE_E4, 2), 453 | DATA_PLAY(0, NOTE_D5, 0), 454 | DATA_PLAY(3, NOTE_G3, 2), 455 | DATA_PLAY(1, NOTE_G4, 1), 456 | DATA_PLAY(2, NOTE_B4, 1), 457 | // 53 458 | DATA_PLAY(0, NOTE_D5, 0), 459 | DATA_PLAY(4, NOTE_E4, 0), 460 | DATA_PLAY(3, NOTE_C4, 1), 461 | DATA_PLAY(4, NOTE_G5, 1), 462 | DATA_PLAY(1, NOTE_G4, 1), 463 | DATA_PLAY(4, NOTE_G5, 1), 464 | DATA_PLAY(0, NOTE_A4, 1), 465 | DATA_PLAY(4, NOTE_G5, 1), 466 | DATA_PLAY(2, NOTE_B4, 0), 467 | DATA_PLAY(1, NOTE_G4, 0), 468 | DATA_PLAY(1, NOTE_F4, 1), 469 | DATA_PLAY(4, NOTE_G5, 1), 470 | DATA_PLAY(2, NOTE_C5, 0), 471 | DATA_PLAY(3, NOTE_G4, 0), 472 | DATA_PLAY(4, NOTE_E4, 1), 473 | DATA_PLAY(0, NOTE_G5, 1), 474 | DATA_PLAY(1, NOTE_D5, 0), 475 | DATA_PLAY(3, NOTE_G4, 0), 476 | DATA_PLAY(2, NOTE_F4, 0), 477 | DATA_PLAY(3, NOTE_D4, 1), 478 | DATA_PLAY(0, NOTE_G5, 1), 479 | // 54 480 | DATA_PLAY(4, NOTE_E5, 0), 481 | DATA_PLAY(0, NOTE_G4, 0), 482 | DATA_PLAY(1, NOTE_E4, 0), 483 | DATA_PLAY(2, NOTE_C4, 1), 484 | DATA_PLAY(3, NOTE_G5, 1), 485 | DATA_PLAY(4, NOTE_C6, 1), 486 | DATA_PLAY(0, NOTE_B5, 1), 487 | DATA_PLAY(1, NOTE_A5, 0), 488 | DATA_PLAY(2, NOTE_A3, 0), 489 | DATA_PLAY(3, NOTE_F3, 1), 490 | DATA_PLAY(4, NOTE_G5, 1), 491 | DATA_PLAY(0, NOTE_F5, 1), 492 | DATA_PLAY(1, NOTE_E5, 1), 493 | DATA_PLAY(2, NOTE_D5, 0), 494 | DATA_PLAY(3, NOTE_B3, 0), 495 | DATA_PLAY(4, NOTE_G3, 1), 496 | DATA_PLAY(0, NOTE_G5, 1), 497 | DATA_PLAY(1, NOTE_F5, 1), 498 | DATA_PLAY(2, NOTE_D5, 1), 499 | // 55 500 | DATA_PLAY(2, NOTE_D5, 0), 501 | DATA_PLAY(2, NOTE_E4, 0), 502 | DATA_PLAY(3, NOTE_C4, 1), 503 | DATA_PLAY(0, NOTE_G5, 1), 504 | DATA_PLAY(4, NOTE_G4, 1), 505 | DATA_PLAY(0, NOTE_G5, 1), 506 | DATA_PLAY(0, NOTE_A4, 1), 507 | DATA_PLAY(1, NOTE_G5, 1), 508 | DATA_PLAY(2, NOTE_B4, 0), 509 | DATA_PLAY(4, NOTE_G4, 0), 510 | DATA_PLAY(3, NOTE_F4, 1), 511 | DATA_PLAY(1, NOTE_G5, 1), 512 | DATA_PLAY(4, NOTE_C5, 0), 513 | DATA_PLAY(0, NOTE_G4, 0), 514 | DATA_PLAY(1, NOTE_E4, 1), 515 | DATA_PLAY(2, NOTE_G5, 1), 516 | DATA_PLAY(3, NOTE_D5, 0), 517 | DATA_PLAY(0, NOTE_G4, 0), 518 | DATA_PLAY(4, NOTE_F4, 0), 519 | DATA_PLAY(0, NOTE_D4, 1), 520 | DATA_PLAY(2, NOTE_G5, 1), 521 | // 56 522 | DATA_PLAY(1, NOTE_E5, 0), 523 | DATA_PLAY(2, NOTE_G4, 0), 524 | DATA_PLAY(3, NOTE_E4, 0), 525 | DATA_PLAY(4, NOTE_C4, 1), 526 | DATA_PLAY(0, NOTE_G5, 1), 527 | DATA_PLAY(1, NOTE_C6, 1), 528 | DATA_PLAY(2, NOTE_B5, 1), 529 | DATA_PLAY(3, NOTE_A5, 0), 530 | DATA_PLAY(4, NOTE_A3, 0), 531 | DATA_PLAY(0, NOTE_F3, 1), 532 | DATA_PLAY(1, NOTE_G5, 1), 533 | DATA_PLAY(2, NOTE_F5, 1), 534 | DATA_PLAY(3, NOTE_E5, 1), 535 | DATA_PLAY(4, NOTE_D5, 0), 536 | DATA_PLAY(0, NOTE_B3, 0), 537 | DATA_PLAY(1, NOTE_G3, 1), 538 | DATA_PLAY(2, NOTE_G5, 1), 539 | DATA_PLAY(3, NOTE_F5, 1), 540 | DATA_PLAY(4, NOTE_D5, 1), 541 | // 57 542 | DATA_PLAY(4, NOTE_E5, 0), 543 | DATA_PLAY(0, NOTE_A3, 0), 544 | DATA_PLAY(1, NOTE_Ab3, 1), 545 | DATA_PLAY(3, NOTE_F5, 1), 546 | DATA_PLAY(4, NOTE_E5, 1), 547 | DATA_PLAY(2, NOTE_Eb5, 1), 548 | DATA_PLAY(4, NOTE_E5, 1), 549 | DATA_PLAY(3, NOTE_B4, 1), 550 | DATA_PLAY(4, NOTE_E5, 1), 551 | DATA_PLAY(2, NOTE_Eb5, 1), 552 | DATA_PLAY(4, NOTE_E5, 1), 553 | DATA_PLAY(3, NOTE_B4, 1), 554 | DATA_PLAY(4, NOTE_E5, 1), 555 | DATA_PLAY(2, NOTE_Eb5, 1), 556 | // 58 557 | DATA_PLAY(4, NOTE_E5, 6), 558 | DATA_PLAY(3, NOTE_B4, 2), 559 | DATA_PLAY(4, NOTE_E5, 2), 560 | DATA_PLAY(2, NOTE_Eb5, 2), 561 | // 59 562 | DATA_PLAY(4, NOTE_E5, 0), 563 | DATA_WAIT(24), 564 | 565 | DATA_END() 566 | }; 567 | 568 | -------------------------------------------------------------------------------- /demos/wavepot.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Test tool for microsound library. Use it on http://wavepot.com/ 3 | * https://github.com/masyamandev/microsound 4 | * 5 | * Author: Aleksandr Maksymenko aka masyaman 6 | */ 7 | 8 | 9 | 10 | /* 11 | * Notes 12 | */ 13 | 14 | var NOTE_SILENCE = 0; 15 | var NOTE_C1 = 1; 16 | var NOTE_Db1 = 2; 17 | var NOTE_D1 = 3; 18 | var NOTE_Eb1 = 4; 19 | var NOTE_E1 = 5; 20 | var NOTE_F1 = 6; 21 | var NOTE_Gb1 = 7; 22 | var NOTE_G1 = 8; 23 | var NOTE_Ab1 = 9; 24 | var NOTE_A1 = 10; 25 | var NOTE_Bb1 = 11; 26 | var NOTE_B1 = 12; 27 | var NOTE_C2 = 13; 28 | var NOTE_Db2 = 14; 29 | var NOTE_D2 = 15; 30 | var NOTE_Eb2 = 16; 31 | var NOTE_E2 = 17; 32 | var NOTE_F2 = 18; 33 | var NOTE_Gb2 = 19; 34 | var NOTE_G2 = 20; 35 | var NOTE_Ab2 = 21; 36 | var NOTE_A2 = 22; 37 | var NOTE_Bb2 = 23; 38 | var NOTE_B2 = 24; 39 | var NOTE_C3 = 25; 40 | var NOTE_Db3 = 26; 41 | var NOTE_D3 = 27; 42 | var NOTE_Eb3 = 28; 43 | var NOTE_E3 = 29; 44 | var NOTE_F3 = 30; 45 | var NOTE_Gb3 = 31; 46 | var NOTE_G3 = 32; 47 | var NOTE_Ab3 = 33; 48 | var NOTE_A3 = 34; 49 | var NOTE_Bb3 = 35; 50 | var NOTE_B3 = 36; 51 | var NOTE_C4 = 37; 52 | var NOTE_Db4 = 38; 53 | var NOTE_D4 = 39; 54 | var NOTE_Eb4 = 40; 55 | var NOTE_E4 = 41; 56 | var NOTE_F4 = 42; 57 | var NOTE_Gb4 = 43; 58 | var NOTE_G4 = 44; 59 | var NOTE_Ab4 = 45; 60 | var NOTE_A4 = 46; 61 | var NOTE_Bb4 = 47; 62 | var NOTE_B4 = 48; 63 | var NOTE_C5 = 49; 64 | var NOTE_Db5 = 50; 65 | var NOTE_D5 = 51; 66 | var NOTE_Eb5 = 52; 67 | var NOTE_E5 = 53; 68 | var NOTE_F5 = 54; 69 | var NOTE_Gb5 = 55; 70 | var NOTE_G5 = 56; 71 | var NOTE_Ab5 = 57; 72 | var NOTE_A5 = 58; 73 | var NOTE_Bb5 = 59; 74 | var NOTE_B5 = 60; 75 | var NOTE_C6 = 61; 76 | 77 | var frequencies = [ 78 | 0, 79 | 32.703, 34.648, 36.708, 38.891, 41.203, 43.654, 46.249, 48.999, 51.913, 55.000, 58.270, 61.735, 80 | 65.406, 69.296, 73.416, 77.782, 82.407, 87.307, 92.499, 97.999, 103.826, 110.000, 116.541, 123.471, 81 | 130.813, 138.591, 146.832, 155.563, 164.814, 174.614, 184.997, 195.998, 207.652, 220.000, 233.082, 246.942, 82 | 261.626, 277.183, 293.665, 311.127, 329.628, 349.228, 369.994, 391.995, 415.305, 440.000, 466.164, 493.883, 83 | 523.251, 554.365, 587.330, 622.254, 659.255, 698.456, 739.989, 783.991, 830.609, 880.000, 932.328, 987.767, 84 | 1046.502]; 85 | 86 | var OVERDRIVE_SHORT = 128; 87 | var PERCUSSION_HAT_H = 0; 88 | var PERCUSSION_HAT_L = 1; 89 | var PERCUSSION_BAR_H = 2; 90 | var PERCUSSION_BAR_L = 3; 91 | 92 | /* 93 | * Data 94 | */ 95 | 96 | var simulate8bits = true; 97 | var CHANNELS = 5; 98 | 99 | var PERC = 0; 100 | var BASS = 1; 101 | var HRMN = 2; 102 | var OVRD = 3; 103 | 104 | var soundData = [ 105 | DATA_TEMPO(480), 106 | DATA_INSTRUMENT(PERC, SAMPLE_PERCUSSION), 107 | DATA_INSTRUMENT(BASS, SAMPLE_BASS), 108 | DATA_INSTRUMENT(HRMN, SAMPLE_HARMONICA), 109 | DATA_INSTRUMENT(OVRD, SAMPLE_OVERDRIVE), 110 | // DATA_INSTRUMENT(BASS, SAMPLE_MUSICBOX), 111 | // DATA_INSTRUMENT(HRMN, SAMPLE_MUSICBOX), 112 | // DATA_INSTRUMENT(OVRD, SAMPLE_MUSICBOX), 113 | DATA_VOLUME(PERC, 80), 114 | DATA_VOLUME(HRMN, 64), 115 | DATA_VOLUME(BASS, 32), 116 | DATA_VOLUME(OVRD, 64), 117 | // DATA_VOLUME(PERC, 0), 118 | // DATA_VOLUME(HRMN, 64), 119 | // DATA_VOLUME(BASS, 0), 120 | // DATA_VOLUME(OVRD, 0), 121 | 122 | // DATA_PLAY(PERC, PERCUSSION_HAT_H, 1), 123 | // DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 124 | // DATA_PLAY(PERC, PERCUSSION_BAR_H, 1), 125 | // DATA_PLAY(PERC, PERCUSSION_BAR_L, 1), 126 | // DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 127 | // DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 128 | // DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 129 | // DATA_PLAY(PERC, PERCUSSION_BAR_L, 2), 130 | // DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 131 | // DATA_END(), 132 | 133 | DATA_PLAY(HRMN, NOTE_C4, 1), 134 | DATA_PLAY(HRMN, NOTE_D4, 0), 135 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 136 | 137 | DATA_PLAY(HRMN, NOTE_E4, 0), 138 | DATA_PLAY(BASS, NOTE_C2, 0), 139 | DATA_PLAY(PERC, PERCUSSION_BAR_L, 2), 140 | DATA_PLAY(HRMN, NOTE_G4, 0), 141 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 142 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 143 | DATA_PLAY(HRMN, NOTE_G4, 0), 144 | DATA_PLAY(OVRD, NOTE_C3, 0), 145 | DATA_PLAY(BASS, NOTE_E2, 0), 146 | DATA_PLAY(PERC, PERCUSSION_BAR_L, 3), 147 | DATA_PLAY(HRMN, NOTE_A4, 0), 148 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 149 | 150 | DATA_PLAY(HRMN, NOTE_G4, 0), 151 | DATA_PLAY(BASS, NOTE_C2, 0), 152 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 153 | DATA_PLAY(HRMN, NOTE_E4, 0), 154 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 155 | DATA_PLAY(PERC, PERCUSSION_BAR_L, 2), 156 | DATA_PLAY(HRMN, NOTE_C4, 0), 157 | DATA_PLAY(OVRD, NOTE_C3, 0), 158 | DATA_PLAY(BASS, NOTE_G1, 0), 159 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 3), 160 | DATA_PLAY(HRMN, NOTE_D4, 1), 161 | 162 | DATA_PLAY(HRMN, NOTE_E4, 0), 163 | DATA_PLAY(BASS, NOTE_C2, 0), 164 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 165 | DATA_PLAY(HRMN, NOTE_E4, 0), 166 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 167 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 168 | DATA_PLAY(HRMN, NOTE_D4, 0), 169 | DATA_PLAY(OVRD, NOTE_C3, 0), 170 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 171 | DATA_PLAY(HRMN, NOTE_C4, 0), 172 | DATA_PLAY(OVRD, NOTE_G3 | OVERDRIVE_SHORT, 0), 173 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 174 | 175 | 176 | DATA_PLAY(HRMN, NOTE_D4, 0), 177 | DATA_PLAY(OVRD, NOTE_G3, 0), // check this 178 | DATA_PLAY(BASS, NOTE_G2, 0), 179 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 180 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 181 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 182 | DATA_PLAY(HRMN, NOTE_C4, 1), 183 | DATA_PLAY(HRMN, NOTE_D4, 0), 184 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 185 | 186 | DATA_PLAY(HRMN, NOTE_E4, 0), 187 | DATA_PLAY(BASS, NOTE_C2, 0), 188 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 189 | DATA_PLAY(HRMN, NOTE_G4, 0), 190 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 191 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 192 | DATA_PLAY(HRMN, NOTE_G4, 0), 193 | DATA_PLAY(OVRD, NOTE_C3, 0), 194 | DATA_PLAY(BASS, NOTE_E2, 0), 195 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 3), 196 | DATA_PLAY(HRMN, NOTE_A4, 0), 197 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 198 | 199 | DATA_PLAY(HRMN, NOTE_G4, 0), 200 | DATA_PLAY(BASS, NOTE_C2, 0), 201 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 2), 202 | DATA_PLAY(HRMN, NOTE_E4, 0), 203 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 204 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 205 | DATA_PLAY(HRMN, NOTE_C4, 0), 206 | DATA_PLAY(OVRD, NOTE_C3, 0), 207 | DATA_PLAY(BASS, NOTE_G1, 0), 208 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 3), 209 | DATA_PLAY(HRMN, NOTE_D4, 0), 210 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 1), 211 | 212 | DATA_PLAY(HRMN, NOTE_E4, 0), 213 | DATA_PLAY(OVRD, NOTE_G3 | OVERDRIVE_SHORT, 0), 214 | DATA_PLAY(BASS, NOTE_C2, 0), 215 | DATA_PLAY(PERC, PERCUSSION_BAR_L, 2), 216 | DATA_PLAY(HRMN, NOTE_E4, 0), 217 | DATA_PLAY(OVRD, NOTE_G3 | OVERDRIVE_SHORT, 0), 218 | DATA_PLAY(BASS, NOTE_C2, 0), 219 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 220 | DATA_PLAY(HRMN, NOTE_D4, 0), 221 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 222 | DATA_PLAY(BASS, NOTE_A1, 0), 223 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 224 | DATA_PLAY(HRMN, NOTE_D4, 0), 225 | DATA_PLAY(OVRD, NOTE_C3 | OVERDRIVE_SHORT, 0), 226 | DATA_PLAY(BASS, NOTE_G1, 0), 227 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 228 | 229 | DATA_PLAY(HRMN, NOTE_C4, 0), 230 | DATA_PLAY(OVRD, NOTE_C3, 0), 231 | DATA_PLAY(BASS, NOTE_C2, 0), 232 | DATA_PLAY(PERC, PERCUSSION_BAR_H, 2), 233 | DATA_PLAY(BASS, NOTE_G2, 0), 234 | DATA_PLAY(PERC, PERCUSSION_HAT_L, 2), 235 | DATA_PLAY(BASS, NOTE_C3, 0), 236 | DATA_PLAY(PERC, PERCUSSION_HAT_H, 6), 237 | 238 | 239 | DATA_TEMPO(480 * 4), 240 | DATA_VOLUME(HRMN, 56), 241 | DATA_VOLUME(OVRD, 28), 242 | DATA_VOLUME(BASS, 56), 243 | DATA_WAIT(1), 244 | DATA_VOLUME(HRMN, 56), 245 | DATA_VOLUME(OVRD, 24), 246 | DATA_VOLUME(BASS, 48), 247 | DATA_WAIT(1), 248 | DATA_VOLUME(HRMN, 40), 249 | DATA_VOLUME(OVRD, 20), 250 | DATA_VOLUME(BASS, 40), 251 | DATA_WAIT(1), 252 | DATA_VOLUME(HRMN, 32), 253 | DATA_VOLUME(OVRD, 16), 254 | DATA_VOLUME(BASS, 32), 255 | DATA_WAIT(1), 256 | DATA_VOLUME(HRMN, 24), 257 | DATA_VOLUME(OVRD, 12), 258 | DATA_VOLUME(BASS, 24), 259 | DATA_WAIT(1), 260 | DATA_VOLUME(HRMN, 16), 261 | DATA_VOLUME(OVRD, 8), 262 | DATA_VOLUME(BASS, 16), 263 | DATA_WAIT(1), 264 | DATA_VOLUME(HRMN, 8), 265 | DATA_VOLUME(OVRD, 4), 266 | DATA_VOLUME(BASS, 8), 267 | DATA_WAIT(1), 268 | DATA_VOLUME(HRMN, 0), 269 | DATA_VOLUME(OVRD, 0), 270 | DATA_VOLUME(BASS, 0), 271 | DATA_WAIT(16), 272 | 273 | DATA_END() 274 | ]; 275 | 276 | 277 | /* 278 | * Instruments 279 | */ 280 | var expNegTable = [ 281 | 255, 249, 244, 238, 233, 228, 223, 219, 214, 209, 205, 200, 196, 192, 188, 184, 282 | 180, 176, 172, 168, 165, 161, 158, 154, 151, 148, 145, 142, 139, 136, 133, 130, 283 | 127, 124, 122, 119, 116, 114, 111, 109, 107, 104, 102, 100, 98, 96, 94, 92, 284 | 90, 88, 86, 84, 82, 80, 79, 77, 75, 74, 72, 71, 69, 68, 66, 65, 285 | 63, 62, 61, 59, 58, 57, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 286 | 45, 44, 43, 42, 41, 40, 39, 38, 37, 37, 36, 35, 34, 34, 33, 32, 287 | 31, 31, 30, 29, 29, 28, 27, 27, 26, 26, 25, 25, 24, 24, 23, 23, 288 | 22, 22, 21, 21, 20, 20, 19, 19, 18, 18, 18, 17, 17, 17, 16, 16, 289 | 15, 15, 15, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 290 | 11, 11, 10, 10, 10, 10, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 291 | 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 292 | 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 293 | 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 294 | 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 295 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 296 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 297 | 0]; 298 | 299 | 300 | var sinTable = [ 301 | 0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 302 | 48, 51, 54, 57, 59, 62, 65, 67, 70, 73, 75, 78, 80, 82, 85, 87, 303 | 89, 91, 94, 96, 98, 100, 102, 103, 105, 107, 108, 110, 112, 113, 114, 116, 304 | 117, 118, 119, 120, 121, 122, 123, 123, 124, 125, 125, 126, 126, 126, 126, 126, 305 | 127, 126, 126, 126, 126, 126, 125, 125, 124, 123, 123, 122, 121, 120, 119, 118, 306 | 117, 116, 114, 113, 112, 110, 108, 107, 105, 103, 102, 100, 98, 96, 94, 91, 307 | 89, 87, 85, 82, 80, 78, 75, 73, 70, 67, 65, 62, 59, 57, 54, 51, 308 | 48, 45, 42, 39, 36, 33, 30, 27, 24, 21, 18, 15, 12, 9, 6, 3, 309 | 0, -3, -6, -9, -12, -15, -18, -21, -24, -27, -30, -33, -36, -39, -42, -45, 310 | -48, -51, -54, -57, -59, -62, -65, -67, -70, -73, -75, -78, -80, -82, -85, -87, 311 | -89, -91, -94, -96, -98, -100, -102, -103, -105, -107, -108, -110, -112, -113, -114, -116, 312 | -117, -118, -119, -120, -121, -122, -123, -123, -124, -125, -125, -126, -126, -126, -126, -126, 313 | -127, -126, -126, -126, -126, -126, -125, -125, -124, -123, -123, -122, -121, -120, -119, -118, 314 | -117, -116, -114, -113, -112, -110, -108, -107, -105, -103, -102, -100, -98, -96, -94, -91, 315 | -89, -87, -85, -82, -80, -78, -75, -73, -70, -67, -65, -62, -59, -57, -54, -51, 316 | -48, -45, -42, -39, -36, -33, -30, -27, -24, -21, -18, -15, -12, -9, -6, -3, 317 | 0]; 318 | 319 | var pianoWaveTable = [ 320 | 0, 1, 3, 7, 12, 17, 24, 31, 38, 44, 50, 55, 58, 60, 60, 59, 321 | 56, 52, 49, 45, 43, 42, 43, 45, 48, 50, 51, 52, 51, 48, 45, 40, 322 | 36, 31, 26, 21, 16, 11, 6, 3, 0, -1, -3, -5, -8, -11, -15, -19, 323 | -24, -28, -31, -34, -35, -36, -34, -30, -26, -20, -15, -10, -6, -4, -2, 4, 324 | 10, 17, 21, 25, 27, 29, 31, 32, 32, 31, 29, 27, 24, 23, 24, 26, 325 | 30, 34, 38, 41, 44, 47, 50, 54, 58, 65, 72, 80, 88, 96, 104, 111, 326 | 118, 122, 125, 127, 125, 123, 119, 115, 109, 104, 98, 92, 86, 80, 75, 70, 327 | 67, 64, 61, 58, 55, 50, 46, 42, 38, 35, 33, 32, 32, 31, 30, 29, 328 | 28, 25, 22, 18, 13, 7, 0, -5, -10, -13, -13, -12, -10, -8, -6, -5, 329 | -6, -8, -12, -17, -24, -31, -38, -44, -48, -50, -51, -50, -48, -45, -41, -37, 330 | -33, -30, -27, -26, -26, -28, -30, -33, -36, -40, -43, -46, -50, -53, -56, -59, 331 | -61, -64, -67, -70, -72, -73, -73, -72, -71, -68, -64, -60, -55, -50, -45, -41, 332 | -39, -38, -37, -37, -38, -39, -40, -41, -41, -42, -43, -43, -45, -47, -49, -53, 333 | -58, -62, -67, -71, -73, -74, -74, -71, -66, -59, -52, -44, -37, -31, -27, -24, 334 | -24, -26, -29, -34, -40, -46, -53, -59, -65, -68, -70, -69, -66, -62, -56, -50, 335 | -44, -39, -36, -33, -31, -29, -26, -22, -17, -12, -8, -5, -3, -2, -1, -1, 336 | 0]; 337 | 338 | function SAMPLE_PIANO(channel, data, t) { 339 | console.log("play piano at " + t); 340 | channel.waveForm = pianoWaveTable; 341 | channel.frequency = frequencies[data % 64]; 342 | channel.volumeForm = expNegTable; 343 | channel.volumeTicksPerSample = 4; 344 | } 345 | 346 | 347 | function SAMPLE_SYNTH_PIANO(channel, data, t) { 348 | console.log("play synth piano at " + t); 349 | channel.waveForm = sinTable; 350 | channel.frequency = frequencies[data % 64]; 351 | channel.volumeForm = expNegTable; 352 | channel.volumeTicksPerSample = 2; 353 | } 354 | 355 | 356 | var bassGuitarWaveTable = [ 357 | 4, 19, 33, 47, 60, 72, 83, 92, 101, 108, 114, 119, 122, 125, 126, 127, 358 | 126, 125, 123, 120, 116, 112, 108, 103, 98, 92, 87, 81, 75, 70, 64, 59, 359 | 54, 49, 44, 40, 36, 32, 29, 25, 23, 20, 18, 16, 14, 13, 11, 10, 360 | 8, 7, 6, 5, 3, 2, 1, 0, -1, -2, -4, -5, -6, -7, -9, -10, 361 | -11, -11, -12, -13, -13, -13, -13, -14, -14, -13, -13, -13, -12, -12, -12, -11, 362 | -11, -10, -9, -9, -8, -8, -7, -6, -5, -4, -4, -3, -2, -1, 0, 0, 363 | 0, 1, 2, 2, 3, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 364 | 4, 3, 3, 2, 1, 1, 0, 0, -1, -2, -3, -4, -4, -5, -6, -6, 365 | -7, -7, -7, -7, -7, -7, -7, -6, -6, -6, -5, -5, -4, -4, -3, -3, 366 | -2, -2, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 367 | 0, 0, 0, 0, 0, -1, -1, -1, -1, -2, -2, -2, -3, -3, -3, -3, 368 | -3, -3, -3, -3, -3, -2, -2, -2, -1, -1, -1, 0, 0, 0, -1, -1, 369 | -2, -3, -4, -5, -7, -8, -10, -12, -14, -16, -18, -20, -21, -23, -24, -25, 370 | -26, -26, -26, -26, -25, -24, -23, -22, -20, -19, -17, -16, -16, -16, -17, -18, 371 | -20, -23, -27, -31, -36, -42, -49, -56, -63, -70, -78, -85, -92, -98, -104, -108, 372 | -112, -115, -116, -116, -115, -113, -109, -103, -96, -88, -78, -67, -55, -41, -26, -11, 373 | 4]; 374 | 375 | function SAMPLE_BASS(channel, data, t) { 376 | console.log("play bass at " + t); 377 | channel.waveForm = bassGuitarWaveTable; 378 | channel.frequency = frequencies[data % 64]; 379 | channel.volumeForm = expNegTable; 380 | channel.volumeTicksPerSample = 4; 381 | } 382 | 383 | 384 | var harmonicaWaveTable = [ 385 | 0, -11, -29, -39, -39, -37, -37, -45, -53, -53, -49, -43, -34, -24, -22, -17, 386 | -6, 6, 22, 39, 55, 69, 72, 72, 76, 78, 83, 85, 81, 79, 74, 63, 387 | 52, 47, 36, 17, 0, -19, -33, -40, -42, -48, -60, -75, -86, -94, -98, -95, 388 | -87, -75, -66, -55, -43, -27, -13, -2, 9, 18, 25, 31, 36, 40, 45, 48, 389 | 44, 36, 26, 19, 13, 7, 3, -4, -14, -26, -40, -51, -56, -61, -72, -78, 390 | -77, -77, -77, -73, -67, -61, -57, -52, -42, -31, -20, -9, 1, 10, 17, 27, 391 | 37, 44, 50, 52, 52, 50, 49, 50, 51, 45, 31, 14, 2, 0, -4, -13, 392 | -20, -24, -30, -32, -28, -26, -27, -22, -16, -10, 0, 14, 27, 30, 28, 26, 393 | 27, 33, 34, 34, 40, 42, 36, 33, 39, 41, 32, 22, 12, 5, 1, -1, 394 | -1, -6, -13, -14, -15, -16, -16, -20, -24, -27, -26, -24, -19, -14, -12, -13, 395 | -11, -12, -14, -15, -18, -23, -30, -35, -36, -35, -39, -46, -49, -52, -57, -63, 396 | -68, -65, -56, -50, -50, -51, -41, -28, -18, -12, -8, -2, 2, 5, 13, 25, 397 | 34, 37, 37, 35, 34, 35, 36, 30, 18, 7, 0, -7, -14, -18, -20, -26, 398 | -36, -44, -48, -48, -47, -44, -37, -32, -26, -17, -7, 5, 18, 32, 50, 70, 399 | 91, 111, 127, 124, 106, 87, 70, 64, 58, 54, 59, 53, 35, 20, 12, 1, 400 | -2, 12, 21, 22, 22, 27, 33, 33, 35, 45, 46, 34, 24, 17, 7, 3, 401 | 0]; 402 | 403 | var harmonicaVolumeTable = [ 404 | 16, 86, 142, 177, 199, 212, 220, 224, 225, 226, 225, 224, 222, 220, 218, 216, 405 | ]; 406 | 407 | function SAMPLE_HARMONICA(channel, data, t) { 408 | console.log("play harmonica at " + t); 409 | channel.waveForm = harmonicaWaveTable; 410 | channel.frequency = frequencies[data % 64 - 12]; 411 | channel.volumeForm = harmonicaVolumeTable; 412 | channel.volumeTicksPerSample = 2; 413 | } 414 | 415 | 416 | var overdrivenGuitarChordWaveTable = [ 417 | 0, 0, -5, -26, -47, -37, -23, -35, -51, -52, -58, -58, -51, -53, -74, -80, 418 | -74, -81, -93, -91, -84, -86, -93, -90, -82, -80, -85, -88, -87, -81, -66, -60, 419 | -63, -59, -49, -49, -55, -49, -37, -32, -22, -16, -17, -14, -6, -1, 5, 17, 420 | 25, 49, 44, 35, 39, 49, 66, 77, 86, 94, 101, 107, 115, 124, 127, 120, 421 | 105, 110, 124, 122, 100, 92, 98, 98, 96, 95, 71, 56, 65, 72, 49, 30, 422 | 28, 24, 13, 9, 13, 12, 3, -15, -38, -48, -39, -27, -27, -35, -32, -30, 423 | -38, -41, -40, -46, -55, -57, -57, -57, -45, -37, -46, -58, -61, -55, -45, -37, 424 | -34, -26, -32, -35, -33, -30, -18, -13, -13, -9, -2, 3, 5, 4, 4, 3, 425 | -5, -2, 4, -1, -18, -11, 5, 2, -11, -14, -19, -14, 1, 12, -3, -12, 426 | -9, -12, -16, -11, -5, -8, -12, -10, -10, -14, -25, -31, -26, -18, -4, -8, 427 | -23, -19, -3, 0, -12, -21, -18, -15, -10, -8, -11, -8, -5, -16, -22, -10, 428 | 1, 16, 5, -4, 0, 8, 19, 19, 17, 24, 35, 40, 42, 45, 47, 42, 429 | 27, 29, 46, 52, 36, 33, 40, 36, 32, 35, 24, 17, 24, 23, 1, -7, 430 | 4, 6, -1, -1, 5, 6, -1, -11, -17, -19, -12, 0, 7, 4, 7, 7, 431 | 3, 7, 21, 23, 13, 7, 9, 17, 33, 41, 32, 21, 19, 19, 22, 25, 432 | 23, 32, 30, 27, 23, 12, 19, 30, 36, 36, 30, 24, 22, 18, 13, 9, 433 | 0]; 434 | 435 | var overdrivenGuitarChordVolumeTableShort = [ 436 | 255, 248, 244, 238, 233, 228, 223, 219, 214, 209, 205, 200, 196, 192, 128, 64, 437 | 0]; 438 | 439 | function SAMPLE_OVERDRIVE(channel, data, t) { 440 | console.log("play overdriven guitar at " + t); 441 | channel.waveForm = overdrivenGuitarChordWaveTable; 442 | channel.frequency = frequencies[data % 64 - 12]; 443 | if (data > 64) { 444 | channel.volumeForm = overdrivenGuitarChordVolumeTableShort; 445 | channel.volumeTicksPerSample = 1; 446 | } else { 447 | channel.volumeForm = expNegTable; 448 | channel.volumeTicksPerSample = 8; 449 | } 450 | } 451 | 452 | var musicboxWaveTable = [ 453 | 0, 1, 4, 6, 9, 11, 13, 16, 18, 20, 22, 25, 28, 31, 34, 37, 454 | 40, 43, 45, 47, 50, 52, 55, 58, 61, 63, 66, 69, 72, 76, 79, 82, 455 | 85, 88, 90, 92, 95, 97, 100, 101, 102, 104, 105, 106, 107, 108, 109, 110, 456 | 111, 112, 113, 115, 116, 117, 119, 120, 121, 122, 124, 125, 126, 127, 126, 126, 457 | 126, 126, 126, 125, 123, 122, 121, 120, 119, 118, 117, 116, 115, 115, 114, 113, 458 | 113, 112, 111, 110, 108, 106, 104, 102, 100, 97, 94, 90, 87, 83, 80, 76, 459 | 73, 69, 66, 62, 60, 57, 55, 52, 50, 48, 45, 43, 41, 38, 36, 32, 460 | 29, 25, 21, 17, 14, 9, 5, 1, -2, -7, -10, -13, -15, -18, -21, -23, 461 | -25, -27, -29, -30, -32, -35, -37, -40, -42, -45, -48, -51, -54, -57, -61, -64, 462 | -67, -69, -71, -73, -75, -77, -77, -78, -79, -79, -80, -81, -82, -82, -83, -84, 463 | -84, -86, -87, -89, -90, -92, -93, -94, -95, -96, -97, -98, -98, -98, -98, -97, 464 | -97, -97, -96, -96, -95, -94, -94, -94, -94, -95, -95, -96, -96, -96, -97, -97, 465 | -98, -98, -98, -98, -97, -96, -96, -95, -94, -93, -92, -91, -90, -89, -88, -88, 466 | -87, -87, -86, -86, -85, -85, -84, -84, -83, -82, -81, -80, -79, -78, -76, -74, 467 | -72, -70, -69, -67, -65, -63, -62, -60, -58, -56, -55, -53, -52, -50, -48, -46, 468 | -44, -41, -39, -36, -34, -31, -28, -25, -22, -19, -16, -13, -11, -8, -5, -3, 469 | 0]; 470 | 471 | var musicboxVolumeTable = [ 472 | 255, 226, 199, 191, 184, 160, 163, 178, 177, 166, 158, 156, 147, 141, 135, 131, 473 | 124, 118, 113, 107, 100, 95, 90, 85, 80, 75, 71, 67, 63, 59, 55, 51, 474 | 48, 45, 43, 40, 39, 36, 34, 30, 28, 27, 25, 24, 23, 22, 22, 20, 475 | 18, 18, 17, 16, 16, 15, 14, 14, 13, 12, 12, 11, 11, 10, 9, 9, 476 | 8,7,6,5,4,3,2,1,0, 477 | 0]; 478 | 479 | function SAMPLE_MUSICBOX(channel, data, t) { 480 | console.log("play musicbox at " + t); 481 | channel.waveForm = musicboxWaveTable; 482 | channel.frequency = frequencies[data % 64]; 483 | channel.volumeForm = musicboxVolumeTable; 484 | channel.volumeTicksPerSample = 4; 485 | } 486 | 487 | var noiseVolumeH = [ 488 | 102, 89, 78, 69, 60, 53, 46, 41, 36, 31, 27, 24, 21, 18, 16, 14, 489 | 12, 11, 9, 8, 7, 6, 5, 5, 4, 3, 3, 3, 2, 2, 2, 1, 490 | 0]; 491 | 492 | var noiseVolumeM = [ 493 | 153, 129, 108, 91, 76, 64, 54, 45, 38, 32, 27, 22, 19, 16, 13, 11, 494 | 9, 8, 6, 5, 4, 4, 3, 2, 2, 2, 1, 1, 1, 1, 0, 0, 495 | 0]; 496 | 497 | var noiseVolumeL = [ 498 | 51, 43, 36, 30, 25, 21, 18, 15, 12, 10, 9, 7, 6, 5, 4, 3, 499 | 3, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 500 | 0]; 501 | 502 | var barVolumeH = [ 503 | 184, 176, 168, 161, 154, 148, 141, 135, 130, 124, 119, 114, 109, 104, 100, 96, 504 | 92, 88, 84, 80, 77, 74, 70, 67, 65, 62, 59, 57, 54, 52, 50, 48, 505 | 46, 44, 42, 40, 38, 37, 35, 33, 32, 31, 29, 28, 27, 26, 25, 24, 506 | 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 14, 14, 13, 13, 12, 12, 507 | // 11, 11, 10, 10, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 6, 508 | // 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 509 | // 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 510 | // 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 511 | 0 512 | ]; 513 | 514 | var barVolumeL = [ 515 | /*184, 176, 168, 161, 154, 148, 141, 135,*/ 130, 124, 119, 114, 109, 104, 100, 96, 516 | 92, 88, 84, 80, 77, 74, 70, 67, 65, 62, 59, 57, 54, 52, 50, 48, 517 | 46, 44, 42, 40, 38, 37, 35, 33, 32, 31, 29, 28, 27, 26, 25, 24, 518 | 23, 22, 21, 20, 19, 18, 17, 16, 16, 15, 14, 14, 13, 13, 12, 12, 519 | // 11, 11, 10, 10, 9, 9, 8, 8, 8, 7, 7, 7, 6, 6, 6, 6, 520 | // 5, 5, 5, 5, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 521 | // 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 522 | // 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 523 | 0 524 | ]; 525 | 526 | function SAMPLE_PERCUSSION(channel, data, t) { 527 | console.log("play percussion at " + t); 528 | 529 | noiseStart = t; 530 | noiseVolume = channel.volume; 531 | 532 | if (data == PERCUSSION_BAR_H) { 533 | noiseVolumeForm = noiseVolumeM; 534 | channel.waveForm = sinTable; 535 | channel.frequency = 55; 536 | channel.volumeForm = barVolumeH; 537 | channel.volumeTicksPerSample = 2; 538 | } else if (data == PERCUSSION_BAR_L) { 539 | noiseVolumeForm = noiseVolumeL; 540 | channel.waveForm = sinTable; 541 | channel.frequency = 55; 542 | channel.volumeForm = barVolumeL; 543 | channel.volumeTicksPerSample = 1; 544 | } else if (data == PERCUSSION_HAT_H) { 545 | noiseVolumeForm = noiseVolumeH; 546 | channel.frequency = 0; 547 | } else { 548 | noiseVolumeForm = noiseVolumeL; 549 | channel.frequency = 0; 550 | } 551 | } 552 | 553 | 554 | 555 | 556 | 557 | /* 558 | * Engine 559 | */ 560 | 561 | var channels = []; 562 | 563 | var dataIndex = 0; 564 | var nextCommandTime = 0; 565 | var beatTime = 60; 566 | 567 | 568 | var noiseStart = 999; 569 | var noiseVolumeForm = [0]; 570 | var noiseVolume = 0; 571 | 572 | var prevT = 999; 573 | 574 | function rand() { 575 | return Math.random() * 2 - 1; 576 | } 577 | 578 | 579 | function playNote(waveSample, t) { 580 | // waveForm, frequency, volumeForm, volumeTicksPerSample, volume 581 | var waveIndex = Math.floor(t * waveSample.frequency * 256) % 256; 582 | var volumeIndex = Math.floor(Math.min(t / 0.004 / waveSample.volumeTicksPerSample, waveSample.volumeForm.length - 1)); 583 | if (simulate8bits) { 584 | return waveSample.waveForm[waveIndex] * Math.round(waveSample.volumeForm[volumeIndex] * waveSample.volume / 256) / 128 / 256; 585 | } else { 586 | return waveSample.waveForm[waveIndex] * waveSample.volumeForm[volumeIndex] * waveSample.volume / 128 / 256 / 256; 587 | } 588 | } 589 | 590 | 591 | function clear() { 592 | dataIndex = 0; 593 | 594 | noiseStart = -999; 595 | noiseVolumeForm = [0]; 596 | noiseVolume = 0; 597 | 598 | for (var i = 0; i < CHANNELS; i++) { 599 | channels[i] = { 600 | waveForm: sinTable, 601 | frequency: 0, 602 | volumeForm: expNegTable, 603 | volumeTicksPerSample: 4, 604 | volume: 0, 605 | startTime: 0 606 | }; 607 | } 608 | } 609 | 610 | function play(t) { 611 | 612 | while (t >= nextCommandTime) { 613 | soundData[dataIndex](t); 614 | dataIndex++; 615 | } 616 | 617 | var res = 0; 618 | 619 | for (var i = 0; i < channels.length; i++) { 620 | res += playNote(channels[i], t - channels[i].startTime); 621 | } 622 | 623 | var noiseVolIndex = Math.floor((t - noiseStart) / 0.004); 624 | if (noiseVolIndex < noiseVolumeForm.length) { 625 | res += rand() * noiseVolumeForm[noiseVolIndex] * noiseVolume / 256 / 256; 626 | } 627 | 628 | if (simulate8bits) { 629 | return round8bits(res); 630 | } else { 631 | return res; 632 | } 633 | } 634 | 635 | 636 | function dsp(t) { 637 | try { 638 | if (t < prevT) { 639 | nextCommandTime = t; 640 | beatTime = 60; 641 | clear(); 642 | } 643 | 644 | prevT = t; 645 | 646 | val = play(t); 647 | // simulate overflow 648 | while (val > 1) {val -= 2;} 649 | while (val < -1) {val += 2;} 650 | return val; 651 | } catch(error) { 652 | console.error(error); 653 | return 0; 654 | } 655 | } 656 | 657 | 658 | 659 | function round8bits(x) { 660 | return Math.floor(x * 127) / 127.0; 661 | } 662 | 663 | 664 | /* 665 | * Commands 666 | */ 667 | 668 | function DATA_TEMPO(bpm) { 669 | return function(t) { 670 | beatTime = 60 / bpm; 671 | console.log("set tempo to " + beatTime); 672 | }; 673 | } 674 | 675 | function DATA_INSTRUMENT(channelId, sample) { 676 | return function(t) { 677 | console.log("set instrument for " + channelId + " at " + t); 678 | channels[channelId].instrument = sample; 679 | }; 680 | } 681 | 682 | function DATA_VOLUME(channelId, volume) { 683 | return function(t) { 684 | console.log("set volume for " + channelId + " to " + volume + " at " + t); 685 | channels[channelId].volume = volume; 686 | }; 687 | } 688 | 689 | function DATA_PLAY(channelId, data, waitBeats) { 690 | return function(t) { 691 | console.log("new note for " + channelId + " at " + t); 692 | channels[channelId].instrument(channels[channelId], data, t); 693 | channels[channelId].startTime = t; 694 | nextCommandTime += waitBeats * beatTime; 695 | console.log("next command at " + nextCommandTime); 696 | }; 697 | } 698 | 699 | 700 | function DATA_WAIT(waitBeats) { 701 | return function(t) { 702 | nextCommandTime += waitBeats * beatTime; 703 | console.log("next command at " + nextCommandTime); 704 | }; 705 | } 706 | 707 | function DATA_END() { 708 | return function(t) { 709 | clear(); 710 | nextCommandTime = t + 0.0001; 711 | dataIndex = -1; 712 | console.log("end at " + t); 713 | }; 714 | } 715 | 716 | --------------------------------------------------------------------------------