1 /* PROJECT:         ReactOS sndrec32
2  * LICENSE:         GPL - See COPYING in the top level directory
3  * FILE:            base/applications/sndrec32/audio_membuffer.cpp
4  * PURPOSE:         Sound recording
5  * PROGRAMMERS:     Marco Pagliaricci (irc: rendar)
6  */
7 
8 #include "stdafx.h"
9 #include "audio_membuffer.hpp"
10 
11 _AUDIO_NAMESPACE_START_
12 
13 /* Protected Functions */
14 
15 void
16 audio_membuffer::alloc_mem_(unsigned int bytes)
17 {
18     /* Some checking */
19     if (bytes == 0)
20         return;
21 
22     /* Checks previously alloc'd memory and frees it */
23     if (audio_data)
24         delete[] audio_data;
25 
26     /* Allocs new memory and zeros it */
27     audio_data = new BYTE[bytes];
28     memset(audio_data, 0, bytes * sizeof(BYTE));
29 
30     /* Sets the correct buffer size */
31     buf_size = bytes;
32     init_size = bytes;
33 }
34 
35 void
36 audio_membuffer::free_mem_(void)
37 {
38     if (audio_data)
39         delete[] audio_data;
40 
41     buf_size = 0;
42     audio_data = 0;
43 }
44 
45 void
46 audio_membuffer::resize_mem_(unsigned int new_size)
47 {
48     if (new_size == 0)
49         return;
50 
51     /* The new_size, cannot be <= of the `bytes_received' member value of the
52        parent class `audio_receiver'. We cannot touch received audio data,
53        so we have to alloc at least bytes_received+1 bytes. But we can truncate
54        unused memory, so `new_size' can be < of `buf_size' */
55     if (new_size <= bytes_received)
56         return;
57 
58     BYTE * new_mem;
59 
60     /* Allocs new memory and zeros it */
61     new_mem = new BYTE[new_size];
62     memset(new_mem, 0, new_size * sizeof(BYTE));
63 
64     if (audio_data)
65     {
66         /* Copies received audio data, and discard unused memory */
67         memcpy(new_mem, audio_data, bytes_received);
68         /* Frees old memory */
69         delete[] audio_data;
70         /* Commit new memory */
71         audio_data = new_mem;
72         buf_size = new_size;
73     } else {
74         audio_data = new_mem;
75         buf_size = new_size;
76     }
77 
78     if (buffer_resized)
79         buffer_resized(new_size);
80 }
81 
82 void
83 audio_membuffer::truncate_(void)
84 {
85     /* If `buf_size' is already = to the `bytes_received' of audio data,
86        then this operation is useless; simply return */
87     if (bytes_received == buf_size)
88         return;
89 
90     if (audio_data)
91     {
92         /* Allocs a new buffer */
93         BYTE * newbuf = new BYTE[bytes_received];
94         /* Copies audio data */
95         memcpy(newbuf, audio_data, bytes_received);
96         /* Frees old memory */
97         delete[] audio_data;
98         /* Commit the new buffer */
99         audio_data = newbuf;
100         buf_size = bytes_received;
101 
102         /* Buffer truncation successful. Now the buffer size is exactly big
103            as much audio data was received */
104     }
105 }
106 
107 /* Public Functions */
108 
109 void
110 audio_membuffer::clear(void)
111 {
112     free_mem_();
113     bytes_received = 0;
114 }
115 
116 void
117 audio_membuffer::reset(void)
118 {
119     /* Frees memory and reset to initial state */
120     clear();
121     /* Alloc memory of size specified at the constructor */
122     alloc_mem_(init_size);
123 }
124 
125 void
126 audio_membuffer::alloc_bytes(unsigned int bytes)
127 {
128     alloc_mem_(bytes);
129 }
130 
131 void
132 audio_membuffer::alloc_seconds(unsigned int secs)
133 {
134     alloc_mem_(aud_info.byte_rate() * secs);
135 }
136 
137 void
138 audio_membuffer::alloc_seconds(float secs)
139 {
140     alloc_mem_((unsigned int)((float)aud_info.byte_rate() * secs));
141 }
142 
143 void
144 audio_membuffer::resize_bytes(unsigned int bytes)
145 {
146     resize_mem_(bytes);
147 }
148 
149 void
150 audio_membuffer::resize_seconds(unsigned int secs)
151 {
152     resize_mem_(aud_info.byte_rate() * secs);
153 }
154 
155 void
156 audio_membuffer::resize_seconds(float secs)
157 {
158     resize_mem_((unsigned int)((float)aud_info.byte_rate() * secs));
159 }
160 
161 /* Inherited Functions */
162 
163 void
164 audio_membuffer::audio_receive(unsigned char *data, unsigned int size)
165 {
166     /* If there isn't a buffer, allocs memory for it of size*2, and copies audio data arrival */
167     if ((audio_data == 0) || (buf_size == 0))
168     {
169         alloc_mem_(size * 2);
170         memcpy(audio_data, data, size);
171         return;
172     }
173 
174     /* If buffer's free memory is < of `size', we have to realloc buffer memory
175        of buf_size*2, while free memory is enough to contain `size' bytes.
176        In this case free memory is represented by `buf_size - bytes_recorded' */
177     unsigned int tot_mem = buf_size, free_mem = buf_size - bytes_received;
178     if (free_mem < size)
179     {
180         /* Calcs new buffer size */
181         /* TODO: flags for other behaviour? */
182         while (free_mem < size)
183         {
184             tot_mem *= 2;
185             free_mem = tot_mem - bytes_received;
186         }
187 
188         /* Resize buffer memory */
189         resize_mem_(tot_mem);
190     }
191 
192     /* Now we have enough free space in the buffer, so let's copy audio data arrivals */
193     memcpy(audio_data + bytes_received, data, size);
194 
195     if (audio_arrival)
196         audio_arrival(aud_info.samples_in_bytes(size));
197 }
198 
199 unsigned int
200 audio_membuffer::read(BYTE *out_buf, unsigned int bytes)
201 {
202     /* Some checking */
203     if (!audio_data)
204         return 0;
205 
206     if (bytes_played_ >= bytes_received)
207         return 0;
208 
209     unsigned int to_play = bytes_received - bytes_played_;
210     unsigned int to_copy = bytes > to_play ? to_play : bytes;
211 
212     /* Copies the audio data out */
213     if ((out_buf) && (to_copy) && (audio_data))
214         memcpy(out_buf, audio_data + bytes_played_, to_copy);
215 
216     /* Increments the number of total bytes played (audio data gone out from
217        the `audio_producer' object) */
218     bytes_played_ += to_copy;
219 
220     if (audio_arrival)
221         audio_arrival(aud_info.samples_in_bytes(to_copy));
222 
223     /* Returns the exact size of audio data produced */
224     return to_copy;
225 }
226 
227 bool
228 audio_membuffer::finished(void)
229 {
230     if (bytes_played_ < bytes_received)
231         return false;
232     else
233         return true;
234 }
235 
236 _AUDIO_NAMESPACE_END_
237