1 #include <windows.h>
2 #include <mmsystem.h>
3 #include "device_mm.h"
4 #include "utility.h"
5 
6 
7 namespace audiere {
8 
9   static const int RATE = 44100;
10 
11 
12   MMAudioDevice*
create(const ParameterList & parameters)13   MMAudioDevice::create(const ParameterList& parameters) {
14     WAVEFORMATEX wfx;
15     memset(&wfx, 0, sizeof(wfx));
16     wfx.wFormatTag      = WAVE_FORMAT_PCM;
17     wfx.nChannels       = 2;
18     wfx.nSamplesPerSec  = RATE;
19     wfx.nAvgBytesPerSec = RATE * 4;
20     wfx.nBlockAlign     = 4;
21     wfx.wBitsPerSample  = 16;
22     wfx.cbSize          = sizeof(WAVEFORMATEX);
23 
24     HWAVEOUT handle;
25     MMRESULT result = waveOutOpen(&handle, WAVE_MAPPER, &wfx, 0, 0, 0);
26     if (result != MMSYSERR_NOERROR) {
27       return 0;
28     }
29 
30     return new MMAudioDevice(handle, RATE);
31   }
32 
33 
MMAudioDevice(HWAVEOUT device,int rate)34   MMAudioDevice::MMAudioDevice(HWAVEOUT device, int rate)
35     : MixerDevice(rate)
36   {
37     ADR_GUARD("MMAudioDevice::MMAudioDevice");
38 
39     m_device = device;
40     m_current_buffer = 0;
41 
42     // fill each buffer with samples and prepare it for output
43     for (int i = 0; i < BUFFER_COUNT; ++i) {
44       WAVEHDR& wh = m_buffers[i];
45       memset(&wh, 0, sizeof(wh));
46       wh.lpData         = (char*)m_samples + i * BUFFER_LENGTH;
47       wh.dwBufferLength = BUFFER_LENGTH;
48 
49       read(BUFFER_LENGTH / 4, wh.lpData);
50 
51       MMRESULT result = waveOutPrepareHeader(m_device, &wh, sizeof(wh));
52       if (result != MMSYSERR_NOERROR) {
53         ADR_LOG("waveOutPrepareHeader failed");
54       }
55 
56       result = waveOutWrite(m_device, &wh, sizeof(wh));
57       if (result != MMSYSERR_NOERROR) {
58         ADR_LOG("waveOutWrite failed");
59       }
60     }
61   }
62 
63 
~MMAudioDevice()64   MMAudioDevice::~MMAudioDevice() {
65     waveOutReset(m_device);
66 
67     for (int i = 0; i < BUFFER_COUNT; ++i) {
68       WAVEHDR& wh = m_buffers[i];
69       if (wh.dwFlags & WHDR_PREPARED || wh.dwFlags & WHDR_DONE) {
70         waveOutUnprepareHeader(m_device, &wh, sizeof(wh));
71       }
72     }
73 
74     waveOutClose(m_device);
75   }
76 
77 
78   void
update()79   MMAudioDevice::update() {
80     ADR_GUARD("MMAudioDevice::update");
81 
82     // if a buffer is done playing, add it to the queue again
83     for (int i = 0; i < BUFFER_COUNT; ++i) {
84       WAVEHDR& wh = m_buffers[i];
85       if (wh.dwFlags & WHDR_DONE) {
86 
87         // unprepare
88         MMRESULT result = waveOutUnprepareHeader(m_device, &wh, sizeof(wh));
89         if (result != MMSYSERR_NOERROR) {
90           ADR_LOG("waveOutUnprepareHeader failed");
91         }
92 
93         // fill with new samples
94         read(BUFFER_LENGTH / 4, wh.lpData);
95         wh.dwFlags = 0;
96 
97         // prepare
98         result = waveOutPrepareHeader(m_device, &wh, sizeof(wh));
99         if (result != MMSYSERR_NOERROR) {
100           ADR_LOG("waveOutPrepareHeader failed");
101         }
102 
103         // write
104         result = waveOutWrite(m_device, &wh, sizeof(wh));
105         if (result != MMSYSERR_NOERROR) {
106           ADR_LOG("waveOutWrite failed");
107         }
108       }
109     }
110     Sleep(10);
111   }
112 
113 
114   const char*
getName()115   MMAudioDevice::getName() {
116     return "winmm";
117   }
118 
119 }
120