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