comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:c55ea9478c80
1 #include <windows.h>
2 #include <mmsystem.h>
3 #include <stdio.h>
4 #include <stdint.h>
5
6 /*
7 * some good values for block size and count
8 */
9 #define BLOCK_SIZE 8192
10 #define BLOCK_COUNT 16
11
12 /*
13 * module level variables
14 */
15 static WAVEHDR* waveBlocks;
16 volatile int waveFreeBlockCount;
17 static int waveCurrentBlock;
18
19 static int xaddl(int volatile *atomic, int add)
20 {
21 int val; /* This works for the 486 and later */
22 __asm__ __volatile__("lock; xaddl %0, %1"
23 : "=r" (val), "+m" (*atomic)
24 : "m" (*atomic), "0" (add));
25 return val;
26 }
27
28 void CALLBACK waveOutProc(HWAVEOUT hWaveOut, UINT uMsg, DWORD dwInstance, DWORD dwParam1,DWORD dwParam2){
29 /*
30 * pointer to free block counter
31 */
32 int* freeBlockCounter = (int*)dwInstance;
33 /*
34 * ignore calls that occur due to openining and closing the
35 * device.
36 */
37 if(uMsg != WOM_DONE)
38 return;
39 xaddl(freeBlockCounter, 1);
40 }
41
42 static WAVEHDR* allocateBlocks(unsigned int size, unsigned int count){
43 unsigned char* buffer;
44 int i;
45 WAVEHDR* blocks;
46 DWORD totalBufferSize = (size + sizeof(WAVEHDR)) * count;
47 /*
48 * allocate memory for the entire set in one go
49 */
50 if((buffer = VirtualAlloc(NULL, totalBufferSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE)) == NULL) {
51 return NULL;
52 }
53 /*
54 * and set up the pointers to each bit
55 */
56 blocks = (WAVEHDR*)buffer;
57 buffer += sizeof(WAVEHDR) * count;
58 for(i = 0; i < count; i++) {
59 blocks[i].dwBufferLength = size;
60 blocks[i].lpData = (char*)buffer;
61 buffer += size;
62 }
63 return blocks;
64 }
65
66 void writeAudio(HWAVEOUT hWaveOut, short *data, unsigned int size){
67 WAVEHDR* current;
68 int remain;
69 current = &waveBlocks[waveCurrentBlock];
70 while(size > 0) {
71 /*
72 * first make sure the header we're going to use is unprepared
73 */
74 if(current->dwFlags & WHDR_PREPARED)
75 waveOutUnprepareHeader(hWaveOut, current, sizeof(WAVEHDR));
76 if(size < (int)(BLOCK_SIZE - current->dwUser)) {
77 memcpy(current->lpData + current->dwUser, data, size);
78 current->dwUser += size;
79 break;
80 }
81 remain = BLOCK_SIZE - current->dwUser;
82 memcpy(current->lpData + current->dwUser, data, remain);
83 size -= remain;
84 data += remain;
85 current->dwBufferLength = BLOCK_SIZE;
86 waveOutPrepareHeader(hWaveOut, current, sizeof(WAVEHDR));
87 waveOutWrite(hWaveOut, current, sizeof(WAVEHDR));
88 xaddl(&waveFreeBlockCount, -1);
89
90 while(!waveFreeBlockCount)
91 Sleep(10);
92
93 waveCurrentBlock++;
94 waveCurrentBlock %= BLOCK_COUNT;
95 current = &waveBlocks[waveCurrentBlock];
96 current->dwUser = 0;
97 }
98 }
99
100 unsigned int wave_out_open(HWAVEOUT *hWaveOut, unsigned int sfreq, unsigned char channels) {
101 WAVEFORMATEX wfx;
102 waveBlocks = allocateBlocks(BLOCK_SIZE, BLOCK_COUNT);
103 waveFreeBlockCount = BLOCK_COUNT;
104 waveCurrentBlock= 0;
105 if(waveBlocks == NULL) {
106 return MMSYSERR_NOMEM;
107 }
108 wfx.nSamplesPerSec = sfreq;
109 wfx.wBitsPerSample = 16;
110 wfx.nChannels = channels;
111 wfx.cbSize = 0;
112 wfx.wFormatTag = WAVE_FORMAT_PCM;
113 wfx.nBlockAlign = (wfx.wBitsPerSample * wfx.nChannels) >> 3;
114 wfx.nAvgBytesPerSec = wfx.nBlockAlign * wfx.nSamplesPerSec;
115 return waveOutOpen(hWaveOut, WAVE_MAPPER, &wfx, (DWORD_PTR)waveOutProc, (DWORD_PTR)&waveFreeBlockCount, CALLBACK_FUNCTION);
116 }
117
118 void wave_out_close(HWAVEOUT hWaveOut) {
119 int i;
120 while(waveFreeBlockCount < BLOCK_COUNT)
121 Sleep(10);
122
123 for(i = 0; i < waveFreeBlockCount; i++)
124 if(waveBlocks[i].dwFlags & WHDR_PREPARED)
125 waveOutUnprepareHeader(hWaveOut, &waveBlocks[i], sizeof(WAVEHDR));
126 VirtualFree(waveBlocks, 0, MEM_RELEASE);
127 waveOutClose(hWaveOut);
128 }
129