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
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)
33 // Summer 2005 - updated to allow many readers
34 //-----------------------------------------------------------------------------
36 #include "util_buffers.h"
37 #include "chuck_errmsg.h"
42 //-----------------------------------------------------------------------------
43 // name: CBufferAdvance()
45 //-----------------------------------------------------------------------------
46 CBufferAdvance::CBufferAdvance()
49 m_data_width
= m_write_offset
= m_max_elem
= 0; // = m_read_offset
55 //-----------------------------------------------------------------------------
56 // name: ~CBufferAdvance()
58 //-----------------------------------------------------------------------------
59 CBufferAdvance::~CBufferAdvance()
67 //-----------------------------------------------------------------------------
70 //-----------------------------------------------------------------------------
71 BOOL__
CBufferAdvance::initialize( UINT__ num_elem
, UINT__ width
)
77 m_data
= (BYTE__
*)malloc( num_elem
* width
);
84 m_max_elem
= (SINT__
)num_elem
;
92 //-----------------------------------------------------------------------------
95 //-----------------------------------------------------------------------------
96 void CBufferAdvance::cleanup()
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
)
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?)
126 if( !m_free
.empty() )
128 read_offset_index
= m_free
.front();
130 //assert( read_offset_index < m_read_offsets.size() );
131 m_read_offsets
[read_offset_index
] = ReadOffset( m_write_offset
, event
);
135 read_offset_index
= m_read_offsets
.size();
136 m_read_offsets
.push_back( ReadOffset( m_write_offset
, event
) );
143 return read_offset_index
;
147 //-----------------------------------------------------------------------------
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() )
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;
171 //-----------------------------------------------------------------------------
174 //-----------------------------------------------------------------------------
175 /*void CBufferAdvance::put( void * data, UINT__ num_elem )
178 BYTE__ * d = (BYTE__ *)data;
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];
192 if( m_write_offset >= m_max_elem )
198 void CBufferAdvance::put( void * data
, UINT__ num_elem
)
201 BYTE__
* d
= (BYTE__
*)data
;
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
];
217 if( m_write_offset
>= m_max_elem
)
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();
242 //-----------------------------------------------------------------------------
245 //-----------------------------------------------------------------------------
246 /*UINT__ CBufferAdvance::get( void * data, UINT__ num_elem )
249 BYTE__ * d = (BYTE__ *)data;
251 // read catch up with write
252 if( m_read_offset == m_write_offset )
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];
267 if( m_read_offset == m_write_offset )
274 if( m_read_offset >= m_max_elem )
278 // return number of elems
283 BOOL__
CBufferAdvance::empty( UINT__ read_offset_index
)
285 // make sure index is valid
286 if( read_offset_index
>= m_read_offsets
.size() )
288 if( m_read_offsets
[read_offset_index
].read_offset
< 0 )
291 SINT__ m_read_offset
= m_read_offsets
[read_offset_index
].read_offset
;
294 return m_read_offset
== m_write_offset
;
298 UINT__
CBufferAdvance::get( void * data
, UINT__ num_elem
, UINT__ read_offset_index
)
301 BYTE__
* d
= (BYTE__
*)data
;
306 // make sure index is valid
307 if( read_offset_index
>= m_read_offsets
.size() )
312 if( m_read_offsets
[read_offset_index
].read_offset
< 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
)
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
];
338 if( m_read_offset
>= m_max_elem
)
342 if( m_read_offset
== m_write_offset
)
349 // update read offset at given index
350 m_read_offsets
[read_offset_index
].read_offset
= m_read_offset
;
355 // return number of elems
362 //-----------------------------------------------------------------------------
363 // name: CBufferSimple()
365 //-----------------------------------------------------------------------------
366 CBufferSimple::CBufferSimple()
369 m_data_width
= m_read_offset
= m_write_offset
= m_max_elem
= 0;
375 //-----------------------------------------------------------------------------
376 // name: ~CBufferSimple()
378 //-----------------------------------------------------------------------------
379 CBufferSimple::~CBufferSimple()
387 //-----------------------------------------------------------------------------
388 // name: initialize()
390 //-----------------------------------------------------------------------------
391 BOOL__
CBufferSimple::initialize( UINT__ num_elem
, UINT__ width
)
397 m_data
= (BYTE__
*)malloc( num_elem
* width
);
401 m_data_width
= width
;
404 m_max_elem
= num_elem
;
412 //-----------------------------------------------------------------------------
415 //-----------------------------------------------------------------------------
416 void CBufferSimple::cleanup()
424 m_data_width
= m_read_offset
= m_write_offset
= m_max_elem
= 0;
430 //-----------------------------------------------------------------------------
433 //-----------------------------------------------------------------------------
434 void CBufferSimple::put( void * data
, UINT__ num_elem
)
437 BYTE__
* d
= (BYTE__
*)data
;
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
];
451 if( m_write_offset
>= m_max_elem
)
459 //-----------------------------------------------------------------------------
462 //-----------------------------------------------------------------------------
463 UINT__
CBufferSimple::get( void * data
, UINT__ num_elem
)
466 BYTE__
* d
= (BYTE__
*)data
;
468 // read catch up with write
469 if( m_read_offset
== m_write_offset
)
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
];
484 if( m_read_offset
== m_write_offset
)
491 if( m_read_offset
>= m_max_elem
)
495 // return number of elems
496 return 1; // shouldn't it return i?
502 //-----------------------------------------------------------------------------
503 // name: AccumBuffer()
505 //-----------------------------------------------------------------------------
506 AccumBuffer::AccumBuffer()
509 m_write_offset
= m_max_elem
= 0;
515 //-----------------------------------------------------------------------------
516 // name: ~AccumBuffer()
518 //-----------------------------------------------------------------------------
519 AccumBuffer::~AccumBuffer()
527 //-----------------------------------------------------------------------------
530 //-----------------------------------------------------------------------------
531 t_CKINT
AccumBuffer::resize( t_CKINT size
)
533 // if the same, then done
534 if( size
== m_max_elem
) return size
;
537 SAMPLE
* next
= (SAMPLE
*)malloc( size
* sizeof(SAMPLE
) );
539 memset( next
, 0, size
* sizeof(SAMPLE
) );
543 EM_log( CK_LOG_WARNING
, "AccumBuffer:resize(%ld) failed to allocated..." );
561 this->get( next
, size
);
566 // write pointer is at the end
578 //-----------------------------------------------------------------------------
581 //-----------------------------------------------------------------------------
582 void AccumBuffer::cleanup()
589 m_write_offset
= m_max_elem
= 0;
595 //-----------------------------------------------------------------------------
598 //-----------------------------------------------------------------------------
599 void AccumBuffer::put( SAMPLE data
)
602 m_data
[m_write_offset
] = data
;
606 if( m_write_offset
>= m_max_elem
)
613 //-----------------------------------------------------------------------------
616 //-----------------------------------------------------------------------------
617 void AccumBuffer::get( SAMPLE
* buffer
, t_CKINT num_elem
)
620 t_CKINT left
= num_elem
;
622 t_CKINT amount
= m_max_elem
- m_write_offset
;
624 t_CKINT tocopy
= ck_min( left
, amount
);
627 // copy after the write pointer
628 memcpy( buffer
, m_data
+ m_write_offset
, tocopy
* sizeof(SAMPLE
) );
634 amount
= m_write_offset
;
636 t_CKINT tocopy2
= ck_min( left
, amount
);
639 // copy before the write pointer
640 memcpy( buffer
+ tocopy
, m_data
, tocopy2
* sizeof(SAMPLE
) );
646 assert( m_max_elem
== (tocopy
+ tocopy2
) );
647 assert( num_elem
> m_max_elem
);
649 memset( buffer
+ m_max_elem
, 0, (num_elem
- m_max_elem
) * sizeof(SAMPLE
) );
657 //-----------------------------------------------------------------------------
658 // name: DeccumBuffer()
660 //-----------------------------------------------------------------------------
661 DeccumBuffer::DeccumBuffer()
664 m_read_offset
= m_max_elem
= 0;
670 //-----------------------------------------------------------------------------
671 // name: ~DeccumBuffer()
673 //-----------------------------------------------------------------------------
674 DeccumBuffer::~DeccumBuffer()
682 //-----------------------------------------------------------------------------
685 //-----------------------------------------------------------------------------
686 t_CKINT
DeccumBuffer::resize( t_CKINT size
)
688 // if the same, then done
689 if( size
== m_max_elem
) return size
;
692 SAMPLE
* next
= (SAMPLE
*)malloc( size
* sizeof(SAMPLE
) );
694 memset( next
, 0, size
* sizeof(SAMPLE
) );
698 EM_log( CK_LOG_WARNING
, "DeccumBuffer:resize(%ld) failed to allocated..." );
716 this->get( next
, size
);
721 // read pointer is at the end
733 //-----------------------------------------------------------------------------
736 //-----------------------------------------------------------------------------
737 void DeccumBuffer::cleanup()
744 m_read_offset
= m_max_elem
= 0;
750 //-----------------------------------------------------------------------------
753 //-----------------------------------------------------------------------------
754 void DeccumBuffer::get( SAMPLE
* data
)
757 *data
= m_data
[m_read_offset
];
759 m_data
[m_read_offset
] = 0;
763 if( m_read_offset
>= m_max_elem
)
770 //-----------------------------------------------------------------------------
773 //-----------------------------------------------------------------------------
774 void DeccumBuffer::get( SAMPLE
* buffer
, t_CKINT num_elem
)
777 t_CKINT left
= num_elem
;
779 t_CKINT amount
= m_max_elem
- m_read_offset
;
781 t_CKINT tocopy
= ck_min( left
, amount
);
784 // copy after the write pointer
785 memcpy( buffer
, m_data
+ m_read_offset
, tocopy
* sizeof(SAMPLE
) );
791 amount
= m_read_offset
;
793 t_CKINT tocopy2
= ck_min( left
, amount
);
796 // copy before the write pointer
797 memcpy( buffer
+ tocopy
, m_data
, tocopy2
* sizeof(SAMPLE
) );
803 assert( m_max_elem
== (tocopy
+ tocopy2
) );
804 assert( num_elem
> m_max_elem
);
806 memset( buffer
+ m_max_elem
, 0, (num_elem
- m_max_elem
) * sizeof(SAMPLE
) );
814 //-----------------------------------------------------------------------------
817 //-----------------------------------------------------------------------------
818 void DeccumBuffer::put( SAMPLE
* buffer
, t_CKINT num_elem
)
821 t_CKINT left
= num_elem
;
823 t_CKINT amount
= m_max_elem
- m_read_offset
;
825 t_CKINT tocopy
= ck_min( left
, amount
);
828 // copy after the write pointer
830 for( i
= 0; i
< tocopy
; i
++ )
831 m_data
[m_read_offset
+i
] += buffer
[i
];
837 amount
= m_read_offset
;
839 t_CKINT tocopy2
= ck_min( left
, amount
);
842 // copy before the write pointer
843 for( i
= 0; i
< tocopy2
; i
++ )
844 m_data
[i
] += buffer
[tocopy
+i
];
850 assert( m_max_elem
== (tocopy
+ tocopy2
) );
851 assert( num_elem
> m_max_elem
);
853 EM_log( CK_LOG_WARNING
, "(IFFT): discarding data during OLA synthesis..." );