Mercurial > pmdwin
view wave_out.c @ 10:e3849cd10ad3 default tip
Build an intermediary fmgen.a archive.
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Mon, 08 Sep 2014 17:44:53 +0200 |
parents | c55ea9478c80 |
children |
line wrap: on
line source
#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); }