~ubuntu-branches/ubuntu/quantal/freewheeling/quantal

« back to all changes in this revision

Viewing changes to src/fweelin_block.cc

  • Committer: Bazaar Package Importer
  • Author(s): Paul Brossier
  • Date: 2005-08-06 15:11:54 UTC
  • Revision ID: james.westby@ubuntu.com-20050806151154-nvhhuxtyvgweh75u
Tags: upstream-0.5pre4
ImportĀ upstreamĀ versionĀ 0.5pre4

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* 
 
2
   Things, in their Essence,
 
3
   are not of this world.
 
4
*/
 
5
 
 
6
#include <sys/time.h>
 
7
 
 
8
#include <stdio.h>
 
9
#include <errno.h>
 
10
#include <unistd.h>
 
11
#include <stdlib.h>
 
12
 
 
13
#include <math.h>
 
14
#include <string.h>
 
15
 
 
16
#include <pthread.h>
 
17
#include <sched.h>
 
18
#include <sys/mman.h>
 
19
 
 
20
#include "fweelin_block.h"
 
21
#include "fweelin_core.h"
 
22
 
 
23
VorbisDecoder::VorbisDecoder(Fweelin *app) : app(app), infd(0) {};
 
24
VorbisDecoder::~VorbisDecoder() {};
 
25
 
 
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 "
 
30
           "bitstream.\n");
 
31
    return 1;
 
32
  }
 
33
 
 
34
  vorbis_info *vi = ov_info(&vf,-1);
 
35
 
 
36
  if (vi->channels == 2) {
 
37
    printf("DISK: (VorbisFile) Stereo loop\n");
 
38
    stereo = 1;
 
39
  }
 
40
  else if (vi->channels == 1) {
 
41
    printf("DISK: (VorbisFile) Mono loop\n");
 
42
    stereo = 0;
 
43
  }
 
44
  else {
 
45
    printf("DISK: (VorbisFile) Unknown # of audio channels %d\n",vi->channels);
 
46
    return 1;
 
47
  }
 
48
 
 
49
  if (vi->rate != (signed int) app->getAUDIO()->get_srate()) {
 
50
    printf("DISK: (VorbisFile) Audio encoded at %dHz but we are running at "
 
51
           "%dHz.\n"
 
52
           "Samplerate conversion not yet supported.\n",
 
53
           (int) vi->rate,app->getAUDIO()->get_srate());
 
54
    return 1;
 
55
  }
 
56
    
 
57
  infd = in;
 
58
  return 0;
 
59
};
 
60
 
 
61
int VorbisDecoder::Decode(float ***pcm_channels, nframes_t max_len) {
 
62
  return ov_read_float(&vf,pcm_channels,max_len,&current_section);
 
63
};
 
64
 
 
65
VorbisEncoder::VorbisEncoder(Fweelin *app, char stereo) : app(app), 
 
66
                                                          stereo(stereo),
 
67
                                                          outfd(0) {
 
68
  const static float VORBIS_ENCODE_QUALITY = 0.5;
 
69
 
 
70
  // Setup vorbis
 
71
  vorbis_info_init(&vi);
 
72
  if (vorbis_encode_init_vbr(&vi,(stereo ? 2 : 1),app->getAUDIO()->get_srate(),
 
73
                             VORBIS_ENCODE_QUALITY))
 
74
    return;
 
75
  
 
76
  // Comment
 
77
  vorbis_comment_init(&vc);
 
78
  vorbis_comment_add_tag(&vc,"ENCODER","FreeWheeling");
 
79
  
 
80
  // Analysis state/Aux encoding storage
 
81
  vorbis_analysis_init(&vd,&vi);
 
82
  vorbis_block_init(&vd,&vb);
 
83
  
 
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 */
 
87
  srand(time(NULL));
 
88
  ogg_stream_init(&os,rand());
 
89
};
 
90
 
 
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);
 
98
};
 
99
 
 
100
void VorbisEncoder::DumpToFile(FILE *out) {
 
101
  outfd = out;
 
102
 
 
103
  // Write vorbis header
 
104
  ogg_packet header;
 
105
  ogg_packet header_comm;
 
106
  ogg_packet header_code;
 
107
  
 
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);
 
112
  
 
113
  while(1) {
 
114
    int result = ogg_stream_flush(&os,&og);
 
115
    if (result == 0)
 
116
      break;
 
117
    fwrite(og.header,1,og.header_len,outfd);
 
118
    fwrite(og.body,1,og.body_len,outfd);
 
119
  }
 
120
}
 
121
 
 
122
// This analyzes and dumps any remaining frames out to file
 
123
long int VorbisEncoder::Encode() {
 
124
  if (outfd != 0) {
 
125
    long int outputsize = 0;
 
126
    
 
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);
 
132
      
 
133
      while(vorbis_bitrate_flushpacket(&vd,&op)) {
 
134
        /* weld the packet into the bitstream */
 
135
        ogg_stream_packetin(&os,&op);
 
136
        
 
137
        /* write out pages (if any) */
 
138
        char eos = 0;
 
139
        while (!eos) {
 
140
          int result = ogg_stream_pageout(&os,&og);
 
141
          if (result == 0)
 
142
            break;
 
143
          fwrite(og.header,1,og.header_len,outfd);
 
144
          fwrite(og.body,1,og.body_len,outfd);
 
145
          
 
146
          // Add to the output size
 
147
          outputsize += og.header_len;
 
148
          outputsize += og.body_len;
 
149
          
 
150
          if (ogg_page_eos(&og))
 
151
            eos = 1;
 
152
        }
 
153
      }
 
154
    }
 
155
 
 
156
    return outputsize;
 
157
  } else {
 
158
    printf("BLOCK: ERROR: OGG encoder finished but Encode() called!\n");
 
159
    return 0;
 
160
  }
 
161
}
 
162
 
 
163
BlockReadManager::BlockReadManager(FILE *in, AutoReadControl *arc, 
 
164
                                   BlockManager *bmg, 
 
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)
 
168
{
 
169
  pthread_mutex_init(&decode_lock,0);
 
170
};
 
171
 
 
172
BlockReadManager::~BlockReadManager() {
 
173
  if (in != 0) {
 
174
    End(0);
 
175
  }
 
176
 
 
177
  pthread_mutex_destroy (&decode_lock);
 
178
};
 
179
 
 
180
// Start decoding from the given file
 
181
void BlockReadManager::Start(FILE *new_in) {
 
182
  if (dec != 0)
 
183
    return; // Already running
 
184
 
 
185
  if (in == 0 && new_in != 0) {
 
186
    // New input specified
 
187
    in = new_in;
 
188
  }
 
189
 
 
190
  if (in != 0) {
 
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());
 
196
    
 
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");
 
203
        if (peaks != 0)
 
204
          peaks->RTDelete();
 
205
        if (avgs != 0)
 
206
          avgs->RTDelete();
 
207
        pa_mgr = 0;
 
208
      } else {
 
209
        b->AddExtendedData(new BED_PeaksAvgs(peaks,avgs,peaksavgs_chunksize));
 
210
        pa_mgr = bmg->PeakAvgOn(b,i,1);
 
211
      }
 
212
    }
 
213
    
 
214
    // Tell decoder to read from file
 
215
    if (dec->ReadFromFile(in))
 
216
      // End in error, freeing vorbis 
 
217
      End(1);
 
218
  }
 
219
};
 
220
 
 
221
void BlockReadManager::End(char error) {
 
222
  // Can't end while decoding- lock mutex
 
223
  pthread_mutex_lock (&decode_lock);
 
224
 
 
225
  // Stop decoder
 
226
  if (dec != 0) {
 
227
    dec->Stop();
 
228
    delete dec;
 
229
 
 
230
    // Chop block to current position
 
231
    i->EndChain();
 
232
 
 
233
    // End peaks avgs compute now
 
234
    if (pa_mgr != 0) {
 
235
      // Catchup then end
 
236
      pa_mgr->Manage();
 
237
      pa_mgr->End();
 
238
      bmg->PeakAvgOff(b);
 
239
      pa_mgr = 0;
 
240
    }
 
241
 
 
242
    delete i;
 
243
    i = 0;
 
244
    dec = 0;
 
245
  }
 
246
 
 
247
  if (in != 0) {
 
248
    printf("DISK: Close input.\n");
 
249
    // Vorbis decoder closes file through ov_clear!
 
250
    in = 0;
 
251
  }
 
252
 
 
253
  if (b != 0) {
 
254
    if (error) {
 
255
      // If error, delete chain and send zero to ReadComplete
 
256
      b->DeleteChain();
 
257
      b = 0;
 
258
    }
 
259
    
 
260
    // Callback
 
261
    if (arc != 0)
 
262
      arc->ReadComplete(b);
 
263
 
 
264
    b = 0;
 
265
  }
 
266
 
 
267
  pthread_mutex_unlock(&decode_lock);
 
268
};
 
269
 
 
270
int BlockReadManager::Manage() {
 
271
  if (in == 0) {
 
272
    // Not currently decoding
 
273
    if (arc != 0) {
 
274
      // We have a callback, get a chain to load
 
275
      arc->GetReadBlock(&in);
 
276
      
 
277
      if (in != 0)
 
278
        // We got a chain to load, so begin
 
279
        Start();
 
280
    } else {
 
281
      // No callback, so we are done!
 
282
      return 1;
 
283
    }
 
284
  }
 
285
 
 
286
  if (in != 0) {
 
287
    // Make sure we have started on this blockchain
 
288
    if (dec == 0)
 
289
      Start();
 
290
 
 
291
    // Continue decoding
 
292
    pthread_mutex_lock (&decode_lock);
 
293
 
 
294
    // Now that we have the lock, make sure we are still active
 
295
    if (in != 0) {
 
296
      float **inbuf;
 
297
      char stereo = dec->IsStereo();
 
298
 
 
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();
 
303
          if (nw == 0) {
 
304
            // Pause decode until block is here
 
305
            printf("BlockReadManager: Waiting for block.\n");
 
306
            pthread_mutex_unlock (&decode_lock);
 
307
            return 0;
 
308
          }
 
309
          
 
310
          i->GetCurBlock()->Link(nw);
 
311
        }
 
312
        
 
313
        // Decode samples
 
314
        int len = dec->Decode(&inbuf,DECODE_CHUNKSIZE);
 
315
        if (len > 0) {
 
316
          // Store in block actual samples read, waiting for alloc if necessary
 
317
          if (stereo) 
 
318
            i->PutFragment(inbuf[0],inbuf[1],len,1);
 
319
          else
 
320
            i->PutFragment(inbuf[0],0,len,1);
 
321
          
 
322
          i->NextFragment();
 
323
        } else if (len == 0) {
 
324
          // EOF
 
325
          pthread_mutex_unlock (&decode_lock);
 
326
          End(0);
 
327
        } else {
 
328
          // Stream error- just continue
 
329
          printf("BlockReadManager (VorbisFile): OGG stream error!\n");
 
330
        }
 
331
      }
 
332
    }
 
333
 
 
334
    pthread_mutex_unlock (&decode_lock);
 
335
  }
 
336
 
 
337
  return 0;
 
338
};
 
339
 
 
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)
 
344
{
 
345
  pthread_mutex_init(&encode_lock,0);
 
346
};
 
347
 
 
348
BlockWriteManager::~BlockWriteManager() {
 
349
  if (b != 0) {
 
350
    End();
 
351
  }
 
352
 
 
353
  pthread_mutex_destroy (&encode_lock);
 
354
};
 
355
 
 
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,
 
359
                              nframes_t new_len) {
 
360
  if (enc != 0)
 
361
    return; // Already running
 
362
 
 
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);
 
366
    b = new_b;
 
367
    i = new_i;
 
368
    out = new_out;
 
369
    len = new_len;
 
370
  }
 
371
 
 
372
  if (b != 0) {
 
373
    //printf("start: out: %p new_out: %p, b: %p new_b: %p\n",out,new_out,
 
374
    //   b,new_b);
 
375
 
 
376
    // Start vorbis encoder
 
377
    enc = new VorbisEncoder(bmg->GetApp(),b->IsStereo());
 
378
    ei = new AudioBlockIterator(b,ENCODE_CHUNKSIZE);
 
379
    
 
380
    // Set encoder to dump to file
 
381
    enc->DumpToFile(out);
 
382
  }
 
383
};
 
384
 
 
385
void BlockWriteManager::End() {
 
386
  // Can't end while encoding- lock mutex
 
387
  pthread_mutex_lock (&encode_lock);
 
388
 
 
389
  // Stop encoder
 
390
  if (enc != 0) {
 
391
    enc->Stop();
 
392
    delete enc;
 
393
    delete ei;
 
394
    enc = 0;
 
395
  }
 
396
 
 
397
  if (out != 0) {
 
398
    printf("DISK: Close output.\n");
 
399
    fclose(out);
 
400
    out = 0;
 
401
  }
 
402
 
 
403
  b = 0;
 
404
  i = 0;
 
405
  len = 0;
 
406
  
 
407
  pthread_mutex_unlock(&encode_lock);
 
408
};
 
409
 
 
410
int BlockWriteManager::Manage() {
 
411
  if (b == 0) {
 
412
    // Not currently encoding
 
413
    if (awc != 0) {
 
414
      // We have a callback, get a chain to save
 
415
      awc->GetWriteBlock(&out,&b,&i,&len);
 
416
      
 
417
      if (b != 0)
 
418
        // We got a chain to save, so begin
 
419
        Start();
 
420
    } else {
 
421
      // No callback, so we are done!
 
422
      return 1;
 
423
    }
 
424
  }
 
425
 
 
426
  if (b != 0) {
 
427
    // Make sure we have started on this blockchain
 
428
    if (enc == 0)
 
429
      Start();
 
430
 
 
431
    // Continue encoding
 
432
    pthread_mutex_lock (&encode_lock);
 
433
 
 
434
    // Now that we have the lock, make sure we are still active
 
435
    if (b != 0) {
 
436
      nframes_t pos = ei->GetTotalLength2Cur(),
 
437
        remaining = len-pos;
 
438
      nframes_t num = MIN(ENCODE_CHUNKSIZE,remaining);
 
439
      
 
440
      float **obuf = enc->GetAnalysisBuffer(num);    
 
441
      sample_t *ibuf[2];
 
442
      if (enc->IsStereo()) {
 
443
        // Stereo
 
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);
 
447
      } else {
 
448
        // Mono
 
449
        ei->GetFragment(&ibuf[0],0);
 
450
        memcpy(obuf[0],ibuf[0],sizeof(float) * num);
 
451
      }
 
452
 
 
453
      enc->WroteToBuffer(num);
 
454
      enc->Encode();
 
455
      
 
456
      if (remaining <= ENCODE_CHUNKSIZE) {
 
457
        // Finished encoding
 
458
        pthread_mutex_unlock (&encode_lock);
 
459
        End();
 
460
      }
 
461
      else
 
462
        ei->NextFragment();
 
463
    }
 
464
 
 
465
    pthread_mutex_unlock (&encode_lock);
 
466
  }
 
467
 
 
468
  return 0;
 
469
};
 
470
 
 
471
BED_PeaksAvgs::~BED_PeaksAvgs() {
 
472
  peaks->DeleteChain();
 
473
  avgs->DeleteChain();
 
474
};
 
475
 
 
476
int BED_MarkerPoints::CountMarkers() {
 
477
  TimeMarker *cur = markers;
 
478
  int markcnt = 0;
 
479
  while (cur != 0) {
 
480
    markcnt++;
 
481
    cur = cur->next;
 
482
  };
 
483
  
 
484
  return markcnt;
 
485
};
 
486
 
 
487
BED_MarkerPoints::~BED_MarkerPoints() {
 
488
  TimeMarker *cur = markers;
 
489
  while (cur != 0) {
 
490
    TimeMarker *tmp = cur->next;
 
491
    cur->RTDelete();
 
492
    cur = tmp;
 
493
  } 
 
494
};
 
495
 
 
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
 
499
// current offset
 
500
TimeMarker *BED_MarkerPoints::GetMarkerNBeforeCur(int n, nframes_t curofs) {
 
501
  TimeMarker *cur = markers;
 
502
  signed int markcnt = 0;
 
503
  int totalmarks = CountMarkers();
 
504
  
 
505
  if (totalmarks == 0) 
 
506
    return 0; // No solution because there are no markers!
 
507
  else {
 
508
    while (cur != 0 && cur->markofs < curofs) {
 
509
      markcnt++;
 
510
      cur = cur->next;
 
511
    }
 
512
    
 
513
    // Markcnt now indexes the next marker after curofs
 
514
    // Go N before!
 
515
    markcnt -= n;
 
516
    while (markcnt < 0) {
 
517
      // Reverse wrap case
 
518
      markcnt += totalmarks;
 
519
    }
 
520
    
 
521
    // Now get marker indexed by markcnt
 
522
    cur = markers;
 
523
    int markcnt2 = 0;
 
524
    while (cur != 0 && markcnt2 != markcnt) {
 
525
      markcnt2++;
 
526
      cur = cur->next;
 
527
    }
 
528
    
 
529
    // & return it
 
530
    return cur;
 
531
  }
 
532
};
 
533
 
 
534
// Create a new extra channel
 
535
BED_ExtraChannel::BED_ExtraChannel(nframes_t len) {
 
536
  if (len > 0) {
 
537
    //printf("allocating origbuf..\n");
 
538
    origbuf = buf = new sample_t[len];
 
539
    //printf("done: origbuf %p: buf %p!..\n",origbuf,buf);
 
540
  }
 
541
  else
 
542
    origbuf = buf = 0;
 
543
};
 
544
 
 
545
BED_ExtraChannel::~BED_ExtraChannel() {
 
546
  if (origbuf != 0) {
 
547
    //printf("deleting origbuf %p: buf %p!..\n",origbuf,buf);
 
548
    delete[] origbuf;
 
549
    //printf("done!\n");
 
550
  }
 
551
};
 
552
 
 
553
// Create a new audioblock as the beginning of a block list
 
554
AudioBlock::AudioBlock(nframes_t len) : len(len), next(0),
 
555
                                        first(this), xt(0)
 
556
{
 
557
  if (len > 0)
 
558
    origbuf = buf = new sample_t[len];
 
559
}
 
560
 
 
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) {
 
564
  prev->next = this;
 
565
  if (len > 0)
 
566
    origbuf = buf = new sample_t[len];
 
567
}
 
568
 
 
569
AudioBlock::~AudioBlock() {
 
570
  //printf("~AudioBlock len: %d dsz: %d\n",len,sizeof(*buf));
 
571
  if (origbuf != 0)
 
572
    delete[] origbuf;
 
573
}
 
574
 
 
575
// Clears this block chain- not changing length
 
576
void AudioBlock::Zero() {
 
577
  AudioBlock *cur = first;
 
578
  while (cur != 0) {
 
579
    memset(cur->buf,0,sizeof(sample_t)*cur->len);
 
580
    cur = cur->next;
 
581
  }
 
582
};
 
583
 
 
584
// Link us up to the specified block
 
585
void AudioBlock::Link(AudioBlock *to) {
 
586
  to->first = first;
 
587
  to->next = 0;
 
588
  next = to;
 
589
}
 
590
 
 
591
// RT safe
 
592
void AudioBlock::ChopChain() {
 
593
  // Chop off the chain at this block
 
594
  // Freeing unused blocks
 
595
  AudioBlock *cur = next;
 
596
  next = 0;
 
597
  while (cur != 0) {
 
598
    AudioBlock *tmp = cur->next;
 
599
    if (cur->xt != 0)
 
600
      printf("BLOCK: WARNING: XT data not freed in ChopChain! "
 
601
             "Possible leak.\n");
 
602
 
 
603
    cur->RTDelete();
 
604
    cur = tmp;
 
605
  }
 
606
}
 
607
 
 
608
void AudioBlock::SmoothEnd() {
 
609
  // Smooth the end of this chain into the beginning for looping
 
610
  AudioBlock *smoothblk;
 
611
  nframes_t smoothofs,
 
612
    smoothcnt,
 
613
    totallen = GetTotalLen();
 
614
  if (totallen >= AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN)
 
615
    smoothcnt = totallen - AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
 
616
  else
 
617
    return; // Very short chain, can't smooth it
 
618
 
 
619
  // Get block & offset for start of smooth
 
620
  SetPtrsFromAbsOffset(&smoothblk, &smoothofs, smoothcnt);
 
621
  if (smoothblk == 0) {
 
622
    // Shouldn't happen
 
623
    printf("AudioBlock: ERROR: Block position mismatch in SmoothEnd\n");
 
624
    exit(1);
 
625
  }
 
626
 
 
627
  AudioBlock *startblk = first;
 
628
  nframes_t startofs = 0;
 
629
 
 
630
  // Second channel?
 
631
  BED_ExtraChannel *rightstartblk = 
 
632
    (BED_ExtraChannel *) startblk->GetExtendedData(T_BED_ExtraChannel),
 
633
    *rightsmoothblk = (BED_ExtraChannel *)
 
634
    smoothblk->GetExtendedData(T_BED_ExtraChannel);
 
635
  char stereo = 0;
 
636
  if (rightstartblk != 0 && rightsmoothblk != 0)
 
637
    stereo = 1; 
 
638
    
 
639
  float mix = 0.0,
 
640
    dmix = 1./(float)AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
 
641
  for (nframes_t i = 0; i < AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN; i++, 
 
642
         mix += dmix) {
 
643
    smoothblk->buf[smoothofs] = mix*startblk->buf[startofs] + 
 
644
      (1.0-mix)*smoothblk->buf[smoothofs];
 
645
    if (stereo)
 
646
      rightsmoothblk->buf[smoothofs] = mix*rightstartblk->buf[startofs] + 
 
647
        (1.0-mix)*rightsmoothblk->buf[smoothofs];
 
648
      
 
649
    smoothofs++;
 
650
    startofs++;
 
651
    if (smoothofs >= smoothblk->len) {
 
652
      smoothblk = smoothblk->next;
 
653
      smoothofs = 0;
 
654
      if (smoothblk == 0) {
 
655
        if (i+1 < AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN) {
 
656
          // Shouldn't happen
 
657
          printf("AudioBlock: ERROR: (smoothblk) Block size mismatch in "
 
658
                 "SmoothEnd: i: %d\n", i);
 
659
          exit(1);
 
660
        }
 
661
        
 
662
        rightsmoothblk = 0;
 
663
      } else {
 
664
        rightsmoothblk = (BED_ExtraChannel *)
 
665
          smoothblk->GetExtendedData(T_BED_ExtraChannel);
 
666
        if (stereo && rightsmoothblk == 0) {
 
667
          // Shouldn't happen
 
668
          printf("AudioBlock: ERROR: (smoothblk) Right channel "
 
669
                 "disappeared!\n");
 
670
          exit(1);
 
671
        }
 
672
      }
 
673
    }
 
674
    if (startofs >= startblk->len) {
 
675
      startblk = startblk->next;
 
676
      startofs = 0;
 
677
      if (startblk == 0) {
 
678
        if (i+1 < AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN) {
 
679
          // Shouldn't happen
 
680
          printf("AudioBlock: ERROR: (startblk) Block size mismatch in "
 
681
                 "SmoothEnd\n");
 
682
          exit(1);
 
683
        }
 
684
        
 
685
        rightstartblk = 0;
 
686
      } else {
 
687
        rightstartblk = (BED_ExtraChannel *)
 
688
          startblk->GetExtendedData(T_BED_ExtraChannel);
 
689
        if (stereo && rightstartblk == 0) {
 
690
          // Shouldn't happen
 
691
          printf("AudioBlock: ERROR: (startblk) Right channel disappeared!\n");
 
692
          exit(1);
 
693
        }
 
694
      }
 
695
    }
 
696
  }
 
697
 
 
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");
 
702
  } else {
 
703
    first->buf += AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
 
704
    first->len -= AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
 
705
 
 
706
    BED_ExtraChannel *rightfirst = 
 
707
      (BED_ExtraChannel *) first->GetExtendedData(T_BED_ExtraChannel);
 
708
    if (rightfirst != 0) 
 
709
      rightfirst->buf += AUDIOBLOCK_SMOOTH_ENDPOINTS_LEN;
 
710
  }
 
711
 
 
712
  //printf("endsmooth: startofs: %d smoothofs: %d len: %d\n",
 
713
  //     startofs, smoothofs, totallen);
 
714
}
 
715
 
 
716
// not RT safe
 
717
void AudioBlock::DeleteChain() {
 
718
  AudioBlock *cur = first;
 
719
  while (cur != 0) {
 
720
    // First erase any extended data
 
721
    BlockExtendedData *curxt = cur->xt;
 
722
    while (curxt != 0) {
 
723
      BlockExtendedData *tmpxt = curxt->next;
 
724
      delete curxt;
 
725
      curxt = tmpxt;
 
726
    }
 
727
 
 
728
    // Then the block itself!
 
729
    AudioBlock *tmp = cur->next;
 
730
    cur->RTDelete();
 
731
    cur = tmp;
 
732
  }
 
733
}
 
734
 
 
735
// Returns the total length of this audio chain
 
736
nframes_t AudioBlock::GetTotalLen() {
 
737
  nframes_t tally = 0;
 
738
  AudioBlock *cur = first;
 
739
  while (cur != 0) {
 
740
    tally += cur->len;
 
741
    cur = cur->next;
 
742
  }
 
743
  
 
744
  return tally;
 
745
};
 
746
 
 
747
// Gets extended data for this block
 
748
BlockExtendedData *AudioBlock::GetExtendedData(BlockExtendedDataType x) { 
 
749
  BlockExtendedData *cur = xt;
 
750
  while (cur!=0 && cur->GetType()!=x)
 
751
    cur = cur->next;
 
752
  return cur;
 
753
};
 
754
 
 
755
// Add this extended data to the list of extended data for this block
 
756
void AudioBlock::AddExtendedData(BlockExtendedData *nw) {
 
757
  nw->next = xt;
 
758
  xt = nw;
 
759
};
 
760
 
 
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, 
 
764
                                      nframes_t absofs) {
 
765
  AudioBlock *cur = first,
 
766
    *prev = 0;
 
767
  nframes_t curofs = 0,
 
768
    prevofs = 0;
 
769
  while (cur != 0 && curofs <= absofs) {
 
770
    prevofs = curofs;
 
771
    curofs += cur->len;
 
772
    prev = cur;
 
773
    cur = cur->next;
 
774
  }  
 
775
  
 
776
  if (curofs < absofs || prev == 0) {
 
777
    // We're at the end and we still haven't traversed far enough!
 
778
    // Return err
 
779
    *ptr = 0;
 
780
    return;
 
781
  }
 
782
  
 
783
  *ptr = prev;
 
784
  *blkofs = absofs-prevofs;
 
785
};
 
786
 
 
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
 
795
// Realtime safe?
 
796
AudioBlock *AudioBlock::GenerateSubChain(nframes_t fromofs, nframes_t toofs,
 
797
                                         char copystereo) {
 
798
  if (toofs == fromofs)
 
799
    return 0;
 
800
  // Handle wrap case
 
801
  if (toofs < fromofs)
 
802
    toofs += GetTotalLen();
 
803
 
 
804
  // Stereo?
 
805
  BED_ExtraChannel *rightfirst = (BED_ExtraChannel *)
 
806
    first->GetExtendedData(T_BED_ExtraChannel);
 
807
  char stereo = (copystereo && rightfirst != 0);
 
808
    
 
809
  // Get enough new blocks to fit the subblock size
 
810
  nframes_t sublen = toofs - fromofs,
 
811
    suballoc = 0;
 
812
  AudioBlock *subfirst = 0,
 
813
    *subcur = 0;
 
814
  while (suballoc < sublen) {
 
815
    if (subfirst == 0) {
 
816
      subcur = subfirst = (AudioBlock *)RTNew();
 
817
      if (subfirst == 0) {
 
818
        printf("Err: GenerateSubChain- No new blocks available\n");
 
819
        return 0;
 
820
      }
 
821
    }
 
822
    else {
 
823
      AudioBlock *tmp = (AudioBlock *)RTNew();
 
824
      if (tmp == 0) {
 
825
        printf("Err: GenerateSubChain- No new blocks available\n");
 
826
        return 0;
 
827
      }
 
828
      subcur->Link(tmp);
 
829
      subcur = subcur->next;
 
830
    }
 
831
 
 
832
    if (stereo) {
 
833
      BED_ExtraChannel *rightsub = (BED_ExtraChannel*)rightfirst->RTNew(); 
 
834
      if (rightsub == 0) {
 
835
        printf("Err: GenerateSubChain- No new right blocks available\n");
 
836
        return 0;
 
837
      }
 
838
      subcur->AddExtendedData(rightsub);
 
839
    }
 
840
 
 
841
    suballoc += subcur->len;
 
842
  }
 
843
    
 
844
  // Find starting pos in chain
 
845
  AudioBlock *cur;
 
846
  nframes_t curofs;
 
847
  SetPtrsFromAbsOffset(&cur,&curofs,fromofs);
 
848
 
 
849
  subcur = subfirst;
 
850
  nframes_t subofs = 0,
 
851
    remaining = sublen; 
 
852
 
 
853
  // Extra channel
 
854
  BED_ExtraChannel *subright = 
 
855
    (stereo ? (BED_ExtraChannel *) subcur->GetExtendedData(T_BED_ExtraChannel)
 
856
     : 0),
 
857
    *right = 
 
858
    (stereo ? (BED_ExtraChannel *) cur->GetExtendedData(T_BED_ExtraChannel)
 
859
     : 0);
 
860
 
 
861
  do {
 
862
    nframes_t n = MIN(cur->len-curofs,remaining);
 
863
    n = MIN(n,subcur->len-subofs);
 
864
 
 
865
    memcpy(&subcur->buf[subofs],&cur->buf[curofs],n*sizeof(sample_t));
 
866
    if (stereo)
 
867
      memcpy(&subright->buf[subofs],&right->buf[curofs],n*sizeof(sample_t));
 
868
      
 
869
    subofs += n;
 
870
    curofs += n;
 
871
    remaining -= n;
 
872
    if (curofs >= cur->len) {
 
873
      cur = cur->next;
 
874
      curofs = 0;
 
875
      if (cur == 0)
 
876
        // Past the end of the block chain-- wrap around to first
 
877
        cur = first;
 
878
 
 
879
      if (stereo)
 
880
        right = (BED_ExtraChannel *) cur->GetExtendedData(T_BED_ExtraChannel);
 
881
    }
 
882
 
 
883
    if (subofs >= subcur->len) {
 
884
      subcur = subcur->next;
 
885
      subofs = 0;
 
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");
 
890
        exit(1);
 
891
      }
 
892
 
 
893
      if (stereo)
 
894
        subright = (BED_ExtraChannel *) 
 
895
          subcur->GetExtendedData(T_BED_ExtraChannel);
 
896
    }
 
897
  } while (remaining);
 
898
 
 
899
  // Truncate the last presized subblock to the right length
 
900
  subcur->len = subofs;
 
901
 
 
902
  // And return the last block in the chain
 
903
  return subcur;
 
904
};
 
905
 
 
906
// *** To be tested! ***
 
907
//
 
908
// Removes the last 'hacklen' samples from this block chain
 
909
// Returns nonzero on error!
 
910
// Realtime safe?
 
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);
 
915
  AudioBlock *hackblk;
 
916
  nframes_t hackofs;
 
917
  if (chainlen <= hacklen)
 
918
    return 1;
 
919
  SetPtrsFromAbsOffset(&hackblk,&hackofs,chainlen-hacklen);
 
920
  
 
921
  // Now hackblk[hackofs] should be the first sample to erase at the
 
922
  // end of the chain
 
923
  hackblk->len = hackofs; // Truncate length of block
 
924
  // Note: Block memory isnt resized, so extra memory lingers until
 
925
  // the block is erased
 
926
  
 
927
  AudioBlock *tmp = hackblk->next;
 
928
  hackblk->next = 0; // End of chain at hack position
 
929
  
 
930
  // Erase remaining blocks in chain
 
931
  hackblk = tmp; 
 
932
  while (hackblk != 0) {
 
933
    tmp = hackblk->next;
 
934
    hackblk->RTDelete();
 
935
    hackblk = tmp;
 
936
  }
 
937
 
 
938
  // **** To be implemented
 
939
  // **** Hack stereo samples
 
940
 
 
941
  //printf("Hack (e): %ld\n",GetTotalLen());
 
942
  return 0;
 
943
};
 
944
 
 
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)
 
950
    nw = nw->next;
 
951
 
 
952
  // Link new block to the beginning of our chain
 
953
  nw->next = first;
 
954
  
 
955
  // Link all first pointers to first block in new chain
 
956
  AudioBlock *cur = first;
 
957
  while (cur != 0) {
 
958
    cur->first = nw->first;
 
959
    cur = cur->next;
 
960
  }
 
961
  
 
962
  return nw->first;
 
963
};
 
964
 
 
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];
 
973
}
 
974
 
 
975
AudioBlockIterator::~AudioBlockIterator() { 
 
976
  delete[] fragment[0];
 
977
  delete[] fragment[1];
 
978
};
 
979
 
 
980
// Stores in cnt the absolute count corresponding to the given
 
981
// block and offset
 
982
void AudioBlockIterator::GenCnt(AudioBlock *blk, nframes_t blkofs, 
 
983
                                nframes_t *cnt) {
 
984
  AudioBlock *cur = curblock->first;
 
985
  nframes_t curofs = 0;
 
986
  while (cur != 0 && cur != blk) {
 
987
    // Add the length of this whole block
 
988
    curofs += cur->len;
 
989
    cur = cur->next;
 
990
  }
 
991
  
 
992
  if (cur == 0) {
 
993
    // Given block not found!
 
994
    *cnt = 0;
 
995
  }
 
996
  else {
 
997
    // We are now on the given block- add only current block offset
 
998
    curofs += blkofs;
 
999
    *cnt = curofs;
 
1000
  }
 
1001
}
 
1002
 
 
1003
void AudioBlockIterator::Jump(nframes_t ofs) {
 
1004
  // Quantize the specified offset to within the limits of the blockchain
 
1005
  ofs = ofs % curblock->GetTotalLen();
 
1006
 
 
1007
  curblock->SetPtrsFromAbsOffset(&curblock,&curblkofs,ofs);
 
1008
  if (curblock == 0) {
 
1009
    printf("Err: AudioBlockIterator::Jump- Pointer/size mismatch\n");
 
1010
    exit(1);
 
1011
  }
 
1012
  currightblock = 0;
 
1013
  nextrightblock = 0;
 
1014
  nextblock = 0;
 
1015
  nextblkofs = 0;
 
1016
  curcnt = ofs;
 
1017
  nextcnt = 0;
 
1018
}
 
1019
 
 
1020
void AudioBlockIterator::GenConstants() {
 
1021
  // Need to recompute curcnt to account for extra blocks?
 
1022
  GenCnt(curblock,curblkofs,&curcnt);
 
1023
  GenCnt(nextblock,nextblkofs,&nextcnt);
 
1024
}
 
1025
 
 
1026
// Moves iterator to start position
 
1027
void AudioBlockIterator::Zero() {
 
1028
  currightblock = 0;
 
1029
  nextrightblock = 0;
 
1030
  curblock = curblock->first;     
 
1031
  curblkofs = 0; 
 
1032
  curcnt = 0;
 
1033
  nextblock = 0;
 
1034
}
 
1035
 
 
1036
// Advances to the next fragment
 
1037
void AudioBlockIterator::NextFragment() {
 
1038
  // Only advance if not stopped
 
1039
  if (!stopped) {
 
1040
    // We must first get a fragment before advancing
 
1041
    if (nextblock == 0)
 
1042
      GetFragment(0,0);
 
1043
    
 
1044
    currightblock = nextrightblock;
 
1045
    nextrightblock = 0;
 
1046
    curblock = nextblock;
 
1047
    curblkofs = nextblkofs;
 
1048
    curcnt = nextcnt;
 
1049
    
 
1050
    nextblock = 0;
 
1051
  }
 
1052
}
 
1053
 
 
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, 
 
1058
                                     char wait_alloc) {
 
1059
  nframes_t fragofs = 0;
 
1060
  nframes_t n = (size_override == 0 ? fragmentsize : size_override);
 
1061
  int wrap = 0;
 
1062
  
 
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,
 
1068
    lclcnt = curcnt;
 
1069
 
 
1070
  nframes_t nextbit;
 
1071
  do {
 
1072
    nextbit = MIN((nframes_t) n, lclblock->len - lclblkofs);
 
1073
 
 
1074
    // Copy back into our block
 
1075
 
 
1076
    // Left
 
1077
    memcpy(&lclblock->buf[lclblkofs],
 
1078
           &frag_l[fragofs],
 
1079
           sizeof(sample_t)*nextbit);
 
1080
 
 
1081
    // If right channel is given and we don't know the right block, find it
 
1082
    if (frag_r != 0) {
 
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");
 
1092
            return 0;
 
1093
          } else {
 
1094
            do {
 
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
 
1099
              }
 
1100
            } while (lclrightblock == 0 && wait_alloc);
 
1101
            if (lclrightblock != 0)
 
1102
              lclblock->AddExtendedData(lclrightblock);
 
1103
            else {
 
1104
              printf("BLOCK: ERROR: RTNew() failed for BED_ExtraChannel.\n");
 
1105
              return 0;
 
1106
            }
 
1107
          }
 
1108
        }
 
1109
      }
 
1110
      
 
1111
      // Right
 
1112
      memcpy(&lclrightblock->buf[lclblkofs],
 
1113
             &frag_r[fragofs],
 
1114
             sizeof(sample_t)*nextbit);
 
1115
    }
 
1116
    
 
1117
    fragofs += nextbit;
 
1118
    lclblkofs += nextbit;
 
1119
    lclcnt += nextbit;
 
1120
    n -= nextbit;
 
1121
    
 
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
 
1125
      
 
1126
      wrap = 1;
 
1127
      if (lclblock->next == 0) {
 
1128
        // END OF AUDIOBLOCK LIST, LOOP TO BEGINNING
 
1129
        lclblock = lclblock->first;
 
1130
        lclblkofs = 0;
 
1131
        lclcnt = lclblkofs;
 
1132
        lclrightblock = 0;
 
1133
      }
 
1134
      else {
 
1135
        lclblock = lclblock->next;
 
1136
        lclblkofs = 0; 
 
1137
        lclrightblock = 0;
 
1138
      }
 
1139
    }
 
1140
  } while (n);
 
1141
  
 
1142
  nextblock = lclblock,
 
1143
    nextrightblock = lclrightblock,
 
1144
    nextblkofs = lclblkofs,
 
1145
    nextcnt = lclcnt;
 
1146
  
 
1147
  return wrap;
 
1148
}
 
1149
 
 
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;
 
1156
  
 
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,
 
1162
    lclcnt = curcnt;
 
1163
  
 
1164
  nframes_t nextbit;
 
1165
  do {
 
1166
    nextbit = MIN((nframes_t) n, lclblock->len - lclblkofs);
 
1167
      
 
1168
    if (nextbit) {
 
1169
      // Left
 
1170
      memcpy(&fragment[0][fragofs],
 
1171
             &lclblock->buf[lclblkofs],
 
1172
             sizeof(sample_t)*nextbit);
 
1173
 
 
1174
      // If right channel is given and we don't know the right block, find it
 
1175
      if (frag_r != 0) {
 
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 "
 
1182
                   "exists!\n");
 
1183
            return;
 
1184
          }
 
1185
        }
 
1186
        
 
1187
        // Right
 
1188
        memcpy(&fragment[1][fragofs],
 
1189
               &lclrightblock->buf[lclblkofs],
 
1190
               sizeof(sample_t)*nextbit);
 
1191
      } else
 
1192
        // Make -sure- we don't jump blocks and keep old rightblock
 
1193
        lclrightblock = 0;
 
1194
 
 
1195
      fragofs += nextbit;
 
1196
      lclblkofs += nextbit;
 
1197
      lclcnt += nextbit;
 
1198
      n -= nextbit;
 
1199
    }
 
1200
      
 
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;
 
1207
        lclblkofs = 0;
 
1208
        lclcnt = lclblkofs;
 
1209
        lclrightblock = 0;
 
1210
      } else {
 
1211
        lclblock = lclblock->next;
 
1212
        lclblkofs = 0; // Beginning of next block
 
1213
        lclrightblock = 0;
 
1214
      }
 
1215
    }
 
1216
  } while (n);
 
1217
  
 
1218
  nextblock = lclblock,
 
1219
    nextrightblock = lclrightblock,
 
1220
    nextblkofs = lclblkofs,
 
1221
    nextcnt = lclcnt;
 
1222
 
 
1223
  // Return fragment buffers
 
1224
  if (frag_l != 0)
 
1225
    *frag_l = fragment[0];
 
1226
  if (frag_r != 0) 
 
1227
    *frag_r = fragment[1];
 
1228
};
 
1229
 
 
1230
// RT safe
 
1231
void AudioBlockIterator::EndChain() {
 
1232
  // Mark iterator stopped
 
1233
  stopped = 1;
 
1234
  
 
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;
 
1239
  }
 
1240
  else
 
1241
    curblock->len = curblkofs;    
 
1242
  
 
1243
  // Stop the chain at this place
 
1244
  curblock->ChopChain();
 
1245
}
 
1246
 
 
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();
 
1254
      if (nw == 0) {
 
1255
        printf("GrowChainManager: ERROR: No free blocks to grow chain\n");
 
1256
        return 0;
 
1257
      }
 
1258
      i->GetCurBlock()->Link(nw);
 
1259
 
 
1260
      // Second channel allocating is done as needed by PutFragment
 
1261
      // in the iterator
 
1262
    }
 
1263
 
 
1264
  return 0;
 
1265
};
 
1266
 
 
1267
void PeaksAvgsManager::Setup() {
 
1268
  // Setup iterators
 
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();
 
1276
 
 
1277
  if (grow) {
 
1278
    // Grow peaks & avgs blocks
 
1279
    bmg->GrowChainOn(pa->peaks,peaksi);
 
1280
    bmg->GrowChainOn(pa->avgs,avgsi);
 
1281
  }
 
1282
};
 
1283
 
 
1284
PeaksAvgsManager::~PeaksAvgsManager() {
 
1285
  if (bmg != 0) {
 
1286
    End();
 
1287
 
 
1288
    delete peaksi;
 
1289
    delete avgsi;
 
1290
    delete mi;
 
1291
  }
 
1292
};
 
1293
 
 
1294
void PeaksAvgsManager::End() {
 
1295
  if (!ended) {
 
1296
    ended = 1;
 
1297
 
 
1298
    if (grow) {
 
1299
      // End chain at current pos!
 
1300
      peaksi->EndChain();
 
1301
      avgsi->EndChain();
 
1302
 
 
1303
      bmg->GrowChainOff(pa->peaks);
 
1304
      bmg->GrowChainOff(pa->avgs);
 
1305
    }
 
1306
  }
 
1307
}
 
1308
 
 
1309
int PeaksAvgsManager::Manage() {
 
1310
  // Stop if ended..
 
1311
  if (ended)
 
1312
    return 1;
 
1313
 
 
1314
  // Compute running peaks and averages
 
1315
  
 
1316
  char wrap;
 
1317
  do {
 
1318
    wrap = 0;
 
1319
    
 
1320
    // Get current position in iterator 
 
1321
    nframes_t curcnt = i->GetTotalLength2Cur();
 
1322
    
 
1323
    if (curcnt < lastcnt) {
 
1324
      // We have a wrap condition!- loop
 
1325
      // printf("Wrap! Now at: %ld\n",curcnt);
 
1326
      curcnt = b->GetTotalLen();
 
1327
      wrap = 1;
 
1328
    }
 
1329
    
 
1330
    // Update peaks & averages to current position    
 
1331
    while (lastcnt < curcnt) {
 
1332
      sample_t *sptr[2];
 
1333
      sample_t s_l, s_r;
 
1334
      if (stereo) {
 
1335
        mi->GetFragment(&sptr[0],&sptr[1]);     
 
1336
        s_l = *sptr[0];
 
1337
        s_r = *sptr[1];
 
1338
      } else {
 
1339
        mi->GetFragment(&sptr[0],0);    
 
1340
        s_l = *sptr[0];
 
1341
        s_r = 0;
 
1342
      }
 
1343
 
 
1344
      // If chunkcnt is -1, we have temporarily stopped until a wrap
 
1345
      if (go) {
 
1346
        if (s_l > runmax)
 
1347
          runmax = s_l;
 
1348
        if (s_l < runmin)
 
1349
          runmin = s_l;
 
1350
 
 
1351
        if (stereo) {
 
1352
          if (s_r > runmax)
 
1353
            runmax = s_r;
 
1354
          if (s_r < runmin)
 
1355
            runmin = s_r;
 
1356
 
 
1357
          runtally += (fabs(s_l)+fabs(s_r))/2;
 
1358
        }
 
1359
        else
 
1360
          runtally += fabs(s_l);
 
1361
          
 
1362
        chunkcnt++;
 
1363
        
 
1364
        if (chunkcnt >= pa->chunksize) {
 
1365
          // One chunk done
 
1366
          sample_t peak = runmax-runmin,
 
1367
            avg = (sample_t) (runtally/pa->chunksize);
 
1368
          
 
1369
          if (peaksi->PutFragment(&peak,0) || 
 
1370
              avgsi->PutFragment(&avg,0)) {
 
1371
            // Peaks should not be wrapping before main buf, stop!
 
1372
            //
 
1373
            // Note that this does happen!!
 
1374
            go = 0;
 
1375
          }
 
1376
          else {
 
1377
            peaksi->NextFragment();
 
1378
            avgsi->NextFragment();
 
1379
            chunkcnt = 0;
 
1380
          }
 
1381
          
 
1382
          runtally = 0;
 
1383
          runmax = 0;
 
1384
          runmin = 0;
 
1385
        }
 
1386
      }
 
1387
      
 
1388
      mi->NextFragment();
 
1389
      lastcnt++;
 
1390
    }
 
1391
    
 
1392
    if (wrap) {
 
1393
      /* printf("Main wrap!: MI: %ld PI: %ld AI: %ld\n",
 
1394
         mi->GetTotalLength2Cur(),
 
1395
         peaksi->GetTotalLength2Cur(),
 
1396
         avgsi->GetTotalLength2Cur()); */
 
1397
      mi->Zero();
 
1398
      peaksi->Zero();
 
1399
      avgsi->Zero();
 
1400
      lastcnt = 0; // Wrap to beginning, and do the samples there
 
1401
      go = 1;
 
1402
      
 
1403
      chunkcnt = 0;
 
1404
      runtally = 0;
 
1405
      runmax = 0;
 
1406
      runmin = 0;
 
1407
    }
 
1408
  } while (wrap);
 
1409
 
 
1410
  return 0;
 
1411
};
 
1412
 
 
1413
void StripeBlockManager::Setup() {
 
1414
  // Does this block have BED_MarkerPoints?
 
1415
  mp = (BED_MarkerPoints *)(b->GetExtendedData(T_BED_MarkerPoints));
 
1416
  if (mp == 0) {
 
1417
    // No marker block  
 
1418
    b->AddExtendedData(mp = new BED_MarkerPoints());
 
1419
  }
 
1420
};
 
1421
 
 
1422
int StripeBlockManager::Manage() {
 
1423
  // This is called whenever a time marker should be striped
 
1424
  // to the block
 
1425
 
 
1426
  char wrap = 0;
 
1427
  do {
 
1428
    if (wrap)
 
1429
      wrap = 2; // Special case if we just wrapped and are on a 2nd pass
 
1430
    else
 
1431
      wrap = 0;
 
1432
 
 
1433
    // Get current iterated offset into block
 
1434
    nframes_t curcnt = i->GetTotalLength2Cur();
 
1435
 
 
1436
    if (curcnt < lastcnt) {
 
1437
      // We have a wrap condition!- loop
 
1438
      // printf("Wrap! Now at: %ld\n",curcnt);
 
1439
      curcnt = b->GetTotalLen();
 
1440
      wrap = 1;
 
1441
    }
 
1442
 
 
1443
    // Scan through time markers for a good place to insert a new one 
 
1444
    TimeMarker *cur = mp->markers,
 
1445
      *prev = 0;
 
1446
    if (wrap == 2) {
 
1447
      // On 2nd pass, delete markers at 0.
 
1448
      wrap = 0;
 
1449
      while (cur != 0 && cur->markofs < lastcnt) {
 
1450
        prev = cur;
 
1451
        cur = cur->next;
 
1452
      }
 
1453
    } else {
 
1454
      while (cur != 0 && cur->markofs <= lastcnt) {
 
1455
        prev = cur;
 
1456
        cur = cur->next;
 
1457
      }
 
1458
    }
 
1459
 
 
1460
    // Delete any markers between last position & current
 
1461
    while (cur != 0 && cur->markofs <= curcnt) {
 
1462
      TimeMarker *tmp = cur->next;
 
1463
      cur->RTDelete();
 
1464
      
 
1465
      cur = tmp;
 
1466
      if (prev != 0)
 
1467
        prev->next = cur;
 
1468
      else
 
1469
        mp->markers = cur;
 
1470
    } 
 
1471
 
 
1472
    if (!wrap) {
 
1473
      // Now insert a new marker in this position
 
1474
      // Use realtime new method- no problem
 
1475
      TimeMarker *nw = (TimeMarker *) pre_tm->RTNew();
 
1476
      if (nw == 0) {
 
1477
        printf("StripeBlockManager: ERROR: No free TimeMarkers\n");
 
1478
        return 0;
 
1479
      }
 
1480
      nw->markofs = curcnt;
 
1481
      nw->next = cur;
 
1482
      if (prev != 0)
 
1483
        prev->next = nw;
 
1484
      else
 
1485
        mp->markers = nw;
 
1486
      
 
1487
      // Update counters
 
1488
      lastcnt = curcnt;
 
1489
    }
 
1490
    else
 
1491
      lastcnt = 0; // Start again from beginning to curcnt
 
1492
  } while (wrap);
 
1493
 
 
1494
  return 0;
 
1495
};
 
1496
 
 
1497
int DelayProcessorCallManager::Manage() {
 
1498
  // OK, we've been triggered!
 
1499
  //printf("Call processor %ld- %d\n",(long) p, data);
 
1500
 
 
1501
  // Call processor
 
1502
  data = p->ProcessorCall(trigger,data);
 
1503
 
 
1504
  if (data == -1) {
 
1505
    // Now remove this manager
 
1506
    return 1; 
 
1507
  } else {
 
1508
    // Save this manager
 
1509
    return 0;
 
1510
  }
 
1511
};
 
1512
 
 
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));
 
1531
 
 
1532
  // Start a block managing thread
 
1533
  int ret = pthread_create(&manage_thread,
 
1534
                           0,
 
1535
                           run_manage_thread,
 
1536
                           static_cast<void *>(this));
 
1537
  if (ret != 0) {
 
1538
    printf("(blockmanager) pthread_create failed, exiting");
 
1539
    exit(1);
 
1540
  }
 
1541
  
 
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");
 
1549
  }
 
1550
}
 
1551
 
 
1552
BlockManager::~BlockManager () {
 
1553
  // Terminate the management thread
 
1554
  threadgo = 0;
 
1555
  pthread_join(manage_thread,0);
 
1556
 
 
1557
  delete pre_growchain;
 
1558
  delete pre_peaksavgs;
 
1559
  delete pre_hipri;
 
1560
  delete pre_stripeblock;
 
1561
  delete pre_delayprocessorcall;
 
1562
}
 
1563
 
 
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();
 
1573
  nw->b = b;
 
1574
  nw->i = i;
 
1575
  AddManager(&manageblocks,nw);
 
1576
}
 
1577
 
 
1578
void BlockManager::GrowChainOff (AudioBlock *b) {
 
1579
  DelManager(&manageblocks,b,T_MC_GrowChain);
 
1580
}
 
1581
 
 
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,
 
1587
                                           char grow) {
 
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();
 
1592
  nw->bmg = this;
 
1593
  nw->b = b;
 
1594
  nw->i = i;
 
1595
  nw->grow = grow;
 
1596
  nw->Setup();
 
1597
  AddManager(&manageblocks,nw);
 
1598
  
 
1599
  return nw;
 
1600
}
 
1601
 
 
1602
void BlockManager::PeakAvgOff (AudioBlock *b) {
 
1603
  DelManager(&manageblocks,b,T_MC_PeaksAvgs);
 
1604
}
 
1605
 
 
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();
 
1613
  nw->b = b;
 
1614
  nw->i = i;
 
1615
  nw->trigger = trigger;
 
1616
  nw->Setup();
 
1617
  AddManager((ManagedChain**) &himanageblocks,nw);
 
1618
}
 
1619
 
 
1620
void BlockManager::StripeBlockOff (void *trigger, AudioBlock *b) {
 
1621
  DelHiManager(&himanageblocks,b,T_MC_StripeBlock,trigger);
 
1622
}
 
1623
 
 
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,
 
1628
    *prev = 0; 
 
1629
  while (cur != 0) {
 
1630
    if (cur->GetType() == T_MC_DelayProcessorCall &&
 
1631
        (cur->trigger == 0 || cur->trigger == trigger) &&
 
1632
        ((DelayProcessorCallManager *) cur)->p == p) {
 
1633
      // Remove chain
 
1634
      HiPriManagedChain *tmp = (HiPriManagedChain *) cur->next;
 
1635
      if (prev != 0) 
 
1636
        prev->next = tmp;
 
1637
      else 
 
1638
        himanageblocks = tmp;
 
1639
      cur->RTDelete();
 
1640
      
 
1641
      // Next chain
 
1642
      cur = himanageblocks; // Start again!
 
1643
    } else {
 
1644
      // Next chain
 
1645
      prev = cur;
 
1646
      cur = (HiPriManagedChain *) cur->next;
 
1647
    }
 
1648
  }
 
1649
};
 
1650
 
 
1651
void BlockManager::AddDelayProcessorCall (void *trigger, Processor *p, 
 
1652
                                          int data) {
 
1653
  DelayProcessorCallManager *nw = (DelayProcessorCallManager *)
 
1654
    pre_delayprocessorcall->RTNew();
 
1655
  nw->trigger = trigger;
 
1656
  nw->p = p;
 
1657
  nw->data = data;
 
1658
  AddManager((ManagedChain **) &himanageblocks,nw);
 
1659
};
 
1660
 
 
1661
void BlockManager::DelDelayProcessorCall (DelayProcessorCallManager *m) {
 
1662
  DelManager((ManagedChain **) &himanageblocks,m);
 
1663
};
 
1664
 
 
1665
// Generic delete/add functions for managers (not hipri)
 
1666
void BlockManager::DelManager (ManagedChain *m) {
 
1667
  DelManager(&manageblocks,m);
 
1668
};
 
1669
void BlockManager::AddManager (ManagedChain *nw) {
 
1670
  AddManager(&manageblocks,nw);
 
1671
};
 
1672
 
 
1673
void BlockManager::DelManager (ManagedChain **first, ManagedChain *m) {
 
1674
  ManagedChain *cur = *first,
 
1675
    *prev = 0;
 
1676
  
 
1677
  // Search for manager 'm' in our list
 
1678
  while (cur != 0 && cur != m) {
 
1679
    prev = cur;
 
1680
    cur = cur->next;
 
1681
  }
 
1682
  
 
1683
  if (cur != 0) {
 
1684
    // Got it, unlink!
 
1685
    if (prev != 0) 
 
1686
      prev->next = cur->next;
 
1687
    else 
 
1688
      *first = cur->next;
 
1689
    cur->RTDelete();
 
1690
  }
 
1691
};
 
1692
 
 
1693
void BlockManager::RefDeleted (ManagedChain **first, void *ref) {
 
1694
  ManagedChain *cur = *first,
 
1695
    *prev = 0; 
 
1696
  while (cur != 0) {
 
1697
    if (cur->RefDeleted(ref)) {
 
1698
      //printf("RefDeleted delete loose reference!\n");
 
1699
 
 
1700
      // Remove chain
 
1701
      ManagedChain *tmp = cur->next;
 
1702
      if (prev != 0) 
 
1703
        prev->next = tmp;
 
1704
      else 
 
1705
        *first = tmp;
 
1706
      cur->RTDelete();
 
1707
      
 
1708
      // Next chain
 
1709
      cur = *first; // Start again!
 
1710
    } else {
 
1711
      // Next chain
 
1712
      prev = cur;
 
1713
      cur = cur->next;
 
1714
    }
 
1715
  }
 
1716
}
 
1717
 
 
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);
 
1723
}
 
1724
 
 
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,
 
1730
    *prev = 0;
 
1731
  
 
1732
  // Count the managers- this is necessary
 
1733
  // Because new managers can be added during the Trigger process
 
1734
  // causing infinite loops
 
1735
  long mgrcnt = 0;
 
1736
  while (cur != 0) {
 
1737
    mgrcnt++;
 
1738
    cur = (HiPriManagedChain *) cur->next;
 
1739
  }
 
1740
  
 
1741
  //printf("HIPRITRIG: %ld\n", mgrcnt);
 
1742
  
 
1743
  cur = himanageblocks;
 
1744
  long curcnt = 0;
 
1745
  while (curcnt < mgrcnt && cur != 0) {
 
1746
    char advance = 1;
 
1747
    
 
1748
    if (cur->trigger == trigger || cur->trigger == 0)
 
1749
      // Ok, right trigger or no trigger specified, call 'em!
 
1750
      if (cur->Manage()) {
 
1751
        // Remove chain
 
1752
        HiPriManagedChain *tmp = (HiPriManagedChain *) cur->next;
 
1753
        if (prev != 0) 
 
1754
          prev->next = tmp;
 
1755
        else 
 
1756
          himanageblocks = tmp;
 
1757
        cur->RTDelete();
 
1758
        
 
1759
        // Next chain
 
1760
        cur = tmp;
 
1761
        curcnt++;
 
1762
        
 
1763
        advance = 0;
 
1764
      }
 
1765
    
 
1766
    if (advance) {
 
1767
      // Next chain
 
1768
      prev = cur;
 
1769
      cur = (HiPriManagedChain *) cur->next;
 
1770
      curcnt++;
 
1771
    }
 
1772
  }
 
1773
}
 
1774
 
 
1775
// Returns the 1st chain manager associated with block b
 
1776
// that has type t
 
1777
ManagedChain *BlockManager::GetBlockManager(AudioBlock *o, 
 
1778
                                            ManagedChainType t) {
 
1779
  ManagedChain *cur = manageblocks;
 
1780
  
 
1781
  // Search for block 'o' && type t in our list
 
1782
  while (cur != 0 && (cur->b != o || cur->GetType() != t))
 
1783
    cur = cur->next;
 
1784
  
 
1785
  return cur;
 
1786
};
 
1787
 
 
1788
void BlockManager::AddManager (ManagedChain **first, ManagedChain *nw) {
 
1789
  ManagedChain *cur = *first;
 
1790
  if (cur == 0)
 
1791
    *first = nw; // That was easy, now we have 1 item
 
1792
  else {
 
1793
    while (cur->next != 0)
 
1794
      cur = cur->next;
 
1795
    cur->next = nw; // Link up the last item to new1
 
1796
  }
 
1797
}
 
1798
 
 
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' 
 
1801
// of any type
 
1802
void BlockManager::DelManager (ManagedChain **first, AudioBlock *o,
 
1803
                               ManagedChainType t) {
 
1804
  ManagedChain *cur = *first,
 
1805
    *prev = 0;
 
1806
  
 
1807
  // Search for block 'o' in our list of type 't'
 
1808
  while (cur != 0 && (cur->b != o || (cur->GetType() != t &&
 
1809
                                      t != T_MC_None))) {
 
1810
    prev = cur;
 
1811
    cur = cur->next;
 
1812
  }
 
1813
  
 
1814
  if (cur != 0) {
 
1815
    // Got it, unlink!
 
1816
    if (prev != 0) 
 
1817
      prev->next = cur->next;
 
1818
    else 
 
1819
      *first = cur->next;
 
1820
    cur->RTDelete();
 
1821
  }
 
1822
}
 
1823
 
 
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, 
 
1829
                                 AudioBlock *o,
 
1830
                                 ManagedChainType t, void *trigger) {
 
1831
  HiPriManagedChain *cur = *first,
 
1832
    *prev = 0;
 
1833
  
 
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))) {
 
1837
    prev = cur;
 
1838
    cur = (HiPriManagedChain *) cur->next;
 
1839
  }
 
1840
  
 
1841
  if (cur != 0) {
 
1842
    // Got it, unlink!
 
1843
    if (prev != 0) 
 
1844
      prev->next = cur->next;
 
1845
    else 
 
1846
      *first = (HiPriManagedChain *) cur->next;
 
1847
    cur->RTDelete();
 
1848
  }
 
1849
}
 
1850
 
 
1851
void *BlockManager::run_manage_thread (void *ptr) {
 
1852
  BlockManager *inst = static_cast<BlockManager *>(ptr);
 
1853
  
 
1854
  while (inst->threadgo) {
 
1855
    // Manage the blocks we have
 
1856
    ManagedChain *cur = inst->manageblocks,
 
1857
      *prev = 0;
 
1858
    while (cur != 0) {
 
1859
      if (cur->Manage()) {
 
1860
        // Remove chain
 
1861
        ManagedChain *tmp = cur->next;
 
1862
        if (prev != 0) 
 
1863
          prev->next = tmp;
 
1864
        else 
 
1865
          inst->manageblocks = tmp;
 
1866
        //printf("end mgr\n");
 
1867
        cur->RTDelete();
 
1868
        
 
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;
 
1873
      }
 
1874
      else {
 
1875
        // Next chain
 
1876
        prev = cur;
 
1877
        cur = cur->next;
 
1878
      }
 
1879
    }
 
1880
 
 
1881
    // Produce status report?
 
1882
    FloConfig *fs = inst->app->getCFG();
 
1883
    if (fs->status_report == FS_REPORT_BLOCKMANAGER) {
 
1884
      fs->status_report++;
 
1885
 
 
1886
      printf("BLOCKMANAGER REPORT:\n");
 
1887
      ManagedChain *cur = inst->manageblocks;
 
1888
      while (cur != 0) {
 
1889
        printf(" bmg mgr: type(%d)\n",cur->GetType());
 
1890
        cur = cur->next;
 
1891
      }
 
1892
 
 
1893
      cur = inst->himanageblocks;
 
1894
      while (cur != 0) {
 
1895
        printf(" bmg HiPrimgr: type(%d)\n",cur->GetType());
 
1896
        cur = cur->next;
 
1897
      }
 
1898
    }
 
1899
 
 
1900
    // 10 ms delay between management tasks
 
1901
    usleep(10000);
 
1902
  }
 
1903
 
 
1904
  // Delete all blockmanagers now
 
1905
  ManagedChain *cur = inst->manageblocks;
 
1906
  while (cur != 0) {
 
1907
    ManagedChain *tmp = cur->next;
 
1908
    cur->RTDelete();
 
1909
    cur = tmp;
 
1910
  }
 
1911
  cur = inst->himanageblocks;
 
1912
  while (cur != 0) {
 
1913
    ManagedChain *tmp = cur->next;
 
1914
    cur->RTDelete();
 
1915
    cur = tmp;
 
1916
  }
 
1917
 
 
1918
  return 0;
 
1919
}