*** empty log message ***
[chuck-blob.git] / v2 / util_buffers.cpp
blob0ce1a8f3ebb7c115d290fd579febbac0c8ed7dee
1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: util_buffers.cpp
27 // desc: buffer implementation
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // Ananya Misra (amisra@cs.princeton.edu)
32 // date: Spring 2004
33 // Summer 2005 - updated to allow many readers
34 //-----------------------------------------------------------------------------
35 #include <stdlib.h>
36 #include "util_buffers.h"
37 #include "chuck_errmsg.h"
42 //-----------------------------------------------------------------------------
43 // name: CBufferAdvance()
44 // desc: constructor
45 //-----------------------------------------------------------------------------
46 CBufferAdvance::CBufferAdvance()
48 m_data = NULL;
49 m_data_width = m_write_offset = m_max_elem = 0; // = m_read_offset
55 //-----------------------------------------------------------------------------
56 // name: ~CBufferAdvance()
57 // desc: destructor
58 //-----------------------------------------------------------------------------
59 CBufferAdvance::~CBufferAdvance()
61 this->cleanup();
67 //-----------------------------------------------------------------------------
68 // name: initialize()
69 // desc: initialize
70 //-----------------------------------------------------------------------------
71 BOOL__ CBufferAdvance::initialize( UINT__ num_elem, UINT__ width )
73 // cleanup
74 cleanup();
76 // allocate
77 m_data = (BYTE__ *)malloc( num_elem * width );
78 if( !m_data )
79 return false;
81 m_data_width = width;
82 //m_read_offset = 0;
83 m_write_offset = 0;
84 m_max_elem = (SINT__)num_elem;
86 return true;
92 //-----------------------------------------------------------------------------
93 // name: cleanup()
94 // desc: cleanup
95 //-----------------------------------------------------------------------------
96 void CBufferAdvance::cleanup()
98 if( !m_data )
99 return;
101 free( m_data );
103 m_data = NULL;
104 m_data_width = 0;
105 m_write_offset = m_max_elem = 0; // = m_read_offset
111 //-----------------------------------------------------------------------------
112 // name: UINT__ join()
113 // desc: shred can call this to get an index into the vector of read pointers
114 //-----------------------------------------------------------------------------
115 UINT__ CBufferAdvance::join( Chuck_Event * event )
117 // TODO: necessary?
118 m_mutex.acquire();
120 // index of new pointer that will be pushed back
121 UINT__ read_offset_index;
123 // add new pointer pointing (as pointers do) to current write offset
124 // (shreds don't get interrupted, so m_write_offset will always be correct, right?)
125 // (uh, hope so...)
126 if( !m_free.empty() )
128 read_offset_index = m_free.front();
129 m_free.pop();
130 //assert( read_offset_index < m_read_offsets.size() );
131 m_read_offsets[read_offset_index] = ReadOffset( m_write_offset, event );
133 else
135 read_offset_index = m_read_offsets.size();
136 m_read_offsets.push_back( ReadOffset( m_write_offset, event ) );
139 // TODO: necessary?
140 m_mutex.release();
142 // return index
143 return read_offset_index;
147 //-----------------------------------------------------------------------------
148 // name: resign
149 // desc: shred quits buffer; frees its index
150 //-----------------------------------------------------------------------------
151 void CBufferAdvance::resign( UINT__ read_offset_index )
153 // make sure read_offset_index passed in is valid
154 if( read_offset_index < 0 || read_offset_index >= m_read_offsets.size() )
155 return;
157 // TODO: necessary?
158 m_mutex.acquire();
160 // add this index to free queue
161 m_free.push( read_offset_index );
163 // "invalidate" the pointer at that index
164 m_read_offsets[read_offset_index].read_offset = -1;
166 // TODO: necessary?
167 m_mutex.release();
171 //-----------------------------------------------------------------------------
172 // name: put()
173 // desc: put
174 //-----------------------------------------------------------------------------
175 /*void CBufferAdvance::put( void * data, UINT__ num_elem )
177 UINT__ i, j;
178 BYTE__ * d = (BYTE__ *)data;
180 // copy
181 for( i = 0; i < num_elem; i++ )
183 for( j = 0; j < m_data_width; j++ )
185 m_data[m_write_offset*m_data_width+j] = d[i*m_data_width+j];
188 // move the write
189 m_write_offset++;
191 // wrap
192 if( m_write_offset >= m_max_elem )
193 m_write_offset = 0;
198 void CBufferAdvance::put( void * data, UINT__ num_elem )
200 UINT__ i, j;
201 BYTE__ * d = (BYTE__ *)data;
203 // TODO: necessary?
204 m_mutex.acquire();
206 // copy
207 for( i = 0; i < num_elem; i++ )
209 for( j = 0; j < m_data_width; j++ )
211 m_data[m_write_offset*m_data_width+j] = d[i*m_data_width+j];
214 // move the write
215 m_write_offset++;
216 // wrap
217 if( m_write_offset >= m_max_elem )
218 m_write_offset = 0;
220 // possibility of expelling evil shreds
221 for( j = 0; j < m_read_offsets.size(); j++ )
223 if( m_write_offset == m_read_offsets[j].read_offset )
225 // inform shred with index j that it has lost its privileges?
226 // invalidate its read_offset
227 // m_read_offsets[j].read_offset = -1;
230 if( m_read_offsets[j].event )
231 m_read_offsets[j].event->queue_broadcast();
235 // TODO: necessary?
236 m_mutex.release();
242 //-----------------------------------------------------------------------------
243 // name: get()
244 // desc: get
245 //-----------------------------------------------------------------------------
246 /*UINT__ CBufferAdvance::get( void * data, UINT__ num_elem )
248 UINT__ i, j;
249 BYTE__ * d = (BYTE__ *)data;
251 // read catch up with write
252 if( m_read_offset == m_write_offset )
253 return 0;
255 // copy
256 for( i = 0; i < num_elem; i++ )
258 for( j = 0; j < m_data_width; j++ )
260 d[i*m_data_width+j] = m_data[m_read_offset*m_data_width+j];
263 // move read
264 m_read_offset++;
266 // catch up
267 if( m_read_offset == m_write_offset )
269 i++;
270 break;
273 // wrap
274 if( m_read_offset >= m_max_elem )
275 m_read_offset = 0;
278 // return number of elems
279 return 1;
283 BOOL__ CBufferAdvance::empty( UINT__ read_offset_index )
285 // make sure index is valid
286 if( read_offset_index >= m_read_offsets.size() )
287 return TRUE;
288 if( m_read_offsets[read_offset_index].read_offset < 0 )
289 return TRUE;
291 SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset;
293 // see if caught up
294 return m_read_offset == m_write_offset;
298 UINT__ CBufferAdvance::get( void * data, UINT__ num_elem, UINT__ read_offset_index )
300 UINT__ i, j;
301 BYTE__ * d = (BYTE__ *)data;
303 // TODO: necessary?
304 m_mutex.acquire();
306 // make sure index is valid
307 if( read_offset_index >= m_read_offsets.size() )
309 m_mutex.release();
310 return 0;
312 if( m_read_offsets[read_offset_index].read_offset < 0 )
314 m_mutex.release();
315 return 0;
318 SINT__ m_read_offset = m_read_offsets[read_offset_index].read_offset;
320 // read catch up with write
321 if( m_read_offset == m_write_offset )
323 m_mutex.release();
324 return 0;
327 // copy
328 for( i = 0; i < num_elem; i++ )
330 for( j = 0; j < m_data_width; j++ )
332 d[i*m_data_width+j] = m_data[m_read_offset*m_data_width+j];
335 // move read
336 m_read_offset++;
337 // wrap
338 if( m_read_offset >= m_max_elem )
339 m_read_offset = 0;
341 // catch up
342 if( m_read_offset == m_write_offset )
344 i++;
345 break;
349 // update read offset at given index
350 m_read_offsets[read_offset_index].read_offset = m_read_offset;
352 // TODO: necessary?
353 m_mutex.release();
355 // return number of elems
356 return i;
362 //-----------------------------------------------------------------------------
363 // name: CBufferSimple()
364 // desc: constructor
365 //-----------------------------------------------------------------------------
366 CBufferSimple::CBufferSimple()
368 m_data = NULL;
369 m_data_width = m_read_offset = m_write_offset = m_max_elem = 0;
375 //-----------------------------------------------------------------------------
376 // name: ~CBufferSimple()
377 // desc: destructor
378 //-----------------------------------------------------------------------------
379 CBufferSimple::~CBufferSimple()
381 this->cleanup();
387 //-----------------------------------------------------------------------------
388 // name: initialize()
389 // desc: initialize
390 //-----------------------------------------------------------------------------
391 BOOL__ CBufferSimple::initialize( UINT__ num_elem, UINT__ width )
393 // cleanup
394 cleanup();
396 // allocate
397 m_data = (BYTE__ *)malloc( num_elem * width );
398 if( !m_data )
399 return false;
401 m_data_width = width;
402 m_read_offset = 0;
403 m_write_offset = 0;
404 m_max_elem = num_elem;
406 return true;
412 //-----------------------------------------------------------------------------
413 // name: cleanup()
414 // desc: cleanup
415 //-----------------------------------------------------------------------------
416 void CBufferSimple::cleanup()
418 if( !m_data )
419 return;
421 free( m_data );
423 m_data = NULL;
424 m_data_width = m_read_offset = m_write_offset = m_max_elem = 0;
430 //-----------------------------------------------------------------------------
431 // name: put()
432 // desc: put
433 //-----------------------------------------------------------------------------
434 void CBufferSimple::put( void * data, UINT__ num_elem )
436 UINT__ i, j;
437 BYTE__ * d = (BYTE__ *)data;
439 // copy
440 for( i = 0; i < num_elem; i++ )
442 for( j = 0; j < m_data_width; j++ )
444 m_data[m_write_offset*m_data_width+j] = d[i*m_data_width+j];
447 // move the write
448 m_write_offset++;
450 // wrap
451 if( m_write_offset >= m_max_elem )
452 m_write_offset = 0;
459 //-----------------------------------------------------------------------------
460 // name: get()
461 // desc: get
462 //-----------------------------------------------------------------------------
463 UINT__ CBufferSimple::get( void * data, UINT__ num_elem )
465 UINT__ i, j;
466 BYTE__ * d = (BYTE__ *)data;
468 // read catch up with write
469 if( m_read_offset == m_write_offset )
470 return 0;
472 // copy
473 for( i = 0; i < num_elem; i++ )
475 for( j = 0; j < m_data_width; j++ )
477 d[i*m_data_width+j] = m_data[m_read_offset*m_data_width+j];
480 // move read
481 m_read_offset++;
483 // catch up
484 if( m_read_offset == m_write_offset )
486 i++;
487 break;
490 // wrap
491 if( m_read_offset >= m_max_elem )
492 m_read_offset = 0;
495 // return number of elems
496 return 1; // shouldn't it return i?
502 //-----------------------------------------------------------------------------
503 // name: AccumBuffer()
504 // desc: constructor
505 //-----------------------------------------------------------------------------
506 AccumBuffer::AccumBuffer()
508 m_data = NULL;
509 m_write_offset = m_max_elem = 0;
515 //-----------------------------------------------------------------------------
516 // name: ~AccumBuffer()
517 // desc: destructor
518 //-----------------------------------------------------------------------------
519 AccumBuffer::~AccumBuffer()
521 this->cleanup();
527 //-----------------------------------------------------------------------------
528 // name: resize()
529 // desc: resize
530 //-----------------------------------------------------------------------------
531 t_CKINT AccumBuffer::resize( t_CKINT size )
533 // if the same, then done
534 if( size == m_max_elem ) return size;
536 // allocate
537 SAMPLE * next = (SAMPLE *)malloc( size * sizeof(SAMPLE) );
538 // zero it
539 memset( next, 0, size * sizeof(SAMPLE) );
540 if( !next )
542 // log
543 EM_log( CK_LOG_WARNING, "AccumBuffer:resize(%ld) failed to allocated..." );
544 // clean up
545 this->cleanup();
546 // done
547 return FALSE;
550 // if no current
551 if( !m_data )
553 // reset everything
554 m_data = next;
555 m_write_offset = 0;
556 m_max_elem = size;
558 else
560 // retrieve next
561 this->get( next, size );
562 // clean up
563 this->cleanup();
564 // copy
565 m_data = next;
566 // write pointer is at the end
567 m_write_offset = 0;
568 // update max elem
569 m_max_elem = size;
572 return TRUE;
578 //-----------------------------------------------------------------------------
579 // name: cleanup()
580 // desc: cleanup
581 //-----------------------------------------------------------------------------
582 void AccumBuffer::cleanup()
584 if( !m_data )
585 return;
587 free( m_data );
588 m_data = NULL;
589 m_write_offset = m_max_elem = 0;
595 //-----------------------------------------------------------------------------
596 // name: put()
597 // desc: put
598 //-----------------------------------------------------------------------------
599 void AccumBuffer::put( SAMPLE data )
601 // copy
602 m_data[m_write_offset] = data;
603 // move the write
604 m_write_offset++;
605 // wrap
606 if( m_write_offset >= m_max_elem )
607 m_write_offset = 0;
613 //-----------------------------------------------------------------------------
614 // name: get()
615 // desc: get
616 //-----------------------------------------------------------------------------
617 void AccumBuffer::get( SAMPLE * buffer, t_CKINT num_elem )
619 // left to copy
620 t_CKINT left = num_elem;
621 // amount
622 t_CKINT amount = m_max_elem - m_write_offset;
623 // to copy
624 t_CKINT tocopy = ck_min( left, amount );
625 // update left
626 left -= tocopy;
627 // copy after the write pointer
628 memcpy( buffer, m_data + m_write_offset, tocopy * sizeof(SAMPLE) );
630 // more?
631 if( left )
633 // amount
634 amount = m_write_offset;
635 // to copy
636 t_CKINT tocopy2 = ck_min( left, amount );
637 // update left
638 left -= tocopy2;
639 // copy before the write pointer
640 memcpy( buffer + tocopy, m_data, tocopy2 * sizeof(SAMPLE) );
642 // more?
643 if( left )
645 // make sure
646 assert( m_max_elem == (tocopy + tocopy2) );
647 assert( num_elem > m_max_elem );
648 // zero it out
649 memset( buffer + m_max_elem, 0, (num_elem - m_max_elem) * sizeof(SAMPLE) );
657 //-----------------------------------------------------------------------------
658 // name: DeccumBuffer()
659 // desc: constructor
660 //-----------------------------------------------------------------------------
661 DeccumBuffer::DeccumBuffer()
663 m_data = NULL;
664 m_read_offset = m_max_elem = 0;
670 //-----------------------------------------------------------------------------
671 // name: ~DeccumBuffer()
672 // desc: destructor
673 //-----------------------------------------------------------------------------
674 DeccumBuffer::~DeccumBuffer()
676 this->cleanup();
682 //-----------------------------------------------------------------------------
683 // name: resize()
684 // desc: resize
685 //-----------------------------------------------------------------------------
686 t_CKINT DeccumBuffer::resize( t_CKINT size )
688 // if the same, then done
689 if( size == m_max_elem ) return size;
691 // allocate
692 SAMPLE * next = (SAMPLE *)malloc( size * sizeof(SAMPLE) );
693 // zero it
694 memset( next, 0, size * sizeof(SAMPLE) );
695 if( !next )
697 // log
698 EM_log( CK_LOG_WARNING, "DeccumBuffer:resize(%ld) failed to allocated..." );
699 // clean up
700 this->cleanup();
701 // done
702 return FALSE;
705 // if no current
706 if( !m_data )
708 // reset everything
709 m_data = next;
710 m_read_offset = 0;
711 m_max_elem = size;
713 else
715 // retrieve next
716 this->get( next, size );
717 // clean up
718 this->cleanup();
719 // copy
720 m_data = next;
721 // read pointer is at the end
722 m_read_offset = 0;
723 // update max elem
724 m_max_elem = size;
727 return TRUE;
733 //-----------------------------------------------------------------------------
734 // name: cleanup()
735 // desc: cleanup
736 //-----------------------------------------------------------------------------
737 void DeccumBuffer::cleanup()
739 if( !m_data )
740 return;
742 free( m_data );
743 m_data = NULL;
744 m_read_offset = m_max_elem = 0;
750 //-----------------------------------------------------------------------------
751 // name: put()
752 // desc: put
753 //-----------------------------------------------------------------------------
754 void DeccumBuffer::get( SAMPLE * data )
756 // copy
757 *data = m_data[m_read_offset];
758 // zero
759 m_data[m_read_offset] = 0;
760 // move the write
761 m_read_offset++;
762 // wrap
763 if( m_read_offset >= m_max_elem )
764 m_read_offset = 0;
770 //-----------------------------------------------------------------------------
771 // name: get()
772 // desc: get
773 //-----------------------------------------------------------------------------
774 void DeccumBuffer::get( SAMPLE * buffer, t_CKINT num_elem )
776 // left to copy
777 t_CKINT left = num_elem;
778 // amount
779 t_CKINT amount = m_max_elem - m_read_offset;
780 // to copy
781 t_CKINT tocopy = ck_min( left, amount );
782 // update left
783 left -= tocopy;
784 // copy after the write pointer
785 memcpy( buffer, m_data + m_read_offset, tocopy * sizeof(SAMPLE) );
787 // more?
788 if( left )
790 // amount
791 amount = m_read_offset;
792 // to copy
793 t_CKINT tocopy2 = ck_min( left, amount );
794 // update left
795 left -= tocopy2;
796 // copy before the write pointer
797 memcpy( buffer + tocopy, m_data, tocopy2 * sizeof(SAMPLE) );
799 // more?
800 if( left )
802 // make sure
803 assert( m_max_elem == (tocopy + tocopy2) );
804 assert( num_elem > m_max_elem );
805 // zero it out
806 memset( buffer + m_max_elem, 0, (num_elem - m_max_elem) * sizeof(SAMPLE) );
814 //-----------------------------------------------------------------------------
815 // name: put()
816 // desc: put
817 //-----------------------------------------------------------------------------
818 void DeccumBuffer::put( SAMPLE * buffer, t_CKINT num_elem )
820 // left to add
821 t_CKINT left = num_elem;
822 // amount
823 t_CKINT amount = m_max_elem - m_read_offset;
824 // to add
825 t_CKINT tocopy = ck_min( left, amount );
826 // update left
827 left -= tocopy;
828 // copy after the write pointer
829 t_CKINT i;
830 for( i = 0; i < tocopy; i++ )
831 m_data[m_read_offset+i] += buffer[i];
833 // more?
834 if( left )
836 // amount
837 amount = m_read_offset;
838 // to copy
839 t_CKINT tocopy2 = ck_min( left, amount );
840 // update left
841 left -= tocopy2;
842 // copy before the write pointer
843 for( i = 0; i < tocopy2; i++ )
844 m_data[i] += buffer[tocopy+i];
846 // more?
847 if( left )
849 // make sure
850 assert( m_max_elem == (tocopy + tocopy2) );
851 assert( num_elem > m_max_elem );
852 // log
853 EM_log( CK_LOG_WARNING, "(IFFT): discarding data during OLA synthesis..." );