diff wave_out.c @ 0:c55ea9478c80

Hello Gensokyo!
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 21 May 2013 10:29:21 +0200
parents
children
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/wave_out.c
@@ -0,0 +1,129 @@
+#include <windows.h>
+#include <mmsystem.h>
+#include <stdio.h>
+#include <stdint.h>
+
+/*
+ * some good values for block size and count
+ */
+#define BLOCK_SIZE 8192
+#define BLOCK_COUNT 16
+
+/*
+ * module level variables
+ */
+static WAVEHDR* waveBlocks;
+volatile int waveFreeBlockCount;
+static int waveCurrentBlock;
+
+static int xaddl(int volatile *atomic, int add)
+{
+  int val; /* This works for the 486 and later */
+  __asm__ __volatile__("lock; xaddl %0, %1"
+                       : "=r" (val), "+m" (*atomic)
+                       : "m" (*atomic), "0" (add));
+  return val;
+}
+
+void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1,DWORD dwParam2){
+	/*
+	 * pointer to free block counter
+	*/
+	int* freeBlockCounter = (int*)dwInstance;
+	/*
+	 * ignore calls that occur due to openining and closing the
+	 * device.
+	 */
+	if(uMsg != WOM_DONE)
+	    return;
+	xaddl(freeBlockCounter, 1);
+}
+
+static WAVEHDR* allocateBlocks(unsigned int size, unsigned int count){
+	unsigned char* buffer;
+	int i;
+	WAVEHDR* blocks;
+	DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;
+	/*
+	 * allocate memory for the entire set in one go
+	 */
+	if((buffer = VirtualAlloc(NULL, totalBufferSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)) == NULL) {
+	    return NULL;
+	}
+	/*
+	 * and set up the pointers to each bit
+	 */
+	blocks = (WAVEHDR*)buffer;
+	buffer += sizeof(WAVEHDR) * count;
+	for(i = 0; i < count; i++) {
+	   blocks[i].dwBufferLength = size;
+	   blocks[i].lpData = (char*)buffer;
+	   buffer += size;
+	}
+	return blocks;
+}
+
+void writeAudio(HWAVEOUT hWaveOut, short *data, unsigned int size){
+	WAVEHDR* current;
+	int remain;
+	current = &waveBlocks[waveCurrentBlock];
+	while(size > 0) {
+	/* 
+	 * first make sure the header we're going to use is unprepared
+	 */
+	if(current->dwFlags & WHDR_PREPARED) 
+	    waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
+	if(size < (int)(BLOCK_SIZE - current->dwUser)) {
+	    memcpy(current->lpData + current->dwUser, data, size);
+	    current->dwUser += size;
+	    break;
+	}
+	remain = BLOCK_SIZE - current->dwUser;
+	memcpy(current->lpData + current->dwUser, data, remain);
+	size -= remain;
+	data += remain;
+	current->dwBufferLength = BLOCK_SIZE;
+	waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
+	waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
+	xaddl(&waveFreeBlockCount, -1);
+
+	while(!waveFreeBlockCount)
+	    Sleep(10);
+
+	waveCurrentBlock++;
+	waveCurrentBlock %= BLOCK_COUNT;
+	current = &waveBlocks[waveCurrentBlock];
+	current->dwUser = 0;
+	}
+}
+
+unsigned int wave_out_open(HWAVEOUT *hWaveOut, unsigned int sfreq, unsigned char channels) {
+	WAVEFORMATEX wfx;
+	waveBlocks = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT);
+	waveFreeBlockCount = BLOCK_COUNT;
+	waveCurrentBlock= 0;
+    if(waveBlocks == NULL) {
+        return MMSYSERR_NOMEM;
+    }
+	wfx.nSamplesPerSec = sfreq;
+	wfx.wBitsPerSample = 16;
+	wfx.nChannels = channels; 
+	wfx.cbSize = 0;
+	wfx.wFormatTag = WAVE_FORMAT_PCM;
+	wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) >> 3;
+	wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
+	return waveOutOpen(hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)waveOutProc, (DWORD_PTR)&waveFreeBlockCount, CALLBACK_FUNCTION);
+}
+
+void wave_out_close(HWAVEOUT hWaveOut) {
+	int i;
+	while(waveFreeBlockCount < BLOCK_COUNT)
+	    Sleep(10);
+
+	for(i = 0; i < waveFreeBlockCount; i++) 
+	    if(waveBlocks[i].dwFlags & WHDR_PREPARED)
+	        waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof(WAVEHDR));
+	VirtualFree(waveBlocks, 0, MEM_RELEASE);
+	waveOutClose(hWaveOut);
+}
+