2
Things, in their Essence,
20
#include "fweelin_block.h"
21
#include "fweelin_core.h"
23
VorbisDecoder::VorbisDecoder(Fweelin *app) : app(app), infd(0) {};
24
VorbisDecoder::~VorbisDecoder() {};
26
// Returns nonzero on error
27
int VorbisDecoder::ReadFromFile(FILE *in) {
28
if (ov_open(in, &vf, NULL, 0) < 0) {
29
printf("DISK: (VorbisFile) Input does not appear to be an Ogg "
34
vorbis_info *vi = ov_info(&vf,-1);
36
if (vi->channels == 2) {
37
printf("DISK: (VorbisFile) Stereo loop\n");
40
else if (vi->channels == 1) {
41
printf("DISK: (VorbisFile) Mono loop\n");
45
printf("DISK: (VorbisFile) Unknown # of audio channels %d\n",vi->channels);
49
if (vi->rate != (signed int) app->getAUDIO()->get_srate()) {
50
printf("DISK: (VorbisFile) Audio encoded at %dHz but we are running at "
52
"Samplerate conversion not yet supported.\n",
53
(int) vi->rate,app->getAUDIO()->get_srate());
61
int VorbisDecoder::Decode(float ***pcm_channels, nframes_t max_len) {
62
return ov_read_float(&vf,pcm_channels,max_len,¤t_section);
65
VorbisEncoder::VorbisEncoder(Fweelin *app, char stereo) : app(app),
68
const static float VORBIS_ENCODE_QUALITY = 0.5;
71
vorbis_info_init(&vi);
72
if (vorbis_encode_init_vbr(&vi,(stereo ? 2 : 1),app->getAUDIO()->get_srate(),
73
VORBIS_ENCODE_QUALITY))
77
vorbis_comment_init(&vc);
78
vorbis_comment_add_tag(&vc,"ENCODER","FreeWheeling");
80
// Analysis state/Aux encoding storage
81
vorbis_analysis_init(&vd,&vi);
82
vorbis_block_init(&vd,&vb);
84
/* set up our packet->stream encoder */
85
/* pick a random serial number; that way we can more likely build
86
chained streams just by concatenation */
88
ogg_stream_init(&os,rand());
91
VorbisEncoder::~VorbisEncoder() {
92
/* Vorbis clean up and exit. vorbis_info_clear() must be called last */
93
ogg_stream_clear(&os);
94
vorbis_block_clear(&vb);
95
vorbis_dsp_clear(&vd);
96
vorbis_comment_clear(&vc);
97
vorbis_info_clear(&vi);
100
void VorbisEncoder::DumpToFile(FILE *out) {
103
// Write vorbis header
105
ogg_packet header_comm;
106
ogg_packet header_code;
108
vorbis_analysis_headerout(&vd,&vc,&header,&header_comm,&header_code);
109
ogg_stream_packetin(&os,&header); /* automatically placed in its own page */
110
ogg_stream_packetin(&os,&header_comm);
111
ogg_stream_packetin(&os,&header_code);
114
int result = ogg_stream_flush(&os,&og);
117
fwrite(og.header,1,og.header_len,outfd);
118
fwrite(og.body,1,og.body_len,outfd);
122
// This analyzes and dumps any remaining frames out to file
123
long int VorbisEncoder::Encode() {
125
long int outputsize = 0;
127
// Now do the real analysis!! Meat n potatoes!
128
while(vorbis_analysis_blockout(&vd,&vb) == 1) {
129
/* analysis, assume we want to use bitrate management */
130
vorbis_analysis(&vb,NULL);
131
vorbis_bitrate_addblock(&vb);
133
while(vorbis_bitrate_flushpacket(&vd,&op)) {
134
/* weld the packet into the bitstream */
135
ogg_stream_packetin(&os,&op);
137
/* write out pages (if any) */
140
int result = ogg_stream_pageout(&os,&og);
143
fwrite(og.header,1,og.header_len,outfd);
144
fwrite(og.body,1,og.body_len,outfd);
146
// Add to the output size
147
outputsize += og.header_len;
148
outputsize += og.body_len;
150
if (ogg_page_eos(&og))
158
printf("BLOCK: ERROR: OGG encoder finished but Encode() called!\n");
163
BlockReadManager::BlockReadManager(FILE *in, AutoReadControl *arc,
165
nframes_t peaksavgs_chunksize) :
166
ManagedChain(0,0), in(in), arc(arc), dec(0), bmg(bmg), pa_mgr(0),
167
peaksavgs_chunksize(peaksavgs_chunksize)
169
pthread_mutex_init(&decode_lock,0);
172
BlockReadManager::~BlockReadManager() {
177
pthread_mutex_destroy (&decode_lock);
180
// Start decoding from the given file
181
void BlockReadManager::Start(FILE *new_in) {
183
return; // Already running
185
if (in == 0 && new_in != 0) {
186
// New input specified
191
// Start vorbis decoder
192
dec = new VorbisDecoder(bmg->GetApp());
193
b = (AudioBlock *) bmg->GetApp()->getPRE_AUDIOBLOCK()->RTNew();
194
i = new AudioBlockIterator(b,DECODE_CHUNKSIZE,
195
bmg->GetApp()->getPRE_EXTRACHANNEL());
197
// Compute audio peaks & averages for display
198
if (peaksavgs_chunksize != 0) {
199
AudioBlock *peaks = (AudioBlock *) b->RTNew(),
200
*avgs = (AudioBlock *) b->RTNew();
201
if (peaks == 0 || avgs == 0) {
202
printf("BlockReadManager: ERROR: No free blocks for peaks/avgs\n");
209
b->AddExtendedData(new BED_PeaksAvgs(peaks,avgs,peaksavgs_chunksize));
210
pa_mgr = bmg->PeakAvgOn(b,i,1);
214
// Tell decoder to read from file
215
if (dec->ReadFromFile(in))
216
// End in error, freeing vorbis
221
void BlockReadManager::End(char error) {
222
// Can't end while decoding- lock mutex
223
pthread_mutex_lock (&decode_lock);
230
// Chop block to current position
233
// End peaks avgs compute now
248
printf("DISK: Close input.\n");
249
// Vorbis decoder closes file through ov_clear!
255
// If error, delete chain and send zero to ReadComplete
262
arc->ReadComplete(b);
267
pthread_mutex_unlock(&decode_lock);
270
int BlockReadManager::Manage() {
272
// Not currently decoding
274
// We have a callback, get a chain to load
275
arc->GetReadBlock(&in);
278
// We got a chain to load, so begin
281
// No callback, so we are done!
287
// Make sure we have started on this blockchain
292
pthread_mutex_lock (&decode_lock);
294
// Now that we have the lock, make sure we are still active
297
char stereo = dec->IsStereo();
299
for (int pass = 0; in != 0 && pass < NUM_DECODE_PASSES; pass++) {
300
// Make sure we have an extra block in our chain
301
if (i->GetCurBlock()->next == 0) {
302
AudioBlock *nw = (AudioBlock *) i->GetCurBlock()->RTNew();
304
// Pause decode until block is here
305
printf("BlockReadManager: Waiting for block.\n");
306
pthread_mutex_unlock (&decode_lock);
310
i->GetCurBlock()->Link(nw);
314
int len = dec->Decode(&inbuf,DECODE_CHUNKSIZE);
316
// Store in block actual samples read, waiting for alloc if necessary
318
i->PutFragment(inbuf[0],inbuf[1],len,1);
320
i->PutFragment(inbuf[0],0,len,1);
323
} else if (len == 0) {
325
pthread_mutex_unlock (&decode_lock);
328
// Stream error- just continue
329
printf("BlockReadManager (VorbisFile): OGG stream error!\n");
334
pthread_mutex_unlock (&decode_lock);
340
BlockWriteManager::BlockWriteManager(FILE *out, AutoWriteControl *awc,
341
BlockManager *bmg, AudioBlock *b,
342
AudioBlockIterator *i) :
343
ManagedChain(b,i), out(out), len(0), awc(awc), enc(0), bmg(bmg)
345
pthread_mutex_init(&encode_lock,0);
348
BlockWriteManager::~BlockWriteManager() {
353
pthread_mutex_destroy (&encode_lock);
356
// Start encoding the given block chain to the given file
357
void BlockWriteManager::Start(FILE *new_out, AudioBlock *new_b,
358
AudioBlockIterator *new_i,
361
return; // Already running
363
if (b == 0 && new_b != 0) {
364
// New chain specified
365
// printf("start: new chain b: %p new_b: %p\n",b,new_b);
373
//printf("start: out: %p new_out: %p, b: %p new_b: %p\n",out,new_out,
376
// Start vorbis encoder
377
enc = new VorbisEncoder(bmg->GetApp(),b->IsStereo());
378
ei = new AudioBlockIterator(b,ENCODE_CHUNKSIZE);
380
// Set encoder to dump to file
381
enc->DumpToFile(out);
385
void BlockWriteManager::End() {
386
// Can't end while encoding- lock mutex
387
pthread_mutex_lock (&encode_lock);
398
printf("DISK: Close output.\n");
407
pthread_mutex_unlock(&encode_lock);
410
int BlockWriteManager::Manage() {
412
// Not currently encoding
414
// We have a callback, get a chain to save
415
awc->GetWriteBlock(&out,&b,&i,&len);
418
// We got a chain to save, so begin
421
// No callback, so we are done!
427
// Make sure we have started on this blockchain
432
pthread_mutex_lock (&encode_lock);
434
// Now that we have the lock, make sure we are still active
436
nframes_t pos = ei->GetTotalLength2Cur(),
438
nframes_t num = MIN(ENCODE_CHUNKSIZE,remaining);
440
float **obuf = enc->GetAnalysisBuffer(num);
442
if (enc->IsStereo()) {
444
ei->GetFragment(&ibuf[0],&ibuf[1]);
445
memcpy(obuf[0],ibuf[0],sizeof(float) * num);
446
memcpy(obuf[1],ibuf[1],sizeof(float) * num);
449
ei->GetFragment(&ibuf[0],0);
450
memcpy(obuf[0],ibuf[0],sizeof(float) * num);
453
enc->WroteToBuffer(num);
456
if (remaining <= ENCODE_CHUNKSIZE) {
458
pthread_mutex_unlock (&encode_lock);
465
pthread_mutex_unlock (&encode_lock);
471
BED_PeaksAvgs::~BED_PeaksAvgs() {
472
peaks->DeleteChain();
476
int BED_MarkerPoints::CountMarkers() {
477
TimeMarker *cur = markers;
487
BED_MarkerPoints::~BED_MarkerPoints() {
488
TimeMarker *cur = markers;
490
TimeMarker *tmp = cur->next;
496
// Returns the nth marker before (in time) the current offset passed
497
// This method correctly handles a reverse wrap case when the
498
// marker NBeforeCur is farther ahead in the attached block than the
500
TimeMarker *BED_MarkerPoints::GetMarkerNBeforeCur(int n, nframes_t curofs) {
501
TimeMarker *cur = markers;
502
signed int markcnt = 0;
503
int totalmarks = CountMarkers();
506
return 0; // No solution because there are no markers!
508
while (cur != 0 && cur->markofs < curofs) {
513
// Markcnt now indexes the next marker after curofs
516
while (markcnt < 0) {
518
markcnt += totalmarks;
521
// Now get marker indexed by markcnt
524
while (cur != 0 && markcnt2 != markcnt) {
534
// Create a new extra channel
535
BED_ExtraChannel::BED_ExtraChannel(nframes_t len) {
537
//printf("allocating origbuf..\n");
538
origbuf = buf = new sample_t[len];
539
//printf("done: origbuf %p: buf %p!..\n",origbuf,buf);
545
BED_ExtraChannel::~BED_ExtraChannel() {
547
//printf("deleting origbuf %p: buf %p!..\n",origbuf,buf);
553
// Create a new audioblock as the beginning of a block list
554
AudioBlock::AudioBlock(nframes_t len) : len(len), next(0),
558
origbuf = buf = new sample_t[len];
561
// Create a new audioblock and link up the specified block to it
562
AudioBlock::AudioBlock(AudioBlock *prev, nframes_t len) :
563
len(len), next(0), first(prev->first), xt(0) {
566
origbuf = buf = new sample_t[len];
569
AudioBlock::~AudioBlock() {
570
//printf("~AudioBlock len: %d dsz: %d\n",len,sizeof(*buf));
575
// Clears this block chain- not changing length
576
void AudioBlock::Zero() {
577
AudioBlock *cur = first;
579
memset(cur->buf,0,sizeof(sample_t)*cur->len);
584
// Link us up to the specified block
585
void AudioBlock::Link(AudioBlock *to) {
592
void AudioBlock::ChopChain() {
593
// Chop off the chain at this block
594
// Freeing unused blocks
595
AudioBlock *cur = next;
598
AudioBlock *tmp = cur->next;
600
printf("BLOCK: WARNING: XT data not freed in ChopChain! "
608
void AudioBlock::SmoothEnd() {
609
// Smooth the end of this chain into the beginning for looping
610
AudioBlock *smoothblk;
613
totallen = GetTotalLen();
614
if (totallen >= AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN)
615
smoothcnt = totallen - AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
617
return; // Very short chain, can't smooth it
619
// Get block & offset for start of smooth
620
SetPtrsFromAbsOffset(&smoothblk, &smoothofs, smoothcnt);
621
if (smoothblk == 0) {
623
printf("AudioBlock: ERROR: Block position mismatch in SmoothEnd\n");
627
AudioBlock *startblk = first;
628
nframes_t startofs = 0;
631
BED_ExtraChannel *rightstartblk =
632
(BED_ExtraChannel *) startblk->GetExtendedData(T_BED_ExtraChannel),
633
*rightsmoothblk = (BED_ExtraChannel *)
634
smoothblk->GetExtendedData(T_BED_ExtraChannel);
636
if (rightstartblk != 0 && rightsmoothblk != 0)
640
dmix = 1./(float)AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
641
for (nframes_t i = 0; i < AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN; i++,
643
smoothblk->buf[smoothofs] = mix*startblk->buf[startofs] +
644
(1.0-mix)*smoothblk->buf[smoothofs];
646
rightsmoothblk->buf[smoothofs] = mix*rightstartblk->buf[startofs] +
647
(1.0-mix)*rightsmoothblk->buf[smoothofs];
651
if (smoothofs >= smoothblk->len) {
652
smoothblk = smoothblk->next;
654
if (smoothblk == 0) {
655
if (i+1 < AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN) {
657
printf("AudioBlock: ERROR: (smoothblk) Block size mismatch in "
658
"SmoothEnd: i: %d\n", i);
664
rightsmoothblk = (BED_ExtraChannel *)
665
smoothblk->GetExtendedData(T_BED_ExtraChannel);
666
if (stereo && rightsmoothblk == 0) {
668
printf("AudioBlock: ERROR: (smoothblk) Right channel "
674
if (startofs >= startblk->len) {
675
startblk = startblk->next;
678
if (i+1 < AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN) {
680
printf("AudioBlock: ERROR: (startblk) Block size mismatch in "
687
rightstartblk = (BED_ExtraChannel *)
688
startblk->GetExtendedData(T_BED_ExtraChannel);
689
if (stereo && rightstartblk == 0) {
691
printf("AudioBlock: ERROR: (startblk) Right channel disappeared!\n");
698
// Adjust first buf to skip samples that were smoothed into end
699
if (first->len < AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN) {
700
printf("AudioBlock: WARNING: First block is very short, "
701
"no adjust in SmoothEnd.\n");
703
first->buf += AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
704
first->len -= AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
706
BED_ExtraChannel *rightfirst =
707
(BED_ExtraChannel *) first->GetExtendedData(T_BED_ExtraChannel);
709
rightfirst->buf += AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
712
//printf("endsmooth: startofs: %d smoothofs: %d len: %d\n",
713
// startofs, smoothofs, totallen);
717
void AudioBlock::DeleteChain() {
718
AudioBlock *cur = first;
720
// First erase any extended data
721
BlockExtendedData *curxt = cur->xt;
723
BlockExtendedData *tmpxt = curxt->next;
728
// Then the block itself!
729
AudioBlock *tmp = cur->next;
735
// Returns the total length of this audio chain
736
nframes_t AudioBlock::GetTotalLen() {
738
AudioBlock *cur = first;
747
// Gets extended data for this block
748
BlockExtendedData *AudioBlock::GetExtendedData(BlockExtendedDataType x) {
749
BlockExtendedData *cur = xt;
750
while (cur!=0 && cur->GetType()!=x)
755
// Add this extended data to the list of extended data for this block
756
void AudioBlock::AddExtendedData(BlockExtendedData *nw) {
761
// Finds the audioblock and offset into that block that correspond
762
// to the provided absolute offset into this chain
763
void AudioBlock::SetPtrsFromAbsOffset(AudioBlock **ptr, nframes_t *blkofs,
765
AudioBlock *cur = first,
767
nframes_t curofs = 0,
769
while (cur != 0 && curofs <= absofs) {
776
if (curofs < absofs || prev == 0) {
777
// We're at the end and we still haven't traversed far enough!
784
*blkofs = absofs-prevofs;
787
// Generates a subchain of AudioBlocks by copying the samples between offsets
788
// from & to.. offsets expressed absolutely with reference to
789
// beginning of this chain!
790
// Samples are copied up to but not including toofs
791
// If toofs < fromofs, generates a subblock that includes the end of
792
// the block and the beginning up to toofs (wrap case)
793
// Returns the last block in the new subchain
794
// Flag sets whether to copy stereo channel if there is one
796
AudioBlock *AudioBlock::GenerateSubChain(nframes_t fromofs, nframes_t toofs,
798
if (toofs == fromofs)
802
toofs += GetTotalLen();
805
BED_ExtraChannel *rightfirst = (BED_ExtraChannel *)
806
first->GetExtendedData(T_BED_ExtraChannel);
807
char stereo = (copystereo && rightfirst != 0);
809
// Get enough new blocks to fit the subblock size
810
nframes_t sublen = toofs - fromofs,
812
AudioBlock *subfirst = 0,
814
while (suballoc < sublen) {
816
subcur = subfirst = (AudioBlock *)RTNew();
818
printf("Err: GenerateSubChain- No new blocks available\n");
823
AudioBlock *tmp = (AudioBlock *)RTNew();
825
printf("Err: GenerateSubChain- No new blocks available\n");
829
subcur = subcur->next;
833
BED_ExtraChannel *rightsub = (BED_ExtraChannel*)rightfirst->RTNew();
835
printf("Err: GenerateSubChain- No new right blocks available\n");
838
subcur->AddExtendedData(rightsub);
841
suballoc += subcur->len;
844
// Find starting pos in chain
847
SetPtrsFromAbsOffset(&cur,&curofs,fromofs);
850
nframes_t subofs = 0,
854
BED_ExtraChannel *subright =
855
(stereo ? (BED_ExtraChannel *) subcur->GetExtendedData(T_BED_ExtraChannel)
858
(stereo ? (BED_ExtraChannel *) cur->GetExtendedData(T_BED_ExtraChannel)
862
nframes_t n = MIN(cur->len-curofs,remaining);
863
n = MIN(n,subcur->len-subofs);
865
memcpy(&subcur->buf[subofs],&cur->buf[curofs],n*sizeof(sample_t));
867
memcpy(&subright->buf[subofs],&right->buf[curofs],n*sizeof(sample_t));
872
if (curofs >= cur->len) {
876
// Past the end of the block chain-- wrap around to first
880
right = (BED_ExtraChannel *) cur->GetExtendedData(T_BED_ExtraChannel);
883
if (subofs >= subcur->len) {
884
subcur = subcur->next;
886
if (subcur == 0 && remaining) {
887
// This should never happen, because we make the destination
888
// chain long enough to hold the subblock
889
printf("Err: GenerateSubChain destination block size mismatch\n");
894
subright = (BED_ExtraChannel *)
895
subcur->GetExtendedData(T_BED_ExtraChannel);
899
// Truncate the last presized subblock to the right length
900
subcur->len = subofs;
902
// And return the last block in the chain
906
// *** To be tested! ***
908
// Removes the last 'hacklen' samples from this block chain
909
// Returns nonzero on error!
911
int AudioBlock::HackTotalLengthBy(nframes_t hacklen) {
912
// Compute the position of hack
913
nframes_t chainlen = GetTotalLen();
914
//printf("Hack (b): %ld\n",chainlen);
917
if (chainlen <= hacklen)
919
SetPtrsFromAbsOffset(&hackblk,&hackofs,chainlen-hacklen);
921
// Now hackblk[hackofs] should be the first sample to erase at the
923
hackblk->len = hackofs; // Truncate length of block
924
// Note: Block memory isnt resized, so extra memory lingers until
925
// the block is erased
927
AudioBlock *tmp = hackblk->next;
928
hackblk->next = 0; // End of chain at hack position
930
// Erase remaining blocks in chain
932
while (hackblk != 0) {
938
// **** To be implemented
939
// **** Hack stereo samples
941
//printf("Hack (e): %ld\n",GetTotalLen());
945
// Inserts the new blockchain at the beginning of this block chain
946
// Returns a pointer to the new first block
947
AudioBlock *AudioBlock::InsertFirst(AudioBlock *nw) {
948
// Move to the end of the passed chain
949
while (nw->next != 0)
952
// Link new block to the beginning of our chain
955
// Link all first pointers to first block in new chain
956
AudioBlock *cur = first;
958
cur->first = nw->first;
965
AudioBlockIterator::AudioBlockIterator(AudioBlock *firstblock,
966
nframes_t fragmentsize,
967
PreallocatedType *pre_extrachannel) :
968
pre_extrachannel(pre_extrachannel), currightblock(0), nextrightblock(0),
969
curblock(firstblock), nextblock(0), curblkofs(0), nextblkofs(0), curcnt(0),
970
nextcnt(0), fragmentsize(fragmentsize), stopped(0) {
971
fragment[0] = new sample_t[fragmentsize];
972
fragment[1] = new sample_t[fragmentsize];
975
AudioBlockIterator::~AudioBlockIterator() {
976
delete[] fragment[0];
977
delete[] fragment[1];
980
// Stores in cnt the absolute count corresponding to the given
982
void AudioBlockIterator::GenCnt(AudioBlock *blk, nframes_t blkofs,
984
AudioBlock *cur = curblock->first;
985
nframes_t curofs = 0;
986
while (cur != 0 && cur != blk) {
987
// Add the length of this whole block
993
// Given block not found!
997
// We are now on the given block- add only current block offset
1003
void AudioBlockIterator::Jump(nframes_t ofs) {
1004
// Quantize the specified offset to within the limits of the blockchain
1005
ofs = ofs % curblock->GetTotalLen();
1007
curblock->SetPtrsFromAbsOffset(&curblock,&curblkofs,ofs);
1008
if (curblock == 0) {
1009
printf("Err: AudioBlockIterator::Jump- Pointer/size mismatch\n");
1020
void AudioBlockIterator::GenConstants() {
1021
// Need to recompute curcnt to account for extra blocks?
1022
GenCnt(curblock,curblkofs,&curcnt);
1023
GenCnt(nextblock,nextblkofs,&nextcnt);
1026
// Moves iterator to start position
1027
void AudioBlockIterator::Zero() {
1030
curblock = curblock->first;
1036
// Advances to the next fragment
1037
void AudioBlockIterator::NextFragment() {
1038
// Only advance if not stopped
1040
// We must first get a fragment before advancing
1044
currightblock = nextrightblock;
1046
curblock = nextblock;
1047
curblkofs = nextblkofs;
1054
// PutFragment puts the specified fragment back into this AudioBlock
1055
// returns nonzero if the end of the block is reached, and we wrap to next
1056
int AudioBlockIterator::PutFragment (sample_t *frag_l, sample_t *frag_r,
1057
nframes_t size_override,
1059
nframes_t fragofs = 0;
1060
nframes_t n = (size_override == 0 ? fragmentsize : size_override);
1063
// Keep local track of pointers
1064
// Since we have to be threadsafe
1065
BED_ExtraChannel *lclrightblock = currightblock;
1066
AudioBlock *lclblock = curblock;
1067
nframes_t lclblkofs = curblkofs,
1072
nextbit = MIN((nframes_t) n, lclblock->len - lclblkofs);
1074
// Copy back into our block
1077
memcpy(&lclblock->buf[lclblkofs],
1079
sizeof(sample_t)*nextbit);
1081
// If right channel is given and we don't know the right block, find it
1083
if (lclrightblock == 0) {
1084
lclrightblock = (BED_ExtraChannel *)
1085
lclblock->GetExtendedData(T_BED_ExtraChannel);
1086
if (lclrightblock == 0) {
1087
// No right channel exists but we are being told to put data there--
1088
// so create a right channel!
1089
if (pre_extrachannel == 0) {
1090
printf("BLOCK: ERROR: Need to make right channel buffer but no "
1091
"preallocator was passed!\n");
1095
lclrightblock = (BED_ExtraChannel *) pre_extrachannel->RTNew();
1096
if (lclrightblock == 0 && wait_alloc) {
1097
printf("BLOCK: Waiting for BED_ExtraChannel.\n");
1098
usleep(10000); // Wait then try again
1100
} while (lclrightblock == 0 && wait_alloc);
1101
if (lclrightblock != 0)
1102
lclblock->AddExtendedData(lclrightblock);
1104
printf("BLOCK: ERROR: RTNew() failed for BED_ExtraChannel.\n");
1112
memcpy(&lclrightblock->buf[lclblkofs],
1114
sizeof(sample_t)*nextbit);
1118
lclblkofs += nextbit;
1122
if (lclblkofs >= lclblock->len) { // if (n) is wrong
1123
// If we get here, it means this block has been fully dumped
1124
// so we need the next block
1127
if (lclblock->next == 0) {
1128
// END OF AUDIOBLOCK LIST, LOOP TO BEGINNING
1129
lclblock = lclblock->first;
1135
lclblock = lclblock->next;
1142
nextblock = lclblock,
1143
nextrightblock = lclrightblock,
1144
nextblkofs = lclblkofs,
1150
// Returns the current fragment of audio
1151
// nextblock and nextblkofs become the new block pointer and offset
1152
// for the next fragment
1153
void AudioBlockIterator::GetFragment(sample_t **frag_l, sample_t **frag_r) {
1154
nframes_t fragofs = 0;
1155
nframes_t n = fragmentsize;
1157
// Keep local track of pointers
1158
// Since we have to be threadsafe
1159
BED_ExtraChannel *lclrightblock = currightblock;
1160
AudioBlock *lclblock = curblock;
1161
nframes_t lclblkofs = curblkofs,
1166
nextbit = MIN((nframes_t) n, lclblock->len - lclblkofs);
1170
memcpy(&fragment[0][fragofs],
1171
&lclblock->buf[lclblkofs],
1172
sizeof(sample_t)*nextbit);
1174
// If right channel is given and we don't know the right block, find it
1176
if (lclrightblock == 0) {
1177
lclrightblock = (BED_ExtraChannel *)
1178
lclblock->GetExtendedData(T_BED_ExtraChannel);
1179
if (lclrightblock == 0) {
1180
// No right channel exists but we are being told to get data--
1181
printf("BLOCK: ERROR: Iterator asked for right channel but none "
1188
memcpy(&fragment[1][fragofs],
1189
&lclrightblock->buf[lclblkofs],
1190
sizeof(sample_t)*nextbit);
1192
// Make -sure- we don't jump blocks and keep old rightblock
1196
lclblkofs += nextbit;
1201
if (lclblkofs >= lclblock->len) {
1202
// If we get here, it means this block is at an end
1203
// so we need the next block
1204
if (lclblock->next == 0) {
1205
// END OF AUDIOBLOCK LIST, LOOP TO BEGINNING
1206
lclblock = lclblock->first;
1211
lclblock = lclblock->next;
1212
lclblkofs = 0; // Beginning of next block
1218
nextblock = lclblock,
1219
nextrightblock = lclrightblock,
1220
nextblkofs = lclblkofs,
1223
// Return fragment buffers
1225
*frag_l = fragment[0];
1227
*frag_r = fragment[1];
1231
void AudioBlockIterator::EndChain() {
1232
// Mark iterator stopped
1235
//printf("Crop: %ld to %ld\n", curblock->len, curblkofs);
1236
if (curblkofs < (nframes_t) fragmentsize) {
1237
//printf("WARNING: REALLY SHORT BLOCK: %d\n",curblkofs);
1238
curblock->len = fragmentsize;
1241
curblock->len = curblkofs;
1243
// Stop the chain at this place
1244
curblock->ChopChain();
1247
int GrowChainManager::Manage() {
1248
// Manage chain growth
1249
if (!i->IsStopped())
1250
if (i->GetCurBlock()->next == 0) {
1251
// Iterator is running and no more blocks at the end
1252
// of this chain! Get another and link it up.
1253
AudioBlock *nw = (AudioBlock *) i->GetCurBlock()->RTNew();
1255
printf("GrowChainManager: ERROR: No free blocks to grow chain\n");
1258
i->GetCurBlock()->Link(nw);
1260
// Second channel allocating is done as needed by PutFragment
1267
void PeaksAvgsManager::Setup() {
1269
pa = (BED_PeaksAvgs *)(b->GetExtendedData(T_BED_PeaksAvgs));
1270
// To do: Optimize this to bypass iterator-
1271
// it would be faster since we are moving one sample at a time!
1272
peaksi = new AudioBlockIterator(pa->peaks,1);
1273
avgsi = new AudioBlockIterator(pa->avgs,1);
1274
mi = new AudioBlockIterator(b,1);
1275
stereo = b->IsStereo();
1278
// Grow peaks & avgs blocks
1279
bmg->GrowChainOn(pa->peaks,peaksi);
1280
bmg->GrowChainOn(pa->avgs,avgsi);
1284
PeaksAvgsManager::~PeaksAvgsManager() {
1294
void PeaksAvgsManager::End() {
1299
// End chain at current pos!
1303
bmg->GrowChainOff(pa->peaks);
1304
bmg->GrowChainOff(pa->avgs);
1309
int PeaksAvgsManager::Manage() {
1314
// Compute running peaks and averages
1320
// Get current position in iterator
1321
nframes_t curcnt = i->GetTotalLength2Cur();
1323
if (curcnt < lastcnt) {
1324
// We have a wrap condition!- loop
1325
// printf("Wrap! Now at: %ld\n",curcnt);
1326
curcnt = b->GetTotalLen();
1330
// Update peaks & averages to current position
1331
while (lastcnt < curcnt) {
1335
mi->GetFragment(&sptr[0],&sptr[1]);
1339
mi->GetFragment(&sptr[0],0);
1344
// If chunkcnt is -1, we have temporarily stopped until a wrap
1357
runtally += (fabs(s_l)+fabs(s_r))/2;
1360
runtally += fabs(s_l);
1364
if (chunkcnt >= pa->chunksize) {
1366
sample_t peak = runmax-runmin,
1367
avg = (sample_t) (runtally/pa->chunksize);
1369
if (peaksi->PutFragment(&peak,0) ||
1370
avgsi->PutFragment(&avg,0)) {
1371
// Peaks should not be wrapping before main buf, stop!
1373
// Note that this does happen!!
1377
peaksi->NextFragment();
1378
avgsi->NextFragment();
1393
/* printf("Main wrap!: MI: %ld PI: %ld AI: %ld\n",
1394
mi->GetTotalLength2Cur(),
1395
peaksi->GetTotalLength2Cur(),
1396
avgsi->GetTotalLength2Cur()); */
1400
lastcnt = 0; // Wrap to beginning, and do the samples there
1413
void StripeBlockManager::Setup() {
1414
// Does this block have BED_MarkerPoints?
1415
mp = (BED_MarkerPoints *)(b->GetExtendedData(T_BED_MarkerPoints));
1418
b->AddExtendedData(mp = new BED_MarkerPoints());
1422
int StripeBlockManager::Manage() {
1423
// This is called whenever a time marker should be striped
1429
wrap = 2; // Special case if we just wrapped and are on a 2nd pass
1433
// Get current iterated offset into block
1434
nframes_t curcnt = i->GetTotalLength2Cur();
1436
if (curcnt < lastcnt) {
1437
// We have a wrap condition!- loop
1438
// printf("Wrap! Now at: %ld\n",curcnt);
1439
curcnt = b->GetTotalLen();
1443
// Scan through time markers for a good place to insert a new one
1444
TimeMarker *cur = mp->markers,
1447
// On 2nd pass, delete markers at 0.
1449
while (cur != 0 && cur->markofs < lastcnt) {
1454
while (cur != 0 && cur->markofs <= lastcnt) {
1460
// Delete any markers between last position & current
1461
while (cur != 0 && cur->markofs <= curcnt) {
1462
TimeMarker *tmp = cur->next;
1473
// Now insert a new marker in this position
1474
// Use realtime new method- no problem
1475
TimeMarker *nw = (TimeMarker *) pre_tm->RTNew();
1477
printf("StripeBlockManager: ERROR: No free TimeMarkers\n");
1480
nw->markofs = curcnt;
1491
lastcnt = 0; // Start again from beginning to curcnt
1497
int DelayProcessorCallManager::Manage() {
1498
// OK, we've been triggered!
1499
//printf("Call processor %ld- %d\n",(long) p, data);
1502
data = p->ProcessorCall(trigger,data);
1505
// Now remove this manager
1508
// Save this manager
1513
BlockManager::BlockManager (Fweelin *app) :
1514
manageblocks(0), himanageblocks(0), threadgo(1), app(app) {
1515
pre_growchain = new PreallocatedType(app->getMMG(),
1516
::new GrowChainManager(),
1517
sizeof(GrowChainManager));
1518
pre_peaksavgs = new PreallocatedType(app->getMMG(),
1519
::new PeaksAvgsManager(),
1520
sizeof(PeaksAvgsManager));
1521
pre_hipri = new PreallocatedType(app->getMMG(),
1522
::new HiPriManagedChain(),
1523
sizeof(HiPriManagedChain));
1524
pre_stripeblock = new PreallocatedType(app->getMMG(),
1525
::new StripeBlockManager(),
1526
sizeof(StripeBlockManager));
1527
pre_delayprocessorcall =
1528
new PreallocatedType(app->getMMG(),
1529
::new DelayProcessorCallManager(),
1530
sizeof(DelayProcessorCallManager));
1532
// Start a block managing thread
1533
int ret = pthread_create(&manage_thread,
1536
static_cast<void *>(this));
1538
printf("(blockmanager) pthread_create failed, exiting");
1542
struct sched_param schp;
1543
memset(&schp, 0, sizeof(schp));
1544
// Manage thread calls delete- can't be SCHED_FIFO
1545
schp.sched_priority = sched_get_priority_max(SCHED_OTHER);
1546
// schp.sched_priority = sched_get_priority_min(SCHED_FIFO);
1547
if (pthread_setschedparam(manage_thread, SCHED_OTHER, &schp) != 0) {
1548
printf("BLOCK: Can't set realtime thread, will use nonRT!\n");
1552
BlockManager::~BlockManager () {
1553
// Terminate the management thread
1555
pthread_join(manage_thread,0);
1557
delete pre_growchain;
1558
delete pre_peaksavgs;
1560
delete pre_stripeblock;
1561
delete pre_delayprocessorcall;
1564
// Turns on automatic allocation of new blocks at the end of the
1565
// specified chain. We work in conjunction with the specified iterator,
1566
// so that when the iterator approaches the end of the block chain,
1567
// the chain grows automatically
1568
void BlockManager::GrowChainOn (AudioBlock *b, AudioBlockIterator *i) {
1569
// Check if the block is already being watched
1570
DelManager(&manageblocks,b,T_MC_GrowChain);
1571
// Tell the manage thread to grow this chain
1572
GrowChainManager *nw = (GrowChainManager *) pre_growchain->RTNew();
1575
AddManager(&manageblocks,nw);
1578
void BlockManager::GrowChainOff (AudioBlock *b) {
1579
DelManager(&manageblocks,b,T_MC_GrowChain);
1582
// Turns on computation of running sample peaks and averages
1583
// for the specified Block & Iterator
1584
// We compute as the currenty iterated position advances
1585
PeaksAvgsManager *BlockManager::PeakAvgOn (AudioBlock *b,
1586
AudioBlockIterator *i,
1588
// Check if the block is already being watched
1589
DelManager(&manageblocks,b,T_MC_PeaksAvgs);
1590
// Tell the manage thread to compute peaks & averages
1591
PeaksAvgsManager *nw = (PeaksAvgsManager *) pre_peaksavgs->RTNew();
1597
AddManager(&manageblocks,nw);
1602
void BlockManager::PeakAvgOff (AudioBlock *b) {
1603
DelManager(&manageblocks,b,T_MC_PeaksAvgs);
1606
void BlockManager::StripeBlockOn (void *trigger, AudioBlock *b,
1607
AudioBlockIterator *i) {
1608
// Check if the block is already being watched
1609
DelHiManager(&himanageblocks,b,T_MC_StripeBlock,trigger);
1610
// Tell the manage thread to stripe beats on blocks
1611
StripeBlockManager *nw = (StripeBlockManager *) pre_stripeblock->RTNew();
1612
nw->pre_tm = app->getPRE_TIMEMARKER();
1615
nw->trigger = trigger;
1617
AddManager((ManagedChain**) &himanageblocks,nw);
1620
void BlockManager::StripeBlockOff (void *trigger, AudioBlock *b) {
1621
DelHiManager(&himanageblocks,b,T_MC_StripeBlock,trigger);
1624
// Removes all delayprocessorcallmanagers on the given trigger
1625
// that call the given processor
1626
void BlockManager::FlushDelayProcessorCall (void *trigger, Processor *p) {
1627
HiPriManagedChain *cur = himanageblocks,
1630
if (cur->GetType() == T_MC_DelayProcessorCall &&
1631
(cur->trigger == 0 || cur->trigger == trigger) &&
1632
((DelayProcessorCallManager *) cur)->p == p) {
1634
HiPriManagedChain *tmp = (HiPriManagedChain *) cur->next;
1638
himanageblocks = tmp;
1642
cur = himanageblocks; // Start again!
1646
cur = (HiPriManagedChain *) cur->next;
1651
void BlockManager::AddDelayProcessorCall (void *trigger, Processor *p,
1653
DelayProcessorCallManager *nw = (DelayProcessorCallManager *)
1654
pre_delayprocessorcall->RTNew();
1655
nw->trigger = trigger;
1658
AddManager((ManagedChain **) &himanageblocks,nw);
1661
void BlockManager::DelDelayProcessorCall (DelayProcessorCallManager *m) {
1662
DelManager((ManagedChain **) &himanageblocks,m);
1665
// Generic delete/add functions for managers (not hipri)
1666
void BlockManager::DelManager (ManagedChain *m) {
1667
DelManager(&manageblocks,m);
1669
void BlockManager::AddManager (ManagedChain *nw) {
1670
AddManager(&manageblocks,nw);
1673
void BlockManager::DelManager (ManagedChain **first, ManagedChain *m) {
1674
ManagedChain *cur = *first,
1677
// Search for manager 'm' in our list
1678
while (cur != 0 && cur != m) {
1686
prev->next = cur->next;
1693
void BlockManager::RefDeleted (ManagedChain **first, void *ref) {
1694
ManagedChain *cur = *first,
1697
if (cur->RefDeleted(ref)) {
1698
//printf("RefDeleted delete loose reference!\n");
1701
ManagedChain *tmp = cur->next;
1709
cur = *first; // Start again!
1718
// Notify all Managers that the object pointed to has been deleted-
1719
// To avoid broken dependencies
1720
void BlockManager::RefDeleted (void *ref) {
1721
RefDeleted(&manageblocks,ref);
1722
RefDeleted((ManagedChain **) &himanageblocks,ref);
1725
// Activate a hipriority trigger- all hiprimanagedchains with
1726
// specified trigger pointer will have manage() method called
1727
// Safe to call in realtime!
1728
void BlockManager::HiPriTrigger (void *trigger) {
1729
HiPriManagedChain *cur = himanageblocks,
1732
// Count the managers- this is necessary
1733
// Because new managers can be added during the Trigger process
1734
// causing infinite loops
1738
cur = (HiPriManagedChain *) cur->next;
1741
//printf("HIPRITRIG: %ld\n", mgrcnt);
1743
cur = himanageblocks;
1745
while (curcnt < mgrcnt && cur != 0) {
1748
if (cur->trigger == trigger || cur->trigger == 0)
1749
// Ok, right trigger or no trigger specified, call 'em!
1750
if (cur->Manage()) {
1752
HiPriManagedChain *tmp = (HiPriManagedChain *) cur->next;
1756
himanageblocks = tmp;
1769
cur = (HiPriManagedChain *) cur->next;
1775
// Returns the 1st chain manager associated with block b
1777
ManagedChain *BlockManager::GetBlockManager(AudioBlock *o,
1778
ManagedChainType t) {
1779
ManagedChain *cur = manageblocks;
1781
// Search for block 'o' && type t in our list
1782
while (cur != 0 && (cur->b != o || cur->GetType() != t))
1788
void BlockManager::AddManager (ManagedChain **first, ManagedChain *nw) {
1789
ManagedChain *cur = *first;
1791
*first = nw; // That was easy, now we have 1 item
1793
while (cur->next != 0)
1795
cur->next = nw; // Link up the last item to new1
1799
// Delete a managed chain for block o and manager type t
1800
// If t is T_MC_None, removes the first managed chain for 'o'
1802
void BlockManager::DelManager (ManagedChain **first, AudioBlock *o,
1803
ManagedChainType t) {
1804
ManagedChain *cur = *first,
1807
// Search for block 'o' in our list of type 't'
1808
while (cur != 0 && (cur->b != o || (cur->GetType() != t &&
1817
prev->next = cur->next;
1824
// Delete a hiprimanaged chain for block o and manager type t
1825
// with specified trigger.
1826
// If t is T_MC_None, removes the first managed chain for 'o'
1827
// with specified trigger, of any type
1828
void BlockManager::DelHiManager (HiPriManagedChain **first,
1830
ManagedChainType t, void *trigger) {
1831
HiPriManagedChain *cur = *first,
1834
// Search for block 'o' in our list of type 't'
1835
while (cur != 0 && (cur->b != o || cur->trigger != trigger ||
1836
(cur->GetType() != t && t != T_MC_None))) {
1838
cur = (HiPriManagedChain *) cur->next;
1844
prev->next = cur->next;
1846
*first = (HiPriManagedChain *) cur->next;
1851
void *BlockManager::run_manage_thread (void *ptr) {
1852
BlockManager *inst = static_cast<BlockManager *>(ptr);
1854
while (inst->threadgo) {
1855
// Manage the blocks we have
1856
ManagedChain *cur = inst->manageblocks,
1859
if (cur->Manage()) {
1861
ManagedChain *tmp = cur->next;
1865
inst->manageblocks = tmp;
1866
//printf("end mgr\n");
1869
// We have to start again, because manageblocks list may
1870
// have changed-- for ex, in destructor of manager 'cur'
1871
// may call DelManager
1872
cur = inst->manageblocks;
1881
// Produce status report?
1882
FloConfig *fs = inst->app->getCFG();
1883
if (fs->status_report == FS_REPORT_BLOCKMANAGER) {
1884
fs->status_report++;
1886
printf("BLOCKMANAGER REPORT:\n");
1887
ManagedChain *cur = inst->manageblocks;
1889
printf(" bmg mgr: type(%d)\n",cur->GetType());
1893
cur = inst->himanageblocks;
1895
printf(" bmg HiPrimgr: type(%d)\n",cur->GetType());
1900
// 10 ms delay between management tasks
1904
// Delete all blockmanagers now
1905
ManagedChain *cur = inst->manageblocks;
1907
ManagedChain *tmp = cur->next;
1911
cur = inst->himanageblocks;
1913
ManagedChain *tmp = cur->next;