cleanup, README, license for github

This commit is contained in:
Joachim Fenkes 2012-08-12 23:24:58 +02:00
parent 45aaaccaf9
commit 39e3c7b447
10 changed files with 59 additions and 344 deletions

3
LICENSE Normal file
View 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
View 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

View file

@ -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

View file

@ -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
}
}
}

View file

@ -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

View file

@ -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);
}
}

View file

@ -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

View file

@ -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
View 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/

View file

@ -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>