This is a part of the Kinetiszer project.
Diff: memory.c
- Revision:
- 0:cb80470434eb
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/memory.c Tue Oct 28 12:19:42 2014 +0000 @@ -0,0 +1,318 @@ +/* +Copyright 2013 Paul Soulsby www.soulsbysynths.com + This file is part of Atmegatron. + + Atmegatron is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Atmegatron is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Atmegatron. If not, see <http://www.gnu.org/licenses/>. +*/ + +//******Read and write patches to flash memory************** + +#include "atmegatron.h" + + +//save patch +void Memory_Save(byte patchnum) +{ + byte i; //, v, + byte lsb, msb; + byte anal, out; + uint32_t addr; + byte bit_position; + //boolean b; + + cli(); //halt interrupts (i.e. audio engine). don't want it interfering with eeprom writing + + addr = (uint32_t)patchnum * MEM_PATCHSIZE; //find start address (normal patch size = 19 bytes) + /*v = 0; + + for (i=0;i<8;i++){ //writes all 16 function values to memory + lsb = Hardware_Get_Value(v); //each function is value 0-15 = 4 bit value. + msb = Hardware_Get_Value(v+1); //so can store 2 function values in each byte (8 bits) + msb = msb << 4; //this is done by bit-shifting every other value left 4 bits + out = msb | lsb; //and ORing with other value + EEPROM.write(addr+i, out); //then write to eeprom + v += 2; + }*/ + + // Write all 16 function values to memory + for (i=0; i<8; i++) + { + lsb = Hardware_Get_Value(2*i); //each function is value 0-15 = 4 bit value. + msb = Hardware_Get_Value(2*i+1); //so can store 2 function values in each byte (8 bits) + EEPROM.write(addr,((msb<<4)&0xf0)|(lsb&0x0f)); //then write to eeprom + addr += 1; + } + + //write all ctrl values to memory + anal = Hardware_Get_Ctrl(0, CTRL_FILT); //first the 6 red bank ctrls + EEPROM.write(addr, anal); + addr += 1; + anal = Hardware_Get_Ctrl(0, CTRL_Q); + EEPROM.write(addr, anal); + addr += 1; + anal = Hardware_Get_Ctrl(0, CTRL_ENV); + EEPROM.write(addr, anal); + addr += 1; + anal = Hardware_Get_Ctrl(0, CTRL_LFO); + EEPROM.write(addr, anal); + addr += 1; + anal = Hardware_Get_Ctrl(0, CTRL_AMP); + EEPROM.write(addr, anal); + addr += 1; + anal = Hardware_Get_Ctrl(0, CTRL_FX); + EEPROM.write(addr, anal); + addr += 1; + anal = Hardware_Get_Ctrl(1, CTRL_ENV); //then the 4 green bank ctrls + EEPROM.write(addr, anal); + addr += 1; + anal = Hardware_Get_Ctrl(1, CTRL_LFO); + EEPROM.write(addr, anal); + addr += 1; + anal = Hardware_Get_Ctrl(1, CTRL_AMP); + EEPROM.write(addr, anal); + addr += 1; + anal = Hardware_Get_Ctrl(1, CTRL_FX); + EEPROM.write(addr, anal); + addr += 1; + + //write function shift modes to memory. + out = 0; //these are boolean, so 1 bit each. so 8 can be store in each byte (i.e. 8 bits). out is used to build up output byte + bit_position = 0x01; + if (Hard_Get_Shift(FUNC_WAVE)==true){ //get each shift mode and set/clear each bit of out. First wavetable bank + //bitSet(out, 0); + out |= bit_position; + } + //else{ + // bitClear(out, 0); + //} + bit_position <<= 1; + if (Hard_Get_Shift(FUNC_FILT)==true){ //filter normalise mode + //bitSet(out, 1); + out |= bit_position; + } + //else{ + // bitClear(out, 1); + //} + bit_position <<= 1; + if (Hard_Get_Shift(FUNC_FENVA)==true){ //filt/pitch env invert mode + //bitSet(out, 2); + out |= bit_position; + } + //else{ + // bitClear(out, 2); + //} + bit_position <<= 1; + if (Hard_Get_Shift(FUNC_LFOTYPE)==true){ //lfo invert mode + //bitSet(out, 3); + out |= bit_position; + } + //else{ + // bitClear(out, 3); + //} +#ifdef __HAS_ARPEGGIATOR__ + bit_position <<= 1; + if (Hard_Get_Shift(FUNC_ARPTYPE)==true){ //arp ping-pong mode + //bitSet(out, 4); + out |= bit_position; + } + //else{ + // bitClear(out, 4); + //} +#endif // __HAS_ARPEGGIATOR__ + bit_position <<= 1; + if (Hard_Get_Shift(FUNC_PORTA)==true){ //proportional portamento + //bitSet(out, 5); + out |= bit_position; + } + //else{ + // bitClear(out, 5); + //} + bit_position <<= 1; + if (Hard_Get_Shift(FUNC_BITCRUSH)==true){ //bitcrush before filter mode + //bitSet(out, 6); + out |= bit_position; + } + //else{ + // bitClear(out, 6); + //} + EEPROM.write(addr, out); //write compiled bits to eeprom + addr += 1; + sei(); //restart interrupts (audio engine) + +} + + +bool Memory_Load_Patch(uint8_t *p_dst, uint32_t src) +{ + int i; + bool patch_not_empty = false; + for (i=0; i<MEM_PATCHSIZE; i++) + { + // We use special EEPROM library that doesn't care about interrupts. + p_dst[i] = EEPROM.read(src+i); + if (p_dst[i]!=0 && p_dst[i]!=0xff) + { + patch_not_empty = true; + } + } + return patch_not_empty; +} + + +//load patch +bool Memory_Load(byte patchnum) +{ + int i; + byte in; + uint8_t eeprom_buffer[MEM_PATCHSIZE]; + + if (Memory_Load_Patch(eeprom_buffer,patchnum*MEM_PATCHSIZE)==false) return false; + + //set function values + for (i=0; i<8; i++) + { + in = eeprom_buffer[i]; + // Two function values in each byte. First one can be obtained by blanking top 4 bits. + Hardware_Let_Value(2*i,in&0x0f); + Hardware_Let_Value(2*i+1,(in>>4)&0x0f); + } + + Hardware_Let_Ctrl(0, CTRL_FILT, eeprom_buffer[i++]); + Hardware_Let_Ctrl(0, CTRL_Q, eeprom_buffer[i++]); + Hardware_Let_Ctrl(0, CTRL_ENV, eeprom_buffer[i++]); + Hardware_Let_Ctrl(0, CTRL_LFO, eeprom_buffer[i++]); + Hardware_Let_Ctrl(0, CTRL_AMP, eeprom_buffer[i++]); + Hardware_Let_Ctrl(0, CTRL_FX, eeprom_buffer[i++]); + Hardware_Let_Ctrl(1, CTRL_ENV, eeprom_buffer[i++]); //the the 4 green bank ctrls + Hardware_Let_Ctrl(1, CTRL_LFO, eeprom_buffer[i++]); + Hardware_Let_Ctrl(1, CTRL_AMP, eeprom_buffer[i++]); + Hardware_Let_Ctrl(1, CTRL_FX, eeprom_buffer[i++]); + + in = eeprom_buffer[i++]; //read entire byte + Hard_Let_Shift(FUNC_WAVE,(in&0x01)!=0); //and set wavetable bank accordingly + Hard_Let_Shift(FUNC_FILT,(in&0x02)!=0); + Hard_Let_Shift(FUNC_FENVA,(in&0x04)!=0); //filter/pitch env invert mode + Hard_Let_Shift(FUNC_LFOTYPE,(in&0x08)!=0); //lfo invert mode +#ifdef __HAS_ARPEGGIATOR__ + Hard_Let_Shift(FUNC_ARPTYPE,(in&0x10)!=0); //arpeggiator pingpong +#endif // __HAS_ARPEGGIATOR__ + Hard_Let_Shift(FUNC_PORTA,(in&0x20)!=0); //proportional portamento + Hard_Let_Shift(FUNC_BITCRUSH,(in&0x40)!=0); //filter before bit crusher + + return true; +} + + +//***** User wave ****** +//save user wave +void Memory_UserWave_Write(byte patchnum) +{ + int i, addr; + cli(); //stop interrupts (audio engine) + addr = ((int)patchnum * WAVE_LEN) + (MEM_PATCHSIZE*16); //calc start address. 288 bytes is the offset from 16 mem patches + for (i=0;i<WAVE_LEN;i++){ + EEPROM.write(addr + i, Wave_Get_UserWave(i)); //write each sample to memory + } + sei(); //restart interrupts (audio engine) +} + + +//load user wave +void Memory_UserWave_Read(byte patchnum) +{ + int i, addr; + cli(); //stop interrupts (audio engine) + addr = ((int)patchnum * WAVE_LEN) + (MEM_PATCHSIZE*16); //calc start address. 288 bytes is the offset from 16 mem patches + for (i=0;i<WAVE_LEN;i++){ + Wave_Let_UserWave(i,EEPROM.read(addr + i)); //read each sample value from memory + } + sei(); //restart interrupts (audio engine) +} + + +//initialise atmegatron with vanilla patch +void Memory_Vanilla(void) +{ + Hardware_Let_Value(FUNC_WAVE, 0); //square wave + Hardware_Let_Value(FUNC_FILT, 1); //lpf + Hardware_Let_Value(FUNC_FENVA, 0); //'donk' shape filter env + Hardware_Let_Value(FUNC_FENVDR, 6); + Hardware_Let_Value(FUNC_FENVS, 0); + Hardware_Let_Value(FUNC_AENVA, 0); //full sustain amp env with short decay if sustain lowered + Hardware_Let_Value(FUNC_AENVD, 6); + Hardware_Let_Value(FUNC_AENVS, 15); + Hardware_Let_Value(FUNC_AENVR, 0); + Hardware_Let_Value(FUNC_LFOTYPE, 0); //sine LFO + Hardware_Let_Value(FUNC_LFOSPEED, 8); //semi-quavers +#ifdef __HAS_ARPEGGIATOR__ + Hardware_Let_Value(FUNC_ARPTYPE, 0); //arp off + Hardware_Let_Value(FUNC_ARPSPEED, 5); //quavers +#endif // __HAS_ARPEGGIATOR__ + Hardware_Let_Value(FUNC_PORTA, 0); //porta off + Hardware_Let_Value(FUNC_BITCRUSH, 0); //bitcrush off + Hardware_Let_Ctrl(0,CTRL_FILT,255); //filter full open + Hardware_Let_Ctrl(0,CTRL_Q,0); //resonance at min (0.5) + Hardware_Let_Ctrl(0,CTRL_ENV,0); //All Envs and LFO amts = 0 + Hardware_Let_Ctrl(1,CTRL_ENV,0); + Hardware_Let_Ctrl(0,CTRL_LFO,0); + Hardware_Let_Ctrl(1,CTRL_LFO,0); + Hardware_Let_Ctrl(0,CTRL_AMP,0); + Hardware_Let_Ctrl(1,CTRL_AMP,0); + Hardware_Let_Ctrl(0,CTRL_FX,0); //no distortion + Hardware_Let_Ctrl(1,CTRL_FX,0); //no phaser + Hard_Let_Shift(FUNC_WAVE, false); //all shift modes off + Hard_Let_Shift(FUNC_FILT, false); + Hard_Let_Shift(FUNC_FENVA, false); + Hard_Let_Shift(FUNC_LFOTYPE, false); +#ifdef __HAS_ARPEGGIATOR__ + Hard_Let_Shift(FUNC_ARPTYPE, false); +#endif // __HAS_ARPEGGIATOR__ + Hard_Let_Shift(FUNC_PORTA, false); + Hard_Let_Shift(FUNC_BITCRUSH, false); +} + + +//read patch from memory and output as sysex +void Memory_SYSEX_write_mem(void) +{ + byte data; + int i; + + Serial.write(SYSEXBEGIN); + Serial.write(125); // 1 manufacturer ID + Serial.write(0); // 2 product ID + Serial.write(SYSEX_MEM); // 3 message type + for (i=0;i<496;i++){ //496 bytes of the mem used + cli(); + data = EEPROM.read(i); + sei(); + Serial.write(data >> 1); //MSB + Serial.write(data & 0x01); //LSB + Serial.flush(); + } + Serial.write(SYSEXEND); + +} + + +void Memory_Channel_Write(byte channel) +{ + EEPROM.write(511, channel); +} + + +byte Memory_Channel_Read(void) +{ + return EEPROM.read(511); +}