/*
 * ul_snd.c
 *
 *  Created on: May 16, 2012
 *      Author: qwer1
 */

#include "ul_snd.h"
#include "ul_timing.h"

//sound buffer
RBUF_IMPL(snd_buf);

//sound thread pointer
struct ptx *_pt_snd;

void setup_snd(void) {
	RBUF_INIT( &snd_buf );
	_pt_snd = ptx_add(pt_snd, NULL, PTX_FLAG_RUN | PTX_FLAG_SYNC_1MS);
}

void snd_buf_add(U16 note) {
	RBUF_WR(&snd_buf, note);
}

void snd_buf_addz(U16 *note) {
	while (*note != 0) {
		RBUF_WR(&snd_buf, *note);
		note++;
	}
}

void snd_buf_addzn(U16 *note, U8 n) {
	while (n--) {
		U16 *note1 = note;
		while (*note1 != 0) {
			RBUF_WR(&snd_buf, *note1);
			note1++;
		}
	}
}

//returns unpacked sample frequency, in Hz
U16 snd_freq(U16 note) {
	return ((note & 0x3FF) << 3);
}

//returns unpacked sample length, in ms
U16 snd_len(U16 note) {
	U16 len = (note >> 10) & 0xF;
	switch (note >> 14) {
		case 0: break;
		case 1: len *= 10; break;
		case 2: len *= 100; break;
		case 3: len *= 1000; break;
	}
	return len;
}

PT_THREAD( pt_snd( struct pt *pt, struct ptx *ptx ) ) {
	PT_BEGIN(pt);
	while (1) {
		//play next note
		if (RBUF_NONEMPTY(&snd_buf)) {
			U16 note = RBUF_RD(&snd_buf); //get next note
			snd_play(snd_freq(note));     //enable frequency generation
			PTX_DELAY_MS(snd_len(note));  //wait for sound duration
			snd_play(0); //disable generation
		}
		PT_YIELD(pt);
	}
	PT_END(pt);
}
