1 /* PROJECT:         ReactOS sndrec32
2  * LICENSE:         GPL - See COPYING in the top level directory
3  * FILE:            base/applications/sndrec32/audio_resampler_acm.cpp
4  * PURPOSE:         Sound recording
5  * PROGRAMMERS:     Marco Pagliaricci (irc: rendar)
6  */
7 
8 #include "stdafx.h"
9 #include "audio_resampler_acm.hpp"
10 
11 _AUDIO_NAMESPACE_START_
12 
13 /* Private Functions */
14 
15 void
16 audio_resampler_acm::init_(void)
17 {
18     /* Zeroing structures */
19     ZeroMemory(&acm_header, sizeof(ACMSTREAMHEADER));
20     ZeroMemory(&wformat_src, sizeof(WAVEFORMATEX));
21     ZeroMemory(&wformat_dst, sizeof(WAVEFORMATEX));
22 
23     /* Setting structures sizes */
24     acm_header.cbStruct = sizeof(ACMSTREAMHEADER);
25     wformat_src.cbSize = sizeof(WAVEFORMATEX);
26     wformat_dst.cbSize = sizeof(WAVEFORMATEX);
27 
28     /* Setting WAVEFORMATEX structure parameters
29        according to `audio_format' in/out classes */
30 
31     wformat_src.wFormatTag = WAVE_FORMAT_PCM;
32     wformat_src.nSamplesPerSec = audfmt_in.sample_rate();
33     wformat_src.nChannels = audfmt_in.channels();
34     wformat_src.wBitsPerSample = audfmt_in.bits();
35     wformat_src.nAvgBytesPerSec = audfmt_in.byte_rate();
36     wformat_src.nBlockAlign = audfmt_in.block_align();
37 
38     wformat_dst.wFormatTag = WAVE_FORMAT_PCM;
39     wformat_dst.nSamplesPerSec = audfmt_out.sample_rate();
40     wformat_dst.nChannels = audfmt_out.channels();
41     wformat_dst.wBitsPerSample = audfmt_out.bits();
42     wformat_dst.nAvgBytesPerSec = audfmt_out.byte_rate();
43     wformat_dst.nBlockAlign = audfmt_out.block_align();
44 
45     /* Init acm structures completed successful */
46 }
47 
48 /* Public Functions */
49 
50 void
51 audio_resampler_acm::open(void)
52 {
53     MMRESULT err;
54 
55     /* Opens ACM stream */
56     err = acmStreamOpen(&acm_stream,
57                         0,
58                         &wformat_src,
59                         &wformat_dst,
60                         0, 0, 0,
61                         ACM_STREAMOPENF_NONREALTIME);
62 
63     if (err != MMSYSERR_NOERROR)
64     {
65         /* TODO: throw error */
66         MessageBox(0, _T("acmOpen error: %i"), _T("ERROR"), MB_ICONERROR);
67     }
68 
69     /* Calcs source buffer length */
70     src_buflen = (unsigned int)((float)audfmt_in.byte_rate() * (float)buf_secs);
71 
72     /* Calcs destination source buffer length with help of ACM apis */
73     err = acmStreamSize(acm_stream,
74                         src_buflen,
75                         &dst_buflen,
76                         ACM_STREAMSIZEF_SOURCE);
77 
78     if (err != MMSYSERR_NOERROR)
79     {
80         /* TODO: throw error */
81         MessageBox(0, _T("acmStreamSize error"), _T("ERROR"), MB_ICONERROR);
82     }
83 
84     /* Initialize ACMSTREAMHEADER structure,
85        and alloc memory for source and destination buffers */
86 
87     acm_header.fdwStatus = 0;
88     acm_header.dwUser = 0;
89 
90     acm_header.pbSrc = (LPBYTE) new BYTE[src_buflen];
91     acm_header.cbSrcLength = src_buflen;
92     acm_header.cbSrcLengthUsed = 0;
93     acm_header.dwSrcUser = src_buflen;
94 
95     acm_header.pbDst = (LPBYTE) new BYTE[dst_buflen];
96     acm_header.cbDstLength = dst_buflen;
97     acm_header.cbDstLengthUsed = 0;
98     acm_header.dwDstUser = dst_buflen;
99 
100     /* Give ACMSTREAMHEADER initialized correctly to the driver */
101     err = acmStreamPrepareHeader(acm_stream, &acm_header, 0L);
102     if (err != MMSYSERR_NOERROR)
103     {
104         /* TODO: throw error */
105         MessageBox(0, _T("acmStreamPrepareHeader error"), _T("ERROR"), MB_ICONERROR);
106     }
107 
108     /* ACM stream successfully opened */
109     stream_opened = true;
110 }
111 
112 void
113 audio_resampler_acm::close(void)
114 {
115     MMRESULT err;
116 
117     if (acm_stream)
118     {
119         if (acm_header.fdwStatus & ACMSTREAMHEADER_STATUSF_PREPARED)
120         {
121             acm_header.cbSrcLength = src_buflen;
122             acm_header.cbDstLength = dst_buflen;
123 
124             err = acmStreamUnprepareHeader(acm_stream, &acm_header, 0L);
125             if (err != MMSYSERR_NOERROR)
126             {
127                 /* Free buffer memory */
128                 if (acm_header.pbSrc != 0)
129                 {
130                     delete[] acm_header.pbSrc;
131                     acm_header.pbSrc = 0;
132                 }
133 
134                 if (acm_header.pbDst != 0)
135                 {
136                     delete[] acm_header.pbDst;
137                     acm_header.pbDst = 0;
138                 }
139 
140                 /* Re-init structures */
141                 init_();
142                 /* Updating status */
143                 stream_opened = false;
144                 /* TODO: throw error */
145                 MessageBox(0, _T("acmStreamUnPrepareHeader error"), _T("ERROR"), MB_ICONERROR);
146             }
147         }
148 
149         err = acmStreamClose(acm_stream, 0);
150         acm_stream = 0;
151 
152         if (err != MMSYSERR_NOERROR)
153         {
154             /* Free buffer memory */
155             if (acm_header.pbSrc != 0)
156             {
157                 delete[] acm_header.pbSrc;
158                 acm_header.pbSrc = 0;
159             }
160 
161             if (acm_header.pbDst != 0)
162             {
163                 delete[] acm_header.pbDst;
164                 acm_header.pbDst = 0;
165             }
166 
167             /* Re-init structures */
168             init_();
169             /* Updating status */
170             stream_opened = false;
171             /* TODO: throw error! */
172             MessageBox(0, _T("acmStreamClose error"), _T("ERROR"), MB_ICONERROR);
173         }
174 
175     } /* if acm_stream != 0 */
176 
177     /* Free buffer memory */
178     if (acm_header.pbSrc != 0)
179         delete[] acm_header.pbSrc;
180 
181     if (acm_header.pbDst != 0)
182         delete[] acm_header.pbDst;
183 
184     /* Re-init structures */
185     init_();
186     /* Updating status */
187     stream_opened = false;
188 
189     /* ACM sream successfully closed */
190 }
191 
192 void
193 audio_resampler_acm::audio_receive(unsigned char *data, unsigned int size)
194 {
195     MMRESULT err;
196 
197     /* Checking for acm stream opened */
198     if (stream_opened)
199     {
200         /* Copy audio data from extern to internal source buffer */
201         memcpy(acm_header.pbSrc, data, size);
202 
203         acm_header.cbSrcLength = size;
204         acm_header.cbDstLengthUsed = 0;
205 
206         err = acmStreamConvert(acm_stream, &acm_header, ACM_STREAMCONVERTF_BLOCKALIGN);
207 
208         if (err != MMSYSERR_NOERROR)
209         {
210             /* TODO: throw error */
211             MessageBox(0, _T("acmStreamConvert error"), _T("ERROR"), MB_ICONERROR);
212         }
213 
214         /* Wait for sound conversion */
215         while ((ACMSTREAMHEADER_STATUSF_DONE & acm_header.fdwStatus) == 0);
216 
217         /* Copy resampled audio, to destination buffer */
218         //memcpy(pbOutputData, acm_header.pbDst, acm_header.cbDstLengthUsed);
219     }
220 }
221 
222 _AUDIO_NAMESPACE_END_
223