cleanup, README, license for github
This commit is contained in:
parent
45aaaccaf9
commit
39e3c7b447
3
LICENSE
Normal file
3
LICENSE
Normal file
|
@ -0,0 +1,3 @@
|
|||
This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
|
||||
To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/
|
||||
or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
|
21
README
Normal file
21
README
Normal file
|
@ -0,0 +1,21 @@
|
|||
The Noiseplug
|
||||
|
||||
An ATtiny9 microcontroller that plays a chiptune.
|
||||
Because 32 bytes of RAM should be enough for everyone.
|
||||
|
||||
There are two versions of the noiseplug program here:
|
||||
win/ A win32/C version that I used to prototype the chiptune and the audio generation
|
||||
avr/ The avr/asm version that makes up the ATtiny9 firmware
|
||||
|
||||
Whenever I decided to change the algorithms to make them easier or smaller to code in asm, I first prototyped the change in the win32/C version to see if it would work. Thus, the C and asm versions are very much in sync with each other, so you can hold them side by side while you try and understand the uncommented gibberish I wrote ;)
|
||||
|
||||
Also, I made a humongous amount of small commits so whenever something broke, I could go back to a known working state. It might be very interesting to check out the progression of changes, especially during the hot assembler coding phase at the hotel room between 11am and 6pm on Saturday.
|
||||
|
||||
You will also see that during that last phase, for example, when I had the bass down pat, I put some more asm-related thought into the arpeggio part of the C prototype before implementing the arpeggio in asm. That way, I could then just write down the asm code line by line and it would work more or less on the first shot. I heartily recommend this approach to everyone going on a similar endeavour.
|
||||
|
||||
If you want to try it on real hardware, just wire up pin 1 of an ATtiny9 (an ATtiny10 should also work) to the signal pin of an audio plug and connect the grounds together. The audio signal is generated by PWMing the supply voltage, so be sure your playback device can take 3V, or 5V if you power the uC from USB.
|
||||
|
||||
Have fun with the source -- I had fun (well, most of the time ;) creating it!
|
||||
|
||||
Signed
|
||||
dojoe
|
|
@ -1,3 +1,7 @@
|
|||
# This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
|
||||
# To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/
|
||||
# or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
|
||||
|
||||
all: flash
|
||||
|
||||
noiseplug.o: noiseplug.S
|
||||
|
|
111
avr/noiseplug.c
111
avr/noiseplug.c
|
@ -1,111 +0,0 @@
|
|||
/*
|
||||
* main.c
|
||||
*
|
||||
* Created on: 30.10.2011
|
||||
* Author: dojoe
|
||||
*/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/pgmspace.h>
|
||||
|
||||
//register uint8_t int_ctr asm("r18");
|
||||
uint8_t int_ctr;
|
||||
|
||||
#if defined(__AVR_ATmega32U4__)
|
||||
ISR(TIMER0_OVF_vect)
|
||||
#elif defined(__AVR_ATtiny9__)
|
||||
ISR(TIM0_OVF_vect)
|
||||
#else
|
||||
#error "warghs"
|
||||
#endif
|
||||
{
|
||||
int_ctr = (int_ctr + 1) & 3;
|
||||
}
|
||||
|
||||
#define NOISEPLUG_BIATCH
|
||||
#include "sound1.c"
|
||||
|
||||
#if 0
|
||||
static inline uint8_t next_sample(const uint32_t t)
|
||||
{
|
||||
// return t*(42&t>>10);
|
||||
// return t*((42&t>>10)%14);
|
||||
// return (t*5&t>>7)|(t*3&t>>10);
|
||||
// return t*9&t>>4|t*5&t>>7|t*3&t/1024;
|
||||
// return (t*9&t>>4|t*5&t>>7|t*3&t/1024)-1;
|
||||
// return t>>4|t&((t>>5)/(t>>7-(t>>15)&-t>>7-(t>>15)));
|
||||
// return (int)(t/1e7*t*t+t)%127|t>>4|t>>5|t%127+(t>>16)|t;
|
||||
uint8_t a = t>>6&1?t>>5:-t>>4;
|
||||
uint8_t b = t>>6^t>>8|t>>12|t&63;
|
||||
|
||||
return random();
|
||||
// return ((t>>6^t>>8|t>>12|t&63)&127)+((t>>6&1?t>>6:-t>>5)&63);
|
||||
// return t << 3;
|
||||
}
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
#if defined(__AVR_ATmega32U4__)
|
||||
#define SAMPLE_L OCR0A
|
||||
clock_prescale_set(clock_div_2);
|
||||
|
||||
DDRB = 1 << PB7 | 1 << PB2; // PB7 == OC0A
|
||||
TCNT0 = 0;
|
||||
OCR0A = 0;
|
||||
TCCR0A = 3 << WGM00 | 2 << COM0A0; // Fast PWM mode, positive polarity
|
||||
TCCR0B = 1 << CS00; // Select main clock, no prescaling
|
||||
TIMSK0 = 1 << TOIE0; // enable overflow interrupt
|
||||
TIFR0 = 1 << TOV0; // make sure it happens
|
||||
|
||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
sei();
|
||||
#elif defined(__AVR_ATtiny9__)
|
||||
#define SAMPLE_L OCR0AL
|
||||
|
||||
CCP = 0xD8;
|
||||
CLKMSR = 0;
|
||||
CCP = 0xD8;
|
||||
CLKPSR = 0;
|
||||
PUEB = 0;
|
||||
DDRB = (1 << PB0) | (1 << PB2);
|
||||
TCNT0 = 0;
|
||||
OCR0A = 0;
|
||||
TCCR0A = (1 << WGM00) | (2 << COM0A0);
|
||||
TCCR0B = (1 << WGM02) | (1 << CS00);
|
||||
TCCR0C = 0;
|
||||
TIMSK0 = 1 << TOIE0;
|
||||
|
||||
set_sleep_mode(SLEEP_MODE_IDLE);
|
||||
sei();
|
||||
TIFR0 = 1 << TOV0;
|
||||
#else
|
||||
#error "not supported"
|
||||
#endif
|
||||
|
||||
uint8_t sample = 0;
|
||||
|
||||
#ifdef __AVR_ATmega32U4__
|
||||
DDRE = 1 << PE6;
|
||||
uint16_t t = 0;
|
||||
#endif
|
||||
|
||||
while (1) {
|
||||
sleep_mode();
|
||||
if (int_ctr == 0) {
|
||||
//PORTB = 1 << PB2;
|
||||
SAMPLE_L = sample;
|
||||
sample = next_sample();
|
||||
//PORTB = 0;
|
||||
|
||||
#ifdef __AVR_ATmega32U4__
|
||||
PORTE = (t & 4096) ? 1 << PE6 : 0;
|
||||
t++;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,3 +1,7 @@
|
|||
; This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
|
||||
; To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/
|
||||
; or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
|
||||
|
||||
.global __vectors
|
||||
|
||||
SREG = 0x3F
|
||||
|
|
18
avr/sound.c
18
avr/sound.c
|
@ -1,18 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
int main(r)
|
||||
{
|
||||
|
||||
unsigned short rnd = 13373;
|
||||
while(1)
|
||||
{
|
||||
unsigned char f1 = (rnd&(3<<13))>>13;
|
||||
unsigned char f2 = (rnd&(3<<10))>>10;
|
||||
rnd <<=1;
|
||||
rnd |= f1^f2;
|
||||
putchar(rnd);
|
||||
|
||||
}
|
||||
}
|
180
avr/sound1.c
180
avr/sound1.c
|
@ -1,180 +0,0 @@
|
|||
#include <inttypes.h>
|
||||
|
||||
#ifndef PROGMEM
|
||||
#define PROGMEM /* nix */
|
||||
#endif
|
||||
|
||||
#define arpeggio_DELAY 128
|
||||
|
||||
#define BIT(x,n) (((x)&(1<<(n)))>>(n))
|
||||
#define SO(x) (sizeof((x))/sizeof(*(x)))
|
||||
|
||||
#define A1 0
|
||||
#define As1 1
|
||||
#define B1 2
|
||||
#define C1 3
|
||||
#define Cs1 4
|
||||
#define D1 5
|
||||
#define Ds1 6
|
||||
#define E1 7
|
||||
#define F1 8
|
||||
#define Fs1 9
|
||||
#define G1 10
|
||||
#define Gs1 11
|
||||
#define A2 12
|
||||
#define Aa2 13
|
||||
#define B2 14
|
||||
#define C2 15
|
||||
#define Cs2 16
|
||||
#define D2 17
|
||||
#define Ds2 18
|
||||
#define E2 19
|
||||
#define F2 20
|
||||
#define Fs2 21
|
||||
#define G2 22
|
||||
#define Gs2 23
|
||||
#define HOLD 24
|
||||
|
||||
static const PROGMEM uint8_t sin[] = {0, 49, 97, 141, 180, 212, 235, 250, 254, 250, 235, 212, 180, 141, 97, 49 };
|
||||
static const PROGMEM uint8_t octave_delay[] = { 36, 34, 32, 31, 29, 27, 26, 24, 23, 22, 20, 19, 18, 17, 16, 15, 14, 14, 13, 12, 11, 11, 10, 10 };
|
||||
static const PROGMEM struct { uint8_t a; uint8_t b; } synth[] = { { 7, 6}, {7, 5}, {7,5}, {6,5} };
|
||||
static const PROGMEM uint8_t arpeggiobase[] = { 3, 4, 4, 5 };
|
||||
static const PROGMEM uint8_t bassdrum[] = { 1, 1, 1, 1 };
|
||||
static const PROGMEM uint8_t snare[] = { 1, 1, 1, 1 };
|
||||
static const PROGMEM uint8_t melody[] =
|
||||
{
|
||||
D2, 0, D2, 0, 0, 0, 0, 0, D2, 0,
|
||||
A1, 0, B1, 0, D2, 0, D2, 0, D2, 0
|
||||
};
|
||||
|
||||
static inline uint8_t next_note()
|
||||
{
|
||||
|
||||
static uint8_t idx=0;
|
||||
|
||||
const uint8_t v = melody[idx++];
|
||||
|
||||
if(idx == SO(melody))
|
||||
idx = 0;
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline uint8_t next_rnd()
|
||||
{
|
||||
static unsigned short rnd = 13373;
|
||||
const uint8_t f1 = (rnd&(3<<13))>>13;
|
||||
const uint8_t f2 = (rnd&(3<<10))>>10;
|
||||
rnd <<=1;
|
||||
rnd |= f1^f2;
|
||||
|
||||
return sin[((uint8_t)rnd)%SO(sin)];
|
||||
}
|
||||
|
||||
static inline uint8_t next_sin(const uint8_t step)
|
||||
{
|
||||
static uint8_t sinoff=SO(sin)-1;
|
||||
sinoff += step;
|
||||
sinoff &= SO(sin) - 1;
|
||||
return sin[sinoff];
|
||||
}
|
||||
|
||||
|
||||
static inline uint8_t next_sample()
|
||||
{
|
||||
static uint16_t t=0;
|
||||
|
||||
static uint8_t t8=0;
|
||||
static uint8_t barevent=0;
|
||||
static uint8_t bars=0;
|
||||
|
||||
static uint8_t pc = 0;
|
||||
static uint8_t arpeggiocnt = 1;
|
||||
|
||||
static uint8_t next_sin_time = 0;
|
||||
static uint8_t current_tone = 0;
|
||||
static uint8_t current_tone_base = 12;
|
||||
|
||||
static unsigned short snaredelay;
|
||||
static unsigned short bassdelay;
|
||||
|
||||
static uint8_t synth1;
|
||||
static uint8_t synth2;
|
||||
|
||||
if(t%1024 == 0)
|
||||
{
|
||||
// implicit rollover of t roughly every 2 seconds
|
||||
if(t==0) t8 = 0;
|
||||
else ++t8;
|
||||
|
||||
// determine which note we're playing
|
||||
barevent |= 8;
|
||||
if(t8%2 == 0) barevent |= 4;
|
||||
if(t8%4 == 0) barevent |= 2;
|
||||
if(t8%8 == 0) barevent |= 1;
|
||||
}
|
||||
else barevent = 0;
|
||||
|
||||
if(barevent & 8)
|
||||
{
|
||||
current_tone = current_tone_base = next_note();
|
||||
}
|
||||
|
||||
// increment bar counter
|
||||
if(barevent & 1) ++bars;
|
||||
|
||||
// increment pattern counter
|
||||
if(bars % 8 == 0)
|
||||
{
|
||||
++pc;
|
||||
pc %= SO(arpeggiobase);
|
||||
}
|
||||
|
||||
// increment arpeggio
|
||||
if(t % arpeggio_DELAY == 0)
|
||||
{
|
||||
// arpeggio
|
||||
++arpeggiocnt;
|
||||
arpeggiocnt &= 3;
|
||||
current_tone = current_tone_base + 4 * arpeggiocnt;
|
||||
}
|
||||
|
||||
// render synth
|
||||
|
||||
synth1 = ((t&(t>>(synth[pc].a))) | (t&(t>>(synth[pc].b))) << 1);
|
||||
|
||||
if(t == next_sin_time)
|
||||
{
|
||||
next_sin_time += octave_delay[current_tone];
|
||||
synth2 = next_sin(5);
|
||||
}
|
||||
|
||||
// mix two synth lines
|
||||
unsigned int mix = (synth1>>1) | (synth2>>1);
|
||||
|
||||
// load or decrement snare delay
|
||||
if(barevent & 8 && snare[pc]) snaredelay = 800;
|
||||
else if(snaredelay > 0) --snaredelay;
|
||||
|
||||
// add snare drum
|
||||
if(snaredelay>0) mix = (next_rnd() & 7) << 3;
|
||||
|
||||
|
||||
// load or decrement bass delay
|
||||
if(barevent & 4 && bassdrum[pc]) bassdelay = 800;
|
||||
else if(bassdelay > 0) --bassdelay;
|
||||
|
||||
// add bass drum
|
||||
if(bassdelay>0) mix = next_sin(1);
|
||||
|
||||
++t;
|
||||
// here comes the noize!
|
||||
return mix;
|
||||
}
|
||||
|
||||
#ifndef NOISEPLUG_BIATCH
|
||||
int main()
|
||||
{
|
||||
while(1) putchar(next_sample());
|
||||
}
|
||||
#endif
|
35
avr/sound3.c
35
avr/sound3.c
|
@ -1,35 +0,0 @@
|
|||
|
||||
#define SO(x) (sizeof((x))/sizeof(*(x)))
|
||||
|
||||
static unsigned char sin[] = {0, 49, 97, 141, 180, 212, 235, 250, 254, 250, 235, 212, 180, 141, 97, 49 };
|
||||
|
||||
unsigned char getRand()
|
||||
{
|
||||
static unsigned short rnd = 13373;
|
||||
unsigned char f1 = (rnd&(3<<13))>>13;
|
||||
unsigned char f2 = (rnd&(3<<10))>>10;
|
||||
rnd <<=1;
|
||||
rnd |= f1^f2;
|
||||
return (unsigned char)(rnd&0x0f);
|
||||
}
|
||||
|
||||
static inline unsigned char rnd_adv()
|
||||
{
|
||||
return sin[getRand()%SO(sin)];
|
||||
}
|
||||
|
||||
static inline unsigned char sin_adv()
|
||||
{
|
||||
static unsigned char sinoff=SO(sin)-1;
|
||||
++sinoff;
|
||||
sinoff %= SO(sin);
|
||||
return sin[sinoff];
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
while(1)
|
||||
{
|
||||
putchar(sin_adv());
|
||||
}
|
||||
}
|
21
noiseplug.nfo
Normal file
21
noiseplug.nfo
Normal file
|
@ -0,0 +1,21 @@
|
|||
dojoe / shack
|
||||
|
||||
presents
|
||||
|
||||
THE NOISEPLUG!
|
||||
|
||||
Two minutes of audio from 1k of
|
||||
Flash and 32 Bytes of RAM.
|
||||
|
||||
Brofists and Ponies to
|
||||
lft for the obvious inspiration =)
|
||||
smrrd for the camera work
|
||||
psykon for last-minute video editing <3
|
||||
Evoke organizing for a great party!
|
||||
YOU for showing interest in this.
|
||||
|
||||
To play along at home: Take an ATtiny9,
|
||||
connect pin 1 to an audio input,
|
||||
flash noiseplug.hex. Have fun!
|
||||
|
||||
http://shackspace.de/
|
|
@ -1,3 +1,9 @@
|
|||
/*
|
||||
This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License.
|
||||
To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/
|
||||
or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
|
Loading…
Reference in a new issue