#include <v_lib.h>

/*
 * MSVC6: no optimization. PII-233. 32 channels: 604 samples per millisecond.
 * MSVC6: -O2 -Ot -Gs -G6. PII-233. 32 channels: 1877 samples per millisecond.
 */
V_LOCAL void
waveMix8Bit(u8_t *out,u8_t **in_buffers,u32_t num_buffers,u32_t buffer_len)
{
	u32_t pos, offset;
	register u32_t value, buf;
	offset=0x80 * num_buffers;
	for(pos=0;pos<buffer_len;pos++)
	{
		value=in_buffers[0][pos];
		for(buf=1;buf<num_buffers;buf++)
			value+=in_buffers[buf][pos];
		value=0x80+value+offset;
		if(value > 0xFF)
			out[pos]=0xFF;
		else
			out[pos]=(u8_t)value;
	}
}


#define	LEN	1024
#define	NCH	32

int main()
{
	u8_t out_buf[LEN];
	u8_t *in_buf[NCH];
	u32_t i,tim;
	for(i=0;i<NCH;i++)
	{
		in_buf[i]=(u8_t*)memAlloc(LEN);
		memFill(in_buf[i],0x80,LEN);
	}
	tim=timeTickCount();
	for(i=0;i<1000;i++)
		waveMix8Bit(out_buf,in_buf,NCH,LEN);
	tim=timeTickCount()-tim;
	printf("%u repeats: %u channels,%u buffer len; %u milliseconds, %u samples/ms.\n",
		i,NCH,LEN,tim,i*LEN/tim);
	for(i=0;i<NCH;i++)
		memFree(in_buf[i]);
	return 0;
}

#if 0

/*
 * This can be used for mixing audio streams, although
 * DSound is better solution.
 */

#error Complete and debug, then use :)

/*
 * au_stream_data_t used both for 'secondary buffers' (audio data)
 * and for 'primary' buffer which contain mixed streams.
 */
typedef struct au_stream_data_s
{
	u8_t	*buffer;
	u32_t	len;
	u32_t	cursor;
	/*
	for buffer looping
	
	typedef struct
	{
		vhandle_t	in_stream;
		void_p		conversion_buffer; FIXME
	}	au_source;
	void	(V_CALL *OnDataEnd)(void_p self);
	*/
}	au_stream_data_t, *ring_buffer_p;

#define	AU_STREAM_HEAD_BYTES(au)	((au).cursor)
#define	AU_STREAM_TAIL_BYTES(au)	((au).len - (au).cursor)

V_LOCAL au_stream_data_p
au_stream_load(char_p file_name)
{
	u32_t len;
	vhandle_t wf;
	au_stream_data_p au;
	wf = waveOpenRead(file_name);
	if(!wf)
		return NULL;
	if(wavNumChannels(wf) != 1 || wavBitsPerSample() != 8)
	{
#ifdef	CHECKED_BUILD
		conlPuts("au_stream_load(): invalid file format.\n");
#endif	/* CHECKED_BUILD */
		fileClose(wf);
		return NULL;
	}
	len = wavNumSamples(wf);
	au = (au_stream_data_p)memAlloc(sizeof(au_stream_data_t) + len);
	au->buffer = (u8_t*)(au + 1);
	au->len = len;
	au->cursor = 0;
	fileRead(wf,au->buffer,len);
	fileClose(wf);
	return au;
}

V_LOCAL au_stream_data_p
au_stream_alloc(u32_t len)
{
	au_stream_data_p au;
	au = (au_stream_data_p)memAlloc(sizeof(au_stream_data_t) + len);
	au->buffer = (u8_t*)(au + 1);
	au->len = len;
	au->cursor = 0;
	memZero(au->buffer,len);
	return au;
}

au_streamdata_p	au_primary_buffer;
vp_stack_t		au_secondary_buffers;



V_LOCAL void
rbfInit(au_stream_data_t *buf,void *data,u32_t len)
{
}

V_LOCAL void
rbfSetPos(au_stream_data_t *buf,u32_t offset);
{
	buf->cursor = offset % buf->len;
}

V_LOCAL void
rbfAdvancePos(au_stream_data_t *buf,u32_t delta)
{
	buf->cursor = (buf->cursor + delta) % buf->len;
}

void
rgfGet(au_stream_data_t *buf,void *dest,u32_t dest_len)
{
	int startlen; /* length of start block */
	int fullblocks; /* number of full blocks */
	int remainder; /* lenght of end block */
	u8_t *ptr;
	int i;
	startlen=buf->len-buf->cursor;
	if(startlen<=dest_len)
	{
		...
		return;
	}
	remainder=dest_len-start_len;
	fullblocks=remainder / buf->len;
	remainder-=fullblocks * buf->len;
	ptr=(u8_t*)dest;
	memCopy(dest,buf->buffer + buf->cursor,startlen);
	ptr+=startlen;
	for(i=0;i<fullblocks;i++,ptr+=buf->len)
		memCopy(ptr,buf->buffer,buf->len);
	memCopy(ptr,buf->buffer,remainder);
	buf->cursor=remainder;
}

#endif /* 0 */

