aboutsummaryrefslogtreecommitdiff
path: root/src/lib/hd24song.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/hd24song.cpp')
-rwxr-xr-xsrc/lib/hd24song.cpp2188
1 files changed, 2188 insertions, 0 deletions
diff --git a/src/lib/hd24song.cpp b/src/lib/hd24song.cpp
new file mode 100755
index 0000000..ac1db77
--- /dev/null
+++ b/src/lib/hd24song.cpp
@@ -0,0 +1,2188 @@
1#include <config.h>
2#include "hd24fs.h"
3#include "convertlib.h"
4#include "memutils.h"
5#define FRAMESPERSEC 30 /* 30 or 100; 30=default for HD24 (=SMPTE rate) */
6#define SONGDEBUG 0
7#if (SONGDEBUG==1)
8#define MEMLEAKMULT 10000
9#else
10#define MEMLEAKMULT 1
11#endif
12#define CACHEBUFFERS 30 /* enough for 25 locate points+some lookahead */
13#define NOTHINGTOQUEUE 0xFFFFFFFF
14#define CACHEBLOCK_UNUSED 0xFFFFFFFF /* a song can never have this number of blocks
15 because this is the max no. of samples in a song
16 and a block consists of multiple samples */
17#define SONGINFO_AUDIOBLOCKS 0x00
18#define SONGINFO_SECSAMPLESWITCH 0x8 /* *512=samples before switch to next track */
19#define SONGINFO_SECBYTESWITCH 0xC /* *512=bytes before switch to next track */
20#define SONGINFO_SONGNAME_8 0x28
21#define SONGINFO_CHANNELS 0x31
22#define SONGINFO_SAMPLERATE 0x34
23#define SONGINFO_BITDEPTH 0x37
24#define SONGINFO_SONGLENGTH_IN_SAMPLES 0x38
25#define SONGINFO_WRITEPROTECTED 0x3c
26#define SONGINFO_LOCATEPOINTLIST 0xb8
27#define LOCATEENTRY_LENGTH 12
28#define SONGINFO_SONGNAME 0x3b8
29#define SONGINFO_ALLOCATIONLIST 0x400
30#define ALLOCINFO_ENTRYLEN 8
31#define ALLOCINFO_SECTORNUM 0x00
32#define ALLOCINFO_AUDIOBLOCKSINBLOCK 0x04
33#define ALLOC_ENTRIES_PER_SONG (ALLOC_SECTORS_PER_SONG*(512/ALLOCINFO_ENTRYLEN))
34#define LOCATE_TIMECODE 0
35#define LOCATE_NAME 4
36/* Quick calculation: A song is max 2^32 samples * 3 bytes *24 tracks
37 = 309 237 645 312 bytes
38 1 block=0x480h sectors = 589 824 bytes
39 So the max number of blocks in a song = (309237645312 / 589824) blocks = 524288 blocks
40*/
41#define MAX_BLOCKS_IN_SONG 524288
42const int hd24song::LOCATEPOS_SONGSTART =0;
43const int hd24song::LOCATEPOS_LOOPSTART =1;
44const int hd24song::LOCATEPOS_LOOPEND =2;
45const int hd24song::LOCATEPOS_PUNCHIN =21;
46const int hd24song::LOCATEPOS_PUNCHOUT =22;
47const int hd24song::LOCATEPOS_EDITIN =23;
48const int hd24song::LOCATEPOS_EDITOUT =24;
49const int hd24song::LOCATEPOS_LAST =24;
50const int hd24song::READMODE_COPY =0;
51const int hd24song::READMODE_REALTIME =1;
52const int hd24song::WRITEMODE_COPY =2;
53const int hd24song::WRITEMODE_REALTIME =3;
54void hd24song::loadblockintocache(__uint32 blocktoqueue)
55{
56 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
57
58 for (int i=LOCATEPOS_LAST;i<CACHEBUFFERS;i++) {
59 if (cachebuf_blocknum[i]==blocktoqueue) {
60 return; // already in cache.
61 }
62 }
63// cout << "Caching block " << blocktoqueue << endl;
64 cachebuf_blocknum[currcachebufnum]=blocktoqueue;
65
66////////////////////// TODO: THIS BLOCK OF CODE CAN BE REPLACED BY GETFIRSTBLOCKSECTOR
67 __uint32 rtallocentrynum=0; // reset cursor to start of song
68 __uint32 rtallocstartblock=0; // blocknum of first block in current allocation entry
69 __uint32 rtallocstartsector=Convert::getint32(buffer,SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*rtallocentrynum)+ALLOCINFO_SECTORNUM);
70 __uint32 rtallocaudioblocks=Convert::getint32(buffer,SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*rtallocentrynum)+ALLOCINFO_AUDIOBLOCKSINBLOCK);
71 __uint32 blocknum=blocktoqueue;
72
73 while ((blocknum-rtallocstartblock) >= rtallocaudioblocks) {
74 rtallocentrynum++; // reset cursor to start of song
75 if (rtallocentrynum>=ALLOC_ENTRIES_PER_SONG ) break;
76 rtallocstartblock+=rtallocaudioblocks; // blocknum of first block in current allocation entry
77 rtallocstartsector=Convert::getint32(buffer,
78 SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*rtallocentrynum)+ALLOCINFO_SECTORNUM);
79 rtallocaudioblocks=Convert::getint32(buffer,
80 SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*rtallocentrynum)+ALLOCINFO_AUDIOBLOCKSINBLOCK);
81
82 }
83///////////////////////////////////////////////////
84// cout << "allocentrynum=" << rtallocentrynum << endl;
85 parentfs->readsectors(parentfs->devhd24,
86 rtallocstartsector+((blocknum-rtallocstartblock)*blocksize_in_sectors),
87 cachebuf_ptr[currcachebufnum],blocksize_in_sectors); // raw read
88
89// cachebuf_ptr[currcachebufnum]=NULL; // TODO: READ SECTORS!!!
90
91 currcachebufnum++;
92 if (currcachebufnum>=CACHEBUFFERS)
93 {
94 currcachebufnum=LOCATEPOS_LAST+1;
95 }
96 return;
97}
98
99
100void hd24song::bufferpoll() {
101 // A process can call this procedure to tell the song
102 // object to check the cache request queue for blocks
103 // to cache.
104 if (currentreadmode==READMODE_COPY) return;
105 if (polling==1)
106 {
107 // Previous poll is still in progress.
108 // This is not a proper semaphore system but will
109 // help relief processing weight should the system
110 // get overloaded. Normally bufferpoll shouldn't be
111 // called much more than around 20 times per second,
112 // so the chance two polls interfere with one another
113 // is minimal.
114 return;
115 }
116 polling=1; // semaphore
117 if (blocktoqueue!=NOTHINGTOQUEUE)
118 {
119// cout << "queue request for " <<blocktoqueue << endl;
120 loadblockintocache(blocktoqueue);
121 blocktoqueue=NOTHINGTOQUEUE;
122 }
123 polling=0; // poll done
124}
125
126__uint32 hd24song::locatepointcount() {
127 return LOCATEPOS_LAST+1;
128}
129
130__uint32 hd24song::getlocatepos(int locatepoint)
131{
132 if (locatepoint<0) locatepoint=0;
133 if (locatepoint>LOCATEPOS_LAST) return songlength_in_samples();
134 long entryoffset=SONGINFO_LOCATEPOINTLIST+(locatepoint*LOCATEENTRY_LENGTH);
135 return Convert::getint32(buffer,entryoffset+LOCATE_TIMECODE);
136}
137
138string* hd24song::getlocatename(int locatepoint)
139{
140 if (locatepoint<0) locatepoint=0;
141 if (locatepoint>LOCATEPOS_LAST) {
142 string* newstr=new string("END");
143 return newstr;
144 }
145 long entryoffset=SONGINFO_LOCATEPOINTLIST+(locatepoint*LOCATEENTRY_LENGTH);
146 return Convert::readstring(buffer,entryoffset+LOCATE_NAME,8);
147}
148
149
150void hd24song::setlocatename(int locatepoint,string newname)
151{
152
153 if (locatepoint<0) locatepoint=0;
154 if (locatepoint>LOCATEPOS_LAST) return;
155 while (newname.length()<8) {
156 newname+=" ";
157 }
158 long entryoffset=SONGINFO_LOCATEPOINTLIST+(locatepoint*LOCATEENTRY_LENGTH);
159 for (__uint32 i=0;i<8;i++) {
160 buffer[entryoffset+LOCATE_NAME+i]=newname.c_str()[i];
161 }
162 return;
163}
164void hd24song::silenceaudioblocks(__uint32 allocsector,__uint32 numblocks)
165{
166 /* Given a sector number and a block count, silence the
167 given number of audio blocks on the drive starting
168 from the given sector number.
169 This function has 2 modes- one working with a 1-sector
170 stack-allocated block (slow), the other working with
171 a heap-allocated cluster (fast but memory intensive).
172 The heap method may need up to a few (2.3 or so) megabytes of RAM.
173 If heap allocation fails, the slow method is used.
174 */
175 unsigned char onesector[512];
176 memset(onesector,0,512);
177
178 __uint32 sectorstoclear=parentfs->getblocksizeinsectors();
179 sectorstoclear*=numblocks;
180 unsigned char* clearblock=(unsigned char*)memutils::mymalloc("silenceaudioblocks",sectorstoclear*512,1);
181 if (clearblock==NULL)
182 {
183 // Alloc failed, use low-memory use version
184 for (__uint32 i=0;i<sectorstoclear;i++)
185 {
186 parentfs->writesectors(parentfs->devhd24,
187 allocsector+i,
188 onesector,
189 1);
190 }
191 }
192 else
193 {
194 memset(clearblock,0,512*sectorstoclear);
195 parentfs->writesectors(parentfs->devhd24,
196 allocsector,
197 clearblock,
198 sectorstoclear);
199 memutils::myfree("silenceaudioblocks",clearblock);
200 }
201 return;
202}
203
204bool hd24song::setallocinfo(bool silencenew)
205{
206 return setallocinfo(silencenew,NULL,NULL,NULL);
207}
208
209__uint32 hd24song::requiredaudioblocks(__uint32 songlen)
210{
211 /* Figure out how many audio blocks we would expect
212 the song to have based on the songlength in samples. */
213 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
214 __uint32 blocksize_in_bytes=blocksize_in_sectors*SECTORSIZE;
215 __uint32 bits=(this->bitdepth());
216 __uint32 bytes_per_sample=bits/8;
217 __uint32 tracks_per_song=physical_channels();
218 __uint32 tracksamples_per_block=0;
219 if (tracks_per_song>0) {
220 tracksamples_per_block=(blocksize_in_bytes / bytes_per_sample) / tracks_per_song;
221 }
222
223 __uint32 remainder=songlen%tracksamples_per_block;
224 __uint32 blocks_expected=(songlen-remainder)/tracksamples_per_block;
225 if (remainder!=0) {
226 blocks_expected++;
227 }
228 return blocks_expected;
229}
230
231bool hd24song::allocatenewblocks(__uint32 blockstoalloc,bool silencenew,char* message,int* cancel,int (*checkfunc)())
232{
233 /* Allocate space in the real drive usage table.
234 Mind that we've been asked to allocate a certain
235 number of blocks, although in reality we are not
236 allocating blocks but clusters of blocks. */
237#if (SONGDEBUG == 1)
238 cout << "Total blocks to alloc=" << blockstoalloc << endl;
239#endif
240 __uint32 totblockstoalloc=blockstoalloc;
241 __uint32 allocsector=0;
242 __uint32 blockspercluster=parentfs->getblockspercluster();
243 cancel=cancel;
244 while (blockstoalloc>0)
245 {
246 __uint32 pct=(__uint32)((100*(totblockstoalloc-blockstoalloc))/totblockstoalloc);
247 if (message!=NULL) {
248 sprintf(message,
249 "Lengthening song... allocating block %ld of %ld, %ld%% done",
250 (long)(totblockstoalloc-blockstoalloc),
251 (long)totblockstoalloc,
252 (long)pct
253 );
254 }
255 if (checkfunc!=NULL)
256 {
257 checkfunc();
258 }
259 allocsector=getnextfreesector(allocsector);
260
261#if (SONGDEBUG == 1)
262 cout << "Allocsector=" << allocsector << endl;
263 cout << "Blockstoalloc=" << blockstoalloc << endl;
264#endif
265 if (allocsector==0) {
266#if (SONGDEBUG == 1)
267 cout << "Ran out of space with " << blockstoalloc
268 <<" left to alloc " << endl;
269#endif
270
271 return false;
272 }
273 if (silencenew)
274 {
275 // overwrite cluster with silence.
276#if (SONGDEBUG == 1)
277 cout << "Overwriting cluster with silence." << endl;
278#endif
279 this->silenceaudioblocks(allocsector,blockspercluster);
280 }
281 __uint32 alloccluster=parentfs->sector2cluster(allocsector);
282#if (SONGDEBUG == 1)
283 cout << "Alloccluster=" << alloccluster << endl;
284#endif
285 parentfs->enablebit(alloccluster,parentfs->sectors_driveusage);
286 if (blockstoalloc>=blockspercluster)
287 {
288 blockstoalloc-=blockspercluster;
289 }
290 else
291 {
292 blockstoalloc=0;
293 }
294 }
295 return true;
296}
297
298bool hd24song::setallocinfo(bool silencenew,char* message,int* cancel,int (*checkfunc)())
299{
300 /* This function is intended for recovering live recordings
301 and lengthening songs. To use it, set a new song length
302 first, then call this function- it will add the required
303 number of blocks to the song.
304
305 Boolean 'silencenew' indicates if newly allocated space
306 should be overwritten with silence.
307
308 For initializing songs to nonzero length, you will want
309 to set this to TRUE.
310
311 For recovering live recordings you will want to set it
312 to FALSE.
313
314 For realtime recording, it is set to FALSE for efficiency
315 reasons, as the recording algorithm itself will overwrite
316 newly allocated space with audio (and silence as needed).
317
318 Savemessage allows giving textual feedback to the user
319 and the int pointed to by cancel will be set to 1 by the
320 GUI if the user interrupts the process.
321 In case of recovering a song, after setting the length of
322 a crashed song to the estimated duration, we want to try
323 to find back the audio.
324
325 It is reasonable that this previously recorded audio can be
326 found by simply allocating as many unused clusters to the
327 song as needed to reach the desired length; because those
328 same clusters would have been allocated to the song after
329 pressing 'stop'.
330
331 This function attempts to perform this allocation (which
332 should also allow people to perform headerless
333 live recoveries).
334
335 The way this will work is:
336 -- find out how many audio blocks are allocated to the song;
337 -- find out how many we think there *should* be allocated;
338 -- then, allocate those blocks (in a copy of the usage table);
339 -- finally, append the newly allocated blocks to the song.
340 -- the last can be done by subtracting the old usage table
341 from the new one and calling appendorphanclusters.
342
343 FIXME: operation is not correct when running out of drive space.
344 TODO: we count blocks to allocate but in reality clusters are
345 being reserved. Shouldn't we work cluster based all the
346 way?
347 */
348
349 __uint32 blocksinalloctable=audioblocks_in_alloctable();
350 __uint32 blocks_expected=requiredaudioblocks(songlength_in_samples());
351
352
353#if (SONGDEBUG == 1)
354 cout << "Actual blocks allocated for song:" << blocksinalloctable << endl;
355 cout << "Expected blocks allocated for song:" << blocks_expected << endl;
356#endif
357 if (blocksinalloctable==blocks_expected)
358 {
359 // right amount of space is already allocated.
360 return true;
361 }
362
363 if (blocksinalloctable>blocks_expected)
364 {
365 // looks like too much space is allocated,
366 // but setallocinfo() won't support song shrinking
367 // for now.
368 return false;
369 }
370
371 /* Not enough space is allocated-- allocate as much extra as needed. */
372#if (SONGDEBUG == 1)
373 cout << "Allocating space for song. " <<endl;
374#endif
375 __uint32 blockstoalloc=blocks_expected-blocksinalloctable;
376
377 unsigned char* copyusagetable=parentfs->getcopyofusagetable();
378 if (copyusagetable==NULL)
379 {
380 /* Cannot get usage table (out of memory?) */
381 return false;
382 }
383
384 bool tryallocnew=this->allocatenewblocks(blockstoalloc,silencenew,message,cancel,checkfunc);
385 if (tryallocnew==false)
386 {
387 /* Cannot allocate new blocks (out of drive space?) */
388 memutils::myfree("copyusagetable",copyusagetable);
389 return false;
390 }
391
392 /* Cluster allocation succeeded.
393 To find out which clusters have been allocated,
394 XOR the previous copy of the usage table over it.
395 This will result in a list of newly allocated
396 (orphan) clusters still to be appended to the song.
397 */
398 for (__uint32 i=0;i<(512*15);i++)
399 {
400 copyusagetable[i]=(copyusagetable[i])
401 ^(parentfs->sectors_driveusage[i]);
402 }
403
404#if (SONGDEBUG == 1)
405 cout << "Alloc action successful- append orphan clusters now." << endl;
406#endif
407 // call appendorphanclusters
408 if (message!=NULL)
409 {
410 sprintf(message,"Adding allocated space to song...");
411 if (checkfunc!=NULL)
412 {
413 checkfunc();
414 }
415 }
416 bool songresize;
417 if (silencenew) {
418 songresize=false;
419 }
420 else
421 {
422 songresize=true;
423 }
424 appendorphanclusters(copyusagetable,songresize);
425 memutils::myfree("copyusagetable",copyusagetable);
426 // save for either song or drive usage table is not
427 // to be called here- it would violate the concept
428 // of safe, read-only recovery.
429 return true;
430}
431
432void hd24song::appendorphanclusters(unsigned char* usagebuffer,bool allowsongresize)
433{
434 __uint32 clusters=parentfs->clustercount();
435 __uint32 currpos=0;
436 __uint32 curralloctableentry=used_alloctable_entries();
437#if (SONGDEBUG == 1)
438 cout << "Appending orphan clusters to song. Used alloctable entries=" << curralloctableentry
439 << "clusters=" << clusters
440 << endl;
441#endif
442
443 while (currpos<clusters) {
444 __uint32 blockstart=currpos;
445 while (parentfs->isfreecluster(blockstart,usagebuffer) && (blockstart<clusters)) {
446 blockstart++;
447 }
448#if (SONGDEBUG == 1)
449 cout << "Block starts at cluster " <<blockstart << endl;
450#endif
451 if (blockstart==clusters) {
452 break;
453 }
454
455 // blockstart now points to a nonfree cluster
456 __uint32 blockend=blockstart;
457 while (!parentfs->isfreecluster(blockend,usagebuffer) && (blockend<clusters)) {
458 blockend++;
459 }
460 // blockend now points to a free cluster
461 currpos=blockend;
462 __uint32 blocklen=blockend-blockstart;
463
464 __uint32 entrystartsector=(unsigned int) (parentfs->cluster2sector(blockstart));
465 __uint32 entrynumblocks=(unsigned int)( parentfs->getblockspercluster()*blocklen );
466 Convert::setint32(buffer,
467 SONGINFO_ALLOCATIONLIST+ALLOCINFO_SECTORNUM
468 +(ALLOCINFO_ENTRYLEN*curralloctableentry),entrystartsector);
469
470 Convert::setint32(buffer,
471 SONGINFO_ALLOCATIONLIST+ALLOCINFO_AUDIOBLOCKSINBLOCK
472 +(ALLOCINFO_ENTRYLEN*curralloctableentry),entrynumblocks);
473 curralloctableentry++;
474#if (SONGDEBUG == 1)
475 printf("%x %x\n",(unsigned int)parentfs->cluster2sector(blockstart),(unsigned int)( parentfs->getblockspercluster()*blocklen ));
476#endif
477 }
478 /* the operation may have resulted in the song getting
479 longer. This is due to the fact that while recording,
480 'stop' may be pressed before all audio blocks of the
481 cluster have been used.
482 Also, of course, there may be more orphaned clusters
483 around than belong to the song- for whatever reason.
484 */
485
486 __uint32 blocksinalloctable=audioblocks_in_alloctable();
487
488 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
489 __uint32 blocksize_in_bytes=blocksize_in_sectors*SECTORSIZE;
490 __uint32 bits=(this->bitdepth());
491 __uint32 bytes_per_sample=bits/8;
492 __uint32 tracks_per_song=physical_channels();
493 __uint32 tracksamples_per_block=0;
494 if (tracks_per_song>0) {
495 tracksamples_per_block=(blocksize_in_bytes / bytes_per_sample) / tracks_per_song;
496 }
497 __uint32 newsonglen=tracksamples_per_block*blocksinalloctable;
498 Convert::setint32(buffer,SONGINFO_AUDIOBLOCKS,blocksinalloctable);
499
500 /* The following directly sets the songlength in the song buffer
501 rather than via songlength_in_samples(val) to prevent
502 testing whether more space needs to be allocated-
503 which is not needed as space has just been allocated.
504 (Also, the below number may be less accurate than the
505 number some user might specify via songlength_in_samples(val)).
506 */
507 if (allowsongresize)
508 {
509 Convert::setint32(buffer,SONGINFO_SONGLENGTH_IN_SAMPLES,newsonglen);
510 }
511 return;
512}
513
514void hd24song::setblockcursor(__uint32 blocknum)
515{
516 allocentrynum=0; // reset cursor to start of song
517 allocstartblock=0; // blocknum of first block in current allocation entry
518 allocstartsector=Convert::getint32(buffer,SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*allocentrynum)+ALLOCINFO_SECTORNUM);
519 allocaudioblocks=Convert::getint32(buffer,SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*allocentrynum)+ALLOCINFO_AUDIOBLOCKSINBLOCK);
520 // cout << " allocaudioblocks=" << allocaudioblocks << endl;
521 while ((blocknum-allocstartblock) >= allocaudioblocks) {
522 allocentrynum++; // reset cursor to start of song
523 allocstartblock+=allocaudioblocks; // blocknum of first block in current allocation entry
524 allocstartsector=Convert::getint32(buffer,
525 SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*allocentrynum)+ALLOCINFO_SECTORNUM);
526 allocaudioblocks=Convert::getint32(buffer,
527 SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*allocentrynum)+ALLOCINFO_AUDIOBLOCKSINBLOCK);
528 }
529 return;
530}
531
532void hd24song::unmark_used_clusters(unsigned char* sectors_inuse)
533{
534 /*
535 * Given an image of used clusters, this function
536 * will alter that image to unmark the clusters
537 * in use by this song.
538 * Under normal circumstances, this is used to
539 * delete songs.
540 * However, it is also useful to search for orphan
541 * clusters (by unmarking all clusters in use by
542 * all songs- the remaining clusters then must be
543 * orphan clusters)
544 */
545#if (SONGDEBUG == 1)
546 cout << "unmark used clusters." << endl;
547#endif
548 __uint32 allocentries=used_alloctable_entries();
549
550 if (allocentries==0) {
551#if (SONGDEBUG == 1)
552 cout << "Song claims no used allocation entries." << endl;
553#endif
554 return;
555 }
556
557 __uint32 blockspercluster=parentfs->getblockspercluster();
558
559 for (__uint32 i=0; i<allocentries; i++)
560 {
561 __uint32 entrystartsector=Convert::getint32(buffer,
562 SONGINFO_ALLOCATIONLIST+ALLOCINFO_SECTORNUM
563 +(ALLOCINFO_ENTRYLEN*i));
564
565 __uint32 entrynumblocks=Convert::getint32(buffer,
566 SONGINFO_ALLOCATIONLIST+ALLOCINFO_AUDIOBLOCKSINBLOCK
567 +(ALLOCINFO_ENTRYLEN*i));
568
569
570 __uint32 entrystartcluster=parentfs->sector2cluster(entrystartsector);
571#if (SONGDEBUG == 1)
572 cout << "startsector=" <<entrystartsector << " blocks=" << entrynumblocks <<" clust=" << entrystartcluster << endl;
573#endif
574
575 __uint32 entrynumclusters=(entrynumblocks-(entrynumblocks%blockspercluster))/blockspercluster;
576 if ((entrynumblocks%blockspercluster)!=0)
577 {
578 entrynumclusters++;
579 }
580#if (SONGDEBUG == 1)
581 cout << "buffer=" << buffer << endl;
582#endif
583 if (entrynumclusters==0)
584 {
585#if (SONGDEBUG == 1)
586 cout << "nothing to free here." << endl;
587#endif
588
589 }
590 for (__uint32 j=0;j<entrynumclusters;j++) {
591 __uint32 clust2free=j+entrystartcluster;
592 parentfs->freecluster(clust2free,sectors_inuse);
593#if (SONGDEBUG == 1)
594 cout << clust2free << " ";
595#endif
596 }
597#if (SONGDEBUG == 1)
598 cout << endl;
599#endif
600 }
601}
602
603__uint32 hd24song::currentlocation()
604{
605 return songcursor;
606}
607void hd24song::currentlocation(__uint32 offset)
608{
609 golocatepos(offset);
610}
611
612__uint32 hd24song::golocatepos(__uint32 offset)
613{
614 /* Offset indicates next sample that will be
615 played back (or recorded). A song of 1 sample long
616 can have the cursor set at offset 0 or offset 1;
617 offset 1 is then beyond the end of the song, which is
618 meaningful for recording but not for playback. */
619
620 __uint32 songlen=songlength_in_samples();
621
622 if (offset>songlen) {
623 offset=songlen;
624 //return offset;
625 }
626
627 songcursor=offset;
628 evenodd=0;
629
630 __uint32 samplenumber=songcursor;
631#if (SONGDEBUG == 1)
632// cout << "songcursor=" << songcursor << endl;
633#endif
634 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
635 __uint32 blocksize_in_bytes=blocksize_in_sectors*SECTORSIZE;
636 __uint32 bits=(this->bitdepth());
637 __uint32 bytes_per_sample=bits/8;
638 __uint32 tracks_per_song=physical_channels();
639 __uint32 tracksamples_per_block=0;
640 if (tracks_per_song>0) {
641 tracksamples_per_block=(blocksize_in_bytes / bytes_per_sample) / tracks_per_song;
642 }
643 __uint32 blocknum=0;
644 if (tracksamples_per_block>0) {
645 blocknum=(samplenumber/(tracksamples_per_block));
646 }
647
648#if (SONGDEBUG == 1)
649// cout << "still going strong" << endl;
650#endif
651
652 setblockcursor(blocknum);
653
654 return songcursor;
655}
656
657__uint32 hd24song::setlocatepos(int locatepoint,__uint32 offset)
658{
659 /** Sets the value of a locate point to the given offset.
660 Parameters:
661 locatepoint
662 The 0-based locate point identifier
663 offset
664 The new offset (in samples*) for the locate point.
665 * In high samplerate songs (88k2, 96k), the offset is given as
666 number of sample pairs, because audio data is interlaced
667 across 2 physical tracks.
668 */
669
670 if (locatepoint<0)
671 {
672 locatepoint=0;
673 }
674
675 if (locatepoint>LOCATEPOS_LAST)
676 {
677 return 0;
678 }
679
680 long entryoffset=SONGINFO_LOCATEPOINTLIST
681 +(locatepoint*LOCATEENTRY_LENGTH);
682
683 buffer[entryoffset+LOCATE_TIMECODE+3]=offset%256;
684 offset=offset>>8;
685 buffer[entryoffset+LOCATE_TIMECODE+2]=offset%256;
686 offset=offset>>8;
687 buffer[entryoffset+LOCATE_TIMECODE+1]=offset%256;
688 offset=offset>>8;
689 buffer[entryoffset+LOCATE_TIMECODE+0]=offset%256;
690 return getlocatepos(locatepoint);
691}
692
693hd24song::hd24song(hd24project* p_parent,__uint32 p_songid)
694{
695#if (SONGDEBUG == 1)
696 cout << "CONSTRUCT hd24song " << p_songid << endl;
697#endif
698 currentreadmode=READMODE_COPY;
699 blocktoqueue=NOTHINGTOQUEUE;
700 polling=0;
701 evenodd=0;
702 audiobuffer=NULL;
703 scratchbook=NULL;
704 buffer=NULL;
705 framespersec=FRAMESPERSEC;
706 lastallocentrynum=0;
707 busyrecording=false;
708 mysongid=p_songid;
709 rehearsemode=false;
710 lengthened=false;
711 lastavailablecacheblock=0xFFFFFFFF;
712 currcachebufnum=LOCATEPOS_LAST+1;
713 buffer=(unsigned char*)memutils::mymalloc("hd24song-buffer",16384,1);
714 parentfs=p_parent->parentfs;
715 parentproject=p_parent;
716 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
717 __uint32 blocksize_in_bytes=blocksize_in_sectors*SECTORSIZE;
718
719 for (__uint32 tracknum=1;tracknum<=24;tracknum++)
720 {
721 track_armed[tracknum-1]=false;
722 }
723
724 // 'read enabled' is used in copy mode to reduce the amount of
725 // secors that need to be read from disk.
726 for (__uint32 tracknum=1;tracknum<=24;tracknum++)
727 {
728 track_readenabled[tracknum-1]=true; // by default all are read enabled.
729 }
730
731#if (SONGDEBUG == 1)
732 cout << "2" << endl;
733#endif
734 audiobuffer=(unsigned char *)memutils::mymalloc("hd24song-audiobuffer",blocksize_in_bytes+SECTORSIZE,1);
735 scratchbook=(unsigned char *)memutils::mymalloc("hd24song-scratchbook",blocksize_in_bytes+SECTORSIZE,1);
736
737 if (audiobuffer==NULL) {
738#if (SONGDEBUG ==1)
739 cout << "could not allocate audio buffer" << endl;
740#endif
741 }
742
743 // Set up cache buffers for realtime access
744 // first, dynamically create pointer array
745 cachebuf_blocknum=(__uint32*)memutils::mymalloc("hd24song-cachebuf",sizeof(__uint32)*CACHEBUFFERS,1);
746 cachebuf_ptr=(unsigned char**)memutils::mymalloc("hd24song-cachebufptr",sizeof (unsigned char *)*CACHEBUFFERS,1);
747 // then, allocate blocks and point array to it.
748 int i;
749
750 for (i=0;i<CACHEBUFFERS;i++)
751 {
752 cachebuf_ptr[i]=NULL;
753 }
754
755 for (i=0;i<CACHEBUFFERS;i++)
756 {
757 cachebuf_blocknum[i]=CACHEBLOCK_UNUSED;
758 cachebuf_ptr[i]=(unsigned char*)memutils::mymalloc("hd24song-cachebufptr[i]",blocksize_in_bytes,1);
759 }
760
761 __uint32 songsector=parentproject->getsongsectornum(mysongid);
762#if (SONGDEBUG ==1)
763 cout << "Reading # song sectors= " << TOTAL_SECTORS_PER_SONG
764 << "from sec " << songsector << endl;
765#endif
766 parentfs->readsectors(parentfs->devhd24,
767 songsector,
768 buffer,TOTAL_SECTORS_PER_SONG);
769 parentfs->fstfix(buffer,TOTAL_SECTORS_PER_SONG*512);
770 //ncout << "sectors read="<<dummy<<endl;
771
772#if (SONGDEBUG ==1)
773 cout << "alloc mem for blocksectors" << endl;
774#endif
775
776 blocksector=(__uint32*)memutils::mymalloc("blocksector",600000,sizeof(__uint32));
777#if (SONGDEBUG ==1)
778 cout << "Blocksector=" <<blocksector << endl;
779 cout << "clear blocksectors" << endl;
780#endif
781 for (int i=0; i<600000;i++) {
782 blocksector[i]=0;
783 }
784 // how many blocks in this song?
785#if (SONGDEBUG == 1)
786 cout << "cleared blocksectors" << endl;
787
788 cout << "create song" << mysongid << endl;
789 cout << "blocksize in bytes=" << blocksize_in_bytes << endl;
790 cout << "bitdepth in bytes=" << bitdepth()/8 << endl;
791 cout << "phys_channels=" << physical_channels() << endl;
792#endif
793 if (physical_channels() >0)
794 {
795 __uint32 blocksize_in_samples=blocksize_in_bytes / (physical_channels()* (bitdepth()/8));
796 __uint32 number_of_blocks=(__uint32) floor ( songlength_in_samples() / blocksize_in_samples );
797#if (SONGDEBUG == 1)
798 cout << "songlen in sam=" << songlength_in_samples() << endl;
799#endif
800 if ( ( songlength_in_samples() % blocksize_in_samples ) !=0 )
801 {
802 number_of_blocks++;
803 }
804
805
806#if (SONGDEBUG == 1)
807 cout << " blocksize in sams = " << blocksize_in_samples;
808 cout << "=" << number_of_blocks << "blocks " << endl;
809
810 cout << "memoize alloc info for " << number_of_blocks << "blocks." << endl;
811#endif
812 memoizeblocksectors(number_of_blocks);
813 }
814
815 divider=0;
816 lastreadblock=0;
817 mustreadblock=1; // next time a sample is requested, we must read from disk
818 //cout << "golocatepos" << endl;
819 golocatepos(0);
820 //cout << "locate done" << endl;
821}
822
823__uint32 hd24song::songid()
824{
825 return this->mysongid;
826}
827
828bool hd24song::has_unexpected_end()
829{
830 // Check if this song has an 'unexpected end of song' error
831 // (in header mode, this always returns false)
832 if (this->parentfs->headersectors!=0)
833 {
834 return false;
835 }
836 // find out how many audioblocks are claimed to be allocated in the
837 // song allocation info table
838
839 __uint32 blocksinalloctable=audioblocks_in_alloctable();
840
841 if ( blocksinalloctable < Convert::getint32(buffer,SONGINFO_AUDIOBLOCKS) )
842 {
843 // the song itself claims it should have more audioblocks
844 return true;
845 }
846 // Over here we could also verify the expected number of blocks
847 // against the given song length in samples.
848 return false;
849}
850
851bool hd24song::is_fixable_unexpected_end()
852{
853 /** Checks if this song has a FIXABLE 'unexpected end of song' error */
854 __uint32 blocksinalloctable=audioblocks_in_alloctable();
855#if (SONGDEBUG == 1)
856 cout << "Blocks in alloctable=" << blocksinalloctable << endl;
857#endif
858 __uint32 songblockcount=Convert::getint32(buffer,SONGINFO_AUDIOBLOCKS);
859 if (songblockcount>MAX_BLOCKS_IN_SONG)
860 {
861 /* Safety feature: corruption detected,
862 block count of song is greater than theoretical maximum. */
863 songblockcount=MAX_BLOCKS_IN_SONG;
864 }
865
866 /* Values in songblockcount and blocksinalloctable should be equal
867 unless the song is corrupt. If the latter value lower,
868 there is an 'unexpected end of song' error. */
869
870 if (!( blocksinalloctable < songblockcount ))
871 {
872 // No unexpected end of song error, nothing to fix
873 return false;
874 }
875
876 /* There is an unexpected end of song error. But is it one of
877 the type we know how to automatically fix? */
878
879 if (used_alloctable_entries() == (512/ALLOCINFO_ENTRYLEN) ) {
880 /* Yes, it is. We have exactly 1 sector of allocated data and
881 the rest is zero data, due to a known (presumed) bug in
882 the HD24 recorder. */
883 return true;
884 }
885
886 /* No, it isn't. Then assume we cannot fix it. */
887 return false;
888}
889
890__uint32 hd24song::used_alloctable_entries()
891{
892 /** Counts how many entries in the song allocation table
893 are in use. */
894 __uint32 MAXALLOCENTRIES=((512/ALLOCINFO_ENTRYLEN)*5)-1;
895
896 for (__uint32 i=0;i<MAXALLOCENTRIES;i++)
897 {
898 __uint32 entrystartsector=Convert::getint32(buffer,
899 SONGINFO_ALLOCATIONLIST+ALLOCINFO_SECTORNUM
900 +(ALLOCINFO_ENTRYLEN*i));
901 if (entrystartsector==0) {
902 return i;
903 }
904 }
905 return MAXALLOCENTRIES;
906}
907
908__uint32 hd24song::audioblocks_in_alloctable()
909{
910 /** Finds out how many audio blocks are claimed in
911 the allocation table of the song. */
912 __uint32 checkentries=used_alloctable_entries();
913 if (checkentries==0) {
914 return 0;
915 }
916 __uint32 totblocks=0;
917
918 for (__uint32 i=0; i<checkentries; i++)
919 {
920 __uint32 entrynumblocks=Convert::getint32(buffer,
921 SONGINFO_ALLOCATIONLIST+ALLOCINFO_AUDIOBLOCKSINBLOCK
922 +(ALLOCINFO_ENTRYLEN*i));
923 totblocks+=entrynumblocks;
924
925 if (totblocks>MAX_BLOCKS_IN_SONG)
926 {
927 /* Safety net: Corruption detected, song claims to use
928 more blocks than the theoretical possible maximum. */
929 return MAX_BLOCKS_IN_SONG;
930 }
931 }
932
933 return totblocks;
934}
935
936hd24song::~hd24song()
937{
938#if (SONGDEBUG == 1)
939 cout << "DESTRUCT hd24song " << mysongid << endl;
940#endif
941 if (buffer!=NULL)
942 {
943 memutils::myfree("buffer",buffer);
944 buffer=NULL;
945 }
946 if (scratchbook != NULL)
947 {
948 memutils::myfree("scratchbook",scratchbook);
949 scratchbook=NULL;
950 }
951 if (audiobuffer != NULL)
952 {
953 memutils::myfree("audiobuffer",audiobuffer);
954 audiobuffer=NULL;
955 }
956 if (blocksector != NULL)
957 {
958 memutils::myfree("blocksector",blocksector);
959 blocksector=NULL;
960 }
961 int i;
962
963 // clear cache
964 for (i=0;i<CACHEBUFFERS;i++)
965 {
966 if (cachebuf_ptr[i]!=NULL) {
967 memutils::myfree("cachebuf_ptr[i]",cachebuf_ptr[i] );
968 }
969 }
970 if (cachebuf_ptr!=NULL)
971 {
972 memutils::myfree("cachebuf_ptr",cachebuf_ptr);
973 }
974 if (cachebuf_blocknum!=NULL)
975 {
976 memutils::myfree("cachebuf_blocknum",cachebuf_blocknum);
977 }
978// cout << "del song " << mysongid << endl;
979}
980
981void hd24song::queuecacheblock(__uint32 blocknum)
982{
983 // Only process request if the block is neither cached nor queued yeta
984 // This function is only called if a block is not cached.
985 // In addition, as playback progresses, the more blocks are queued,
986 // the less importance the oldest blocks have.
987 // For this reason, a circular queue would make sense-- if too many blocks
988 // get queued, the last one requested can be ignored.
989 // The queue needn't be very big; a shortcut is to use a queue of
990 // just 1 element long. This should still work OK because a block
991 // queue request may be issued over and over again until it is cached.
992 if (blocknum!=blocktoqueue)
993 {
994 // block not yet queued
995// cout << "Processing request to queue block " << blocknum << " for caching " << endl;
996 }
997 blocktoqueue=blocknum;
998 return;
999}
1000
1001string* hd24song::songname(hd24fs* parentfs, unsigned char* songbuf)
1002{
1003 string* ver=parentfs->version();
1004 if (*ver == "1.00") {
1005 // version 1.0 filesystem.
1006 delete ver;
1007 string* tmp=new string("");
1008 string* dummy=Convert::readstring(songbuf,SONGINFO_SONGNAME_8,8);
1009
1010 *tmp+=*dummy;
1011 delete dummy;
1012 if (tmp->length()==8) {
1013 dummy=Convert::readstring(songbuf,SONGINFO_SONGNAME_8+10,2);
1014 *tmp+=*dummy;
1015 delete dummy;
1016 }
1017 return tmp;
1018 }
1019 delete ver;
1020 string* tmp=Convert::readstring(songbuf,SONGINFO_SONGNAME,64);
1021 return tmp;
1022}
1023
1024string* hd24song::songname()
1025{
1026 return songname(this->parentfs,buffer);
1027}
1028
1029void hd24song::songname(string newname)
1030{
1031 songname(buffer,newname);
1032}
1033
1034void hd24song::songname(unsigned char* songbuf,string newname)
1035{
1036 hd24fs::setname(songbuf,newname,SONGINFO_SONGNAME_8,SONGINFO_SONGNAME);
1037 return;
1038}
1039
1040bool hd24song::iswriteprotected()
1041{
1042 __uint32 writeprot=(Convert::getint32(buffer,SONGINFO_WRITEPROTECTED));
1043 writeprot&=0x04000000;
1044 if (writeprot==0) return false;
1045 return true;
1046}
1047
1048void hd24song::setwriteprotected(bool prot)
1049{
1050 __uint32 writeprot=(Convert::getint32(buffer,SONGINFO_WRITEPROTECTED));
1051 writeprot&=0xFBFFFFFF;
1052
1053 if (prot) {
1054 writeprot|=0x04000000;
1055 }
1056 Convert::setint32(buffer,SONGINFO_WRITEPROTECTED,writeprot);
1057 return;
1058}
1059
1060void hd24song::physical_channels(unsigned char* songbuf,__uint32 newchannelcount)
1061{
1062 if (newchannelcount>24) newchannelcount=24;
1063 songbuf[SONGINFO_CHANNELS]=(unsigned char)(newchannelcount&0xFF);
1064}
1065
1066void hd24song::physical_channels(__uint32 newchannelcount)
1067{
1068 physical_channels(buffer,newchannelcount);
1069}
1070
1071__uint32 hd24song::physical_channels(unsigned char* songbuf)
1072{
1073 int channels=Convert::getint32(songbuf,SONGINFO_CHANNELS)>>24;
1074 channels=(channels & 0x1f);
1075 if (channels>24) channels=24;
1076 return channels;
1077}
1078
1079__uint32 hd24song::physical_channels()
1080{
1081 return physical_channels(buffer);
1082}
1083
1084__uint32 hd24song::logical_channels()
1085{
1086 if (this->samplerate()>=88200)
1087 {
1088 return (physical_channels()>>1);
1089 } else {
1090 return (physical_channels());
1091 }
1092}
1093
1094__uint32 hd24song::logical_channels(unsigned char* songbuf)
1095{
1096 if (samplerate(songbuf)>=88200)
1097 {
1098 return (physical_channels(songbuf)>>1);
1099 } else {
1100 return (physical_channels(songbuf));
1101 }
1102}
1103
1104void hd24song::logical_channels(unsigned char* songbuf,__uint32 channelcount)
1105{
1106 if (samplerate(songbuf)>=88200) {
1107 physical_channels(songbuf,channelcount*2);
1108 } else {
1109 physical_channels(songbuf,channelcount);
1110 }
1111}
1112
1113__uint32 hd24song::samplerate(unsigned char* songbuf)
1114{
1115 __uint32 samrate=Convert::getint32(songbuf,SONGINFO_SAMPLERATE)>>8;
1116 return samrate;
1117}
1118
1119__uint32 hd24song::samplerate()
1120{
1121 return samplerate(buffer);
1122}
1123
1124void hd24song::samplerate(unsigned char* songbuf,__uint32 newrate)
1125{
1126 __uint32 samrate=(newrate<<8);
1127 __uint32 bd=((unsigned char)songbuf[SONGINFO_BITDEPTH]);
1128 samrate|=bd;
1129 Convert::setint32(songbuf,SONGINFO_SAMPLERATE,samrate);
1130}
1131
1132void hd24song::samplerate(__uint32 newrate)
1133{
1134 samplerate(buffer,newrate);
1135}
1136
1137
1138__uint32 hd24song::bitdepth()
1139{
1140 __uint32 depth=(__uint32)((unsigned char)buffer[SONGINFO_BITDEPTH]);
1141 if ((depth!=24) && (depth !=16) && (depth!=32)) return 24;
1142 return depth;
1143}
1144
1145__uint32 hd24song::songlength_in_samples()
1146{
1147 return (Convert::getint32(buffer,SONGINFO_SONGLENGTH_IN_SAMPLES));
1148}
1149
1150__uint32 hd24song::songlength_in_samples(__uint32 newlen,bool silencenew)
1151{
1152 return hd24song::songlength_in_samples(newlen,silencenew,NULL,NULL);
1153}
1154
1155__uint32 hd24song::songlength_in_samples(__uint32 newlen,bool silencenew,char* savemessage,int* cancel)
1156{
1157 return hd24song::songlength_in_samples(newlen,silencenew,savemessage,cancel,NULL);
1158}
1159
1160hd24fs* hd24song::fs()
1161{
1162 return this->parentfs;
1163}
1164
1165__uint32 hd24song::songlength_in_samples(__uint32 newlen,bool silencenew,char* savemessage,int* cancel,int (*checkfunc)())
1166{
1167 /* Sets the length of a song and updates any allocation
1168 info as needed.
1169 The return value of the function is the actual song length
1170 set. Return value may differ from newlen if not enough drive
1171 space was available or if allocating ran into problems
1172 otherwise. */
1173 if (this==NULL)
1174 {
1175#if (SONGDEBUG==1)
1176 cout << "Song object is NULL! Cannot lengthen song." << endl;
1177#endif
1178 return 0;
1179 }
1180 __uint32 oldlen=songlength_in_samples();
1181 if (savemessage!=NULL)
1182 {
1183 // clear default save message
1184 savemessage[0]='\0';
1185 }
1186 if (cancel!=NULL)
1187 {
1188 *cancel=0;
1189 }
1190#if (SONGDEBUG==1)
1191 cout << "Lengthening song to " << newlen << " samples" << endl;
1192 if (silencenew) {
1193 cout << "(And silencing new blocks)" << endl;
1194 }
1195#endif
1196 Convert::setint32(buffer,SONGINFO_SONGLENGTH_IN_SAMPLES,newlen);
1197 if (newlen==0) {
1198 Convert::setint32(buffer,SONGINFO_AUDIOBLOCKS,0);
1199 return 0;
1200 }
1201
1202 // the above is required by setallocinfo
1203 if (setallocinfo(silencenew,savemessage,cancel,checkfunc)) {
1204 // setting alloc info succeeded
1205#if (SONGDEBUG==1)
1206 cout << "Success lengthening song to " << newlen << " samples" << endl;
1207#endif
1208 this->lengthened=true;
1209 memoizeblocksectors(Convert::getint32(buffer,SONGINFO_AUDIOBLOCKS));
1210 return newlen;
1211 }
1212 // setting new length failed- reset song to old length.
1213#if (SONGDEBUG==1)
1214 cout << "Failed. Keep at old length of " <<oldlen << endl;
1215#endif
1216 Convert::setint32(buffer,SONGINFO_SONGLENGTH_IN_SAMPLES,oldlen);
1217 return oldlen;
1218}
1219
1220__uint32 hd24song::songlength_in_samples(__uint32 newlen)
1221{
1222 return songlength_in_samples(newlen,true);
1223}
1224
1225string* hd24song::display_cursor()
1226{
1227 return (display_duration(songcursor));
1228}
1229__uint32 hd24song::cursorpos()
1230{
1231 return songcursor;
1232}
1233
1234
1235string* hd24song::display_duration(__uint32 offset,__uint32 samrate)
1236{
1237 //cout << "dispdur" << offset << endl;
1238 if (samrate==0)
1239 {
1240 string* nulldur=Convert::int2str(0,2,"0");
1241 *nulldur+=":00:00.00";
1242 return nulldur;
1243 }
1244 //cout <<"disphours "<<offset << endl;
1245 //cout << "samrateh=" <<samplerate() << endl;
1246 if (samrate>=88200) { samrate=samrate>>1; }
1247 __uint32 subsec=display_subseconds(offset,samrate);
1248 if (samrate>0) {
1249 subsec=this->framespersec*subsec/samrate;
1250 }
1251 string* newstr= Convert::int2str(display_hours(offset),2,"0");
1252 *newstr+=":";
1253 string* mins=Convert::int2str(display_minutes(offset),2,"0");
1254 *newstr+=*mins;
1255 delete mins;
1256 *newstr+=":";
1257 string* secs=Convert::int2str(display_seconds(offset),2,"0");
1258 *newstr+=*secs;
1259 delete secs;
1260 *newstr+=".";
1261 string* subsecs=Convert::int2str(subsec,2,"0");
1262 *newstr+=*subsecs;
1263 delete subsecs;
1264 return newstr;
1265}
1266
1267string* hd24song::display_duration(__uint32 offset)
1268{
1269 return display_duration(offset,samplerate());
1270}
1271
1272string* hd24song::display_duration()
1273{
1274 __uint32 songlen=songlength_in_samples();
1275 return display_duration(songlen);
1276}
1277
1278__uint32 hd24song::display_hours()
1279{
1280 __uint32 songlen=songlength_in_samples();
1281 return display_hours(songlen);
1282}
1283
1284__uint32 hd24song::display_hours(__uint32 offset,__uint32 samrate)
1285{
1286 if (samrate==0)
1287 {
1288 return 0;
1289 }
1290 //cout <<"disphours "<<offset << endl;
1291 //cout << "samrateh=" <<samplerate() << endl;
1292 if (samrate>=88200) { samrate=samrate>>1; }
1293
1294 __uint32 totsonglen=offset;
1295 __uint32 songsubsecs=totsonglen%samrate;
1296 __uint32 cutsonglen=(totsonglen-songsubsecs);
1297 __uint32 totsongsecs=(cutsonglen/samrate);
1298 __uint32 viewsongsecs=totsongsecs%60;
1299 __uint32 totsongmins=(totsongsecs-viewsongsecs)/60;
1300 __uint32 viewsongmins=(totsongmins%60);
1301 __uint32 totsonghours=(totsongmins-viewsongmins)/60;
1302 return totsonghours;
1303}
1304
1305__uint32 hd24song::display_minutes()
1306{
1307 return display_minutes(songlength_in_samples());
1308}
1309
1310__uint32 hd24song::display_minutes(__uint32 offset,__uint32 samrate)
1311{
1312 if (samrate==0)
1313 {
1314 return 0;
1315 }
1316 //cout <<"dispmin "<<offset << endl;
1317 //cout << "samratem=" <<samplerate() << endl;
1318 if (samrate>=88200) { samrate=samrate>>1; }
1319 __uint32 totsonglen=offset;
1320 __uint32 songsubsecs=totsonglen%samrate;
1321 __uint32 cutsonglen=(totsonglen-songsubsecs);
1322 __uint32 totsongsecs=(cutsonglen/samrate);
1323 __uint32 viewsongsecs=totsongsecs%60;
1324 __uint32 totsongmins=(totsongsecs-viewsongsecs)/60;
1325 __uint32 viewsongmins=(totsongmins%60);
1326 return viewsongmins;
1327}
1328
1329__uint32 hd24song::display_seconds()
1330{
1331 return display_seconds(songlength_in_samples());
1332}
1333
1334void hd24song::sectorinit(unsigned char* songsector)
1335{
1336 unsigned char emptysong[512] = {
1337 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X10,0X00,0X00,0X00,0X30,0X00,0X00,0X00,
1338 0X00,0X20,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
1339 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X67,0X6E,0X6F,0X53,0X6D,0X61,0X4E,0X20,
1340 0X20,0X65,0X18,0X00,0X18,0X44,0XAC,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
1341 0X00,0X00,0X00,0X00,0X01,0X02,0X00,0X00,0XE4,0X12,0X04,0X30,0XA8,0X10,0X00,0X20,
1342 0X00,0X00,0X00,0X20,0X01,0X00,0X13,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
1343 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
1344 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
1345 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
1346 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
1347 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
1348 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X41,0X54,0X53,0X20,
1349 0X20,0X20,0X54,0X52,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X31,0X30,0X6D,0X61,
1350 0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X32,0X30,0X6D,0X61,0X00,0X00,0X00,0X00,
1351 0X4E,0X63,0X6F,0X4C,0X33,0X30,0X6D,0X61,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,
1352 0X34,0X30,0X6D,0X61,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X35,0X30,0X6D,0X61,
1353 0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X36,0X30,0X6D,0X61,0X00,0X00,0X00,0X00,
1354 0X4E,0X63,0X6F,0X4C,0X37,0X30,0X6D,0X61,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,
1355 0X38,0X30,0X6D,0X61,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X39,0X30,0X6D,0X61,
1356 0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X30,0X31,0X6D,0X61,0X00,0X00,0X00,0X00,
1357 0X4E,0X63,0X6F,0X4C,0X31,0X31,0X6D,0X61,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,
1358 0X32,0X31,0X6D,0X61,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X33,0X31,0X6D,0X61,
1359 0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X34,0X31,0X6D,0X61,0X00,0X00,0X00,0X00,
1360 0X4E,0X63,0X6F,0X4C,0X35,0X31,0X6D,0X61,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,
1361 0X36,0X31,0X6D,0X61,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X37,0X31,0X6D,0X61,
1362 0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,0X38,0X31,0X6D,0X61,0X00,0X00,0X00,0X00,
1363 0X4E,0X63,0X6F,0X4C,0X39,0X31,0X6D,0X61,0X00,0X00,0X00,0X00,0X4E,0X63,0X6F,0X4C,
1364 0X30,0X32,0X6D,0X61,0X00,0X00,0X00,0X00,0X63,0X6E,0X75,0X50,0X20,0X6E,0X49,0X68,
1365 0X00,0X00,0X00,0X00,0X63,0X6E,0X75,0X50,0X74,0X75,0X4F,0X68,0X00,0X00,0X00,0X00,
1366 0X74,0X69,0X64,0X45,0X20,0X6E,0X49,0X20,0X00,0X00,0X00,0X00,0X74,0X69,0X64,0X45,
1367 0X74,0X75,0X4F,0X20,0X04,0X04,0X00,0X00,0X78,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
1368 0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00
1369 };
1370 for (int i=0;i<1024;i++) {
1371 songsector[i]=0; // wipe clean entire buffer
1372 }
1373 for (int i=0;i<512;i++) {
1374 songsector[i]=emptysong[i]; // init with empty song info
1375 }
1376 hd24fs::fstfix(songsector,1024); // from native drive format to normal byte ordering
1377 songname(songsector,"Song Name");
1378}
1379
1380__uint32 hd24song::display_seconds(__uint32 offset,__uint32 samrate)
1381{
1382 if (samrate==0)
1383 {
1384 return 0;
1385 }
1386 if (samrate>=88200) { samrate=samrate>>1; }
1387 __uint32 cutsonglen=offset-display_subseconds(offset,samrate);
1388 __uint32 totsongsecs=(cutsonglen/samrate);
1389 __uint32 viewsongsecs=totsongsecs%60;
1390 return viewsongsecs;
1391}
1392
1393__uint32 hd24song::display_subseconds() {
1394 return display_subseconds(songlength_in_samples());
1395}
1396
1397__uint32 hd24song::display_subseconds(__uint32 offset,__uint32 samrate)
1398{
1399 if (samrate==0)
1400 {
1401 return 0;
1402 }
1403 if (samrate>=88200) { samrate=samrate>>1; }
1404 __uint32 totsonglen=offset;
1405 __uint32 songsubsecs=totsonglen%samrate;
1406 return songsubsecs;
1407}
1408
1409__uint32 hd24song::display_hours(__uint32 offset)
1410{
1411 return display_hours(offset,samplerate());
1412}
1413
1414__uint32 hd24song::display_minutes(__uint32 offset)
1415{
1416 return display_minutes(offset,samplerate());
1417}
1418
1419__uint32 hd24song::display_seconds(__uint32 offset)
1420{
1421 return display_seconds(offset,samplerate());
1422}
1423
1424__uint32 hd24song::display_subseconds(__uint32 offset)
1425{
1426 return display_subseconds(offset,samplerate());
1427}
1428
1429unsigned char* hd24song::getcachedbuffer(__uint32 blocknum)
1430{
1431 // This will return a pointer to an audio buffer containing
1432 // the audio of the given blocknum, if available.
1433 // If not available, it will return a pointer to a silent
1434 // block and queue the blocknum for caching
1435 int i;
1436 bool foundbuf=false;
1437 unsigned char* bufptr=NULL;
1438
1439 /* A straight loop isn't the fastest way to find the
1440 * correct buffer (a binary tree or hash would perform
1441 * better). However the advantage for a total of around
1442 * 40 blocks (25 locate points and some lookahead)
1443 * would be rather marginal. */
1444
1445 bool havenext=false;
1446 bool haveprev=false;
1447
1448 for (i=LOCATEPOS_LAST;i<CACHEBUFFERS;i++)
1449 {
1450 if (blocknum>0) {
1451 if (cachebuf_blocknum[i]==(blocknum-1)) {
1452 haveprev=true;
1453 if (havenext && foundbuf) break;
1454 }
1455 }
1456 if (cachebuf_blocknum[i]==(blocknum+1)) {
1457 havenext=true;
1458 if (haveprev && foundbuf) break;
1459 }
1460 if (cachebuf_blocknum[i]==blocknum)
1461 {
1462 bufptr=cachebuf_ptr[i];
1463 foundbuf=true;
1464 if (havenext && haveprev) break;
1465 }
1466 }
1467 if (!(foundbuf))
1468 {
1469 if (!haveprev)
1470 {
1471 queuecacheblock(blocknum-1);
1472 }
1473 if (!havenext)
1474 {
1475 queuecacheblock(blocknum+1);
1476 }
1477 queuecacheblock(blocknum);
1478 return NULL;
1479 }
1480 if (!haveprev)
1481 {
1482 queuecacheblock(blocknum-1);
1483 }
1484 if (!havenext)
1485 {
1486 queuecacheblock(blocknum+1);
1487 }
1488 // Cache buffer was found.
1489 // If we want we can optimize the cache here.
1490 // Otherwise, just return the buffer pointer.
1491 lastavailablecacheblock=blocknum;
1492 return bufptr;
1493}
1494
1495void hd24song::memoizeblocksectors(__uint32 number_of_blocks)
1496{
1497 __uint32 totblocksfound=0;
1498 __uint32 myallocentrynum=0;
1499
1500 __uint32 entrystartsector=0;
1501 __uint32 entrynumblocks=0;
1502
1503 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
1504
1505 while (
1506 (totblocksfound < number_of_blocks)
1507 && (totblocksfound <= MAX_BLOCKS_IN_SONG)
1508 && (myallocentrynum<ALLOC_ENTRIES_PER_SONG)
1509 )
1510 {
1511
1512 entrystartsector=Convert::getint32(buffer,
1513 SONGINFO_ALLOCATIONLIST+ALLOCINFO_SECTORNUM
1514 +(ALLOCINFO_ENTRYLEN*myallocentrynum));
1515 entrynumblocks=Convert::getint32(buffer,
1516 SONGINFO_ALLOCATIONLIST+ALLOCINFO_AUDIOBLOCKSINBLOCK
1517 +(ALLOCINFO_ENTRYLEN*myallocentrynum));
1518#if (SONGDEBUG == 1)
1519 cout << "Entry " << myallocentrynum << " start sector=" << entrystartsector ;
1520 cout << "# blocks in entry=" << entrynumblocks << endl;
1521#endif
1522
1523 for (__uint32 filler=0;filler<entrynumblocks;filler++) {
1524 if (totblocksfound+filler > MAX_BLOCKS_IN_SONG) break;
1525 blocksector[totblocksfound+filler]=entrystartsector+(blocksize_in_sectors*filler);
1526 }
1527 totblocksfound+=entrynumblocks;
1528 myallocentrynum++;
1529 }
1530 lastallocentrynum=myallocentrynum;
1531#if (SONGDEBUG == 1)
1532 cout << "Tot blocks found = " << totblocksfound << "/" << number_of_blocks << endl;
1533#endif
1534 return ;
1535}
1536
1537/* Quick calculation:
1538 Saving 1 block sectornum=32 bit (4 bytes).
1539 MAX_BLOCKS_IN_SONG=524288, so the maximum number of bytes needed to
1540 memoize all song allocation info=524288*4=2097152 bytes (~2 megabyte)
1541 for the worst case song, which is certainly doable.
1542
1543 As memoization can be done efficiently when carried out sequentially, it can be done in O(n)
1544
1545 When this function is called once with last blocknum, all blocks can be memoized during a
1546 single pass of the WHILE loop
1547 Lookup will be O(1).
1548 A typical song transfer will take X tracks
1549 (each track requires a sector calc for all blocks).
1550*/
1551
1552void hd24song::getmultitracksample(long* mtsample,int readmode)
1553{
1554 /* This procedure is intended for copying audio from disk (and for realtime
1555 playback). This procedure assumes sequential reading.
1556
1557 If reverse playback is desired, golocatepos() must be called for
1558 every sample. This is a bit more expensive in resources.
1559 However, as golocatepos()
1560 doesn't cause any I/O, it should still be light enough for regular use.
1561
1562 As such, allocation info for every sample will only be recalculated
1563 when needed. This results in the best possible performance.
1564
1565 There are two playback modes: copy and realtime. Copy mode guarantees
1566 that a bit-accurate copy of the disk contents is returned, but may
1567 require (slow) disk reads in the process, which makes it unsuitable
1568 for anything requiring realtime response.
1569
1570 Realtime mode guarantees to return a result in a short amount of time,
1571 by using a cache. This makes it suitable for realtime playback.
1572 When a block is not available in cache, silence is returned. This makes
1573 realtime mode unsuitable for accurate transfers, but suitable for direct
1574 from-disk mixing. Blocks that are not available in cache are queued for
1575 caching. Periodic background checks should be performed on this queue to
1576 help guarantee availability of the blocks to cache.
1577
1578 In high samplerate mode, samples are interlaced between odd tracks and
1579 even tracks. This allows the song cursor to keep running at normal speed-
1580 the difference is that at double the speed the songcursor is only
1581 updated every other multitrack sample request. This means that at the
1582 cost of only being able to do locate operations to even samples,
1583 we can maintain use the same code for block calculation.
1584 */
1585#if (SONGDEBUG==1)
1586 cout << "Getmultitracksample mtsample=" << mtsample <<" mode=" <<readmode<< "this=" <<this << endl;
1587 cout << "parentfs=" << parentfs << endl;
1588#endif
1589 unsigned char* buffertouse=NULL;
1590 currentreadmode=readmode;
1591 __uint32 samrate=samplerate();
1592 __uint32 samplenumber=songcursor;
1593 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
1594 __uint32 blocksize_in_bytes=blocksize_in_sectors*SECTORSIZE;
1595 __uint32 bits=(this->bitdepth());
1596 __uint32 bytes_per_sample=bits/8;
1597 __uint32 tracks_per_song=physical_channels();
1598 __uint32 tracksamples_per_block=(blocksize_in_bytes / bytes_per_sample) / tracks_per_song;
1599 __uint32 blocknum=(samplenumber/(tracksamples_per_block));
1600#if (SONGDEBUG==1)
1601 cout << "tracksamples per block="<<tracksamples_per_block << endl;
1602 cout << "readmtsample MARK" << endl;
1603#endif
1604 bool mustgetaudiodata=false;
1605 if (parentfs->maintenancemode==1) {
1606 readmode=hd24song::READMODE_COPY;
1607 }
1608 switch (readmode)
1609 {
1610 case hd24song::READMODE_COPY:
1611 if ((lastreadblock!=blocknum)||(mustreadblock==1))
1612 {
1613 mustgetaudiodata=true;
1614 }
1615 break;
1616 case hd24song::READMODE_REALTIME:
1617 mustgetaudiodata=false;
1618 if ((lastavailablecacheblock!=blocknum)||(mustreadblock==1)) {
1619 mustgetaudiodata=true;
1620 }
1621 break;
1622 default:
1623 mustgetaudiodata=false;
1624 break;
1625 }
1626
1627#if (SONGDEBUG==1)
1628 cout << "readmtsample MARK2" << endl;
1629#endif
1630 if (mustgetaudiodata)
1631 {
1632 // We advanced a block. This means we need to read more audio data.
1633 // (or in case of realtime reading, at least find out what next block to get)
1634 if (blocknum==(allocstartblock+allocaudioblocks))
1635 {
1636 // In fact, we've read all data in the current allocation entry.
1637 allocentrynum++; // reset cursor to start of song
1638 allocstartblock=blocknum; // blocknum of first block in current allocation entry
1639 allocstartsector=Convert::getint32(buffer,
1640 SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*allocentrynum)+ALLOCINFO_SECTORNUM);
1641 allocaudioblocks=Convert::getint32(buffer,
1642 SONGINFO_ALLOCATIONLIST+(ALLOCINFO_ENTRYLEN*allocentrynum)+ALLOCINFO_AUDIOBLOCKSINBLOCK);
1643 }
1644
1645 switch (readmode)
1646 {
1647 case (hd24song::READMODE_COPY):
1648 if (parentfs->maintenancemode==1)
1649 {
1650 // in maintenance mode, we will display the sector currently
1651 // being played back (that is what maintenance mode is all
1652 // about
1653
1654 string* bla=Convert::int32tohex(allocstartsector+((blocknum-allocstartblock)*blocksize_in_sectors));
1655 cout << *bla << "-1" << endl; // maintenance mode
1656 delete bla;
1657 }
1658
1659 parentfs->readsectors(parentfs->devhd24,
1660 allocstartsector+((blocknum-allocstartblock)*blocksize_in_sectors),
1661 audiobuffer,blocksize_in_sectors); // raw audio read, no fstfix needed
1662 mustreadblock=0;
1663 break;
1664 case (hd24song::READMODE_REALTIME):
1665 buffertouse=getcachedbuffer(blocknum);
1666
1667 default: break;
1668 }
1669 // cout << "read done. " << endl;
1670 }
1671#if (SONGDEBUG==1)
1672 cout << "readmtsample MARK 3" << endl;
1673 cout << "audiobuffer=" << audiobuffer << endl;
1674 cout << "readmtsample MARK 3b" << endl;
1675#endif
1676
1677 int sample_within_block=samplenumber%(tracksamples_per_block);
1678 if (readmode==hd24song::READMODE_COPY)
1679 {
1680 buffertouse=audiobuffer;
1681 }
1682 __uint32 trackspersam;
1683 if (samrate>=88200) {
1684 trackspersam=2;
1685 } else {
1686 trackspersam=1;
1687 }
1688#if (SONGDEBUG==1)
1689 cout << "readmtsample MARK 3c" << endl;
1690#endif
1691 __uint32 tottracks=logical_channels();
1692 for (__uint32 tracknum=0;tracknum<tottracks;tracknum++)
1693 {
1694 __uint32 samval;
1695 if (buffertouse==NULL)
1696 {
1697 samval=0;
1698 }
1699 else
1700 {
1701 int offset_first_blocksample=(((tracknum*trackspersam)+evenodd)*tracksamples_per_block*bytes_per_sample);
1702 int sample_offset=offset_first_blocksample+(sample_within_block*bytes_per_sample);
1703 samval=Convert::getint24(buffertouse,sample_offset);
1704 // TODO: Handle word lengths other than 24 bits
1705 }
1706#if (SONGDEBUG==1)
1707 cout << "readmtsample MARK 3e" << endl;
1708 cout << "tracknum=" << tracknum << endl;
1709#endif
1710 mtsample[tracknum]=samval;
1711#if ( SONGDEBUG == 1 )
1712 cout << "posttracknum=" << tracknum << endl;
1713 if ((tracknum==0) && (songcursor<20)) {
1714 string* bla=Convert::int32tohex(samval);
1715 cout << *bla << "-2"<< endl;
1716 delete bla;
1717 }
1718 cout << "readmtsample MARK 3f" << endl;
1719#endif
1720 }
1721#if (SONGDEBUG==1)
1722 cout << "readmtsample MARK 4" << endl;
1723#endif
1724 lastreadblock=blocknum;
1725 if (samrate>=88200)
1726 {
1727 // only for high sample rate mode:
1728 evenodd=1-evenodd;
1729 if (evenodd==0) {
1730 songcursor++;
1731 }
1732 } else {
1733 songcursor++;
1734 }
1735
1736 return;
1737}
1738
1739int hd24song::getmtrackaudiodata(__uint32 firstsamnum,__uint32 samples,unsigned char* buffer,int readmode)
1740{
1741 /* WARNING: For best performance the number of samples must not cross
1742 audio block boundaries. This function has been tested in such a fashion only.
1743
1744 This procedure is intended for reading audio data from disk,
1745 in a completely random access fashion.
1746 It assumes single track audio and will always read only whole blocks,
1747 directly to the given buffer. Return value is a pointer to the
1748 first sample that was supposed to be read.
1749
1750 The buffer should be sufficiently large to hold the total audio size.
1751 (number of samples*3 bytes for normal sample rates or
1752 number of samples*3*2 bytes for high sample rates (88k2, 96k).
1753
1754 In copy mode, only required blocks will be read from disk
1755 (no caching will take place- we'll leave this to the OS)
1756
1757 Realtime mode guarantees to return a result in a short amount of time,
1758 by using a cache. This makes it suitable for realtime playback.
1759 REALTIME MODE IS NOT IMPLEMENTED YET.
1760 When a block is not available in cache, silence is returned. This makes
1761 realtime mode unsuitable for accurate transfers, but suitable for direct
1762 from-disk mixing. Blocks that are not available in cache are queued for
1763 caching. Periodic background checks should be performed on this queue to
1764 help guarantee availability of the blocks to cache.
1765 */
1766
1767 currentreadmode=readmode;
1768 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
1769 __uint32 blocksize_in_bytes=blocksize_in_sectors*SECTORSIZE;
1770
1771 __uint32 bits=(this->bitdepth());
1772 __uint32 bytes_per_sample=bits/8;
1773 __uint32 tracks_per_song=logical_channels();
1774 __uint32 tracksamples_per_block=(blocksize_in_bytes / bytes_per_sample) / tracks_per_song;
1775
1776 __uint32 startblocknum=((firstsamnum-(firstsamnum%tracksamples_per_block))/(tracksamples_per_block));
1777 __uint32 lastsamnum=firstsamnum+samples-1;
1778 __uint32 endblocknum=((lastsamnum-(lastsamnum%tracksamples_per_block))/(tracksamples_per_block));
1779
1780 // check read enable flags to allow reducing number of sectors to be transferred.
1781 __uint32 first_readenabled=0;
1782 __uint32 last_readenabled=23;
1783 for (__uint32 i=0;i<logical_channels();i++)
1784 {
1785 if (track_readenabled[i])
1786 {
1787 first_readenabled=i;
1788 break;
1789 }
1790 }
1791 for (__uint32 i=logical_channels();i>0;i--)
1792 {
1793 if (track_readenabled[i-1])
1794 {
1795 last_readenabled=i-1;
1796 break;
1797 }
1798 }
1799#if (SONGDEBUG==1)
1800 cout << "first,last track="<<first_readenabled<<","<<last_readenabled<<endl;
1801#endif
1802 __uint32 chanmult=physical_channels()/logical_channels();
1803
1804 __uint32 physicaltracksreadenabled=chanmult*(last_readenabled-first_readenabled)+1;
1805 __uint32 firsttrackoffset=chanmult*first_readenabled*tracksamples_per_block*bytes_per_sample;
1806 __uint32 sectoroffset=firsttrackoffset/SECTORSIZE;
1807 __uint32 readlength=(physicaltracksreadenabled*bytes_per_sample*tracksamples_per_block)/SECTORSIZE;
1808#if (SONGDEBUG==1)
1809 cout << "sectoroffset,readlength="<<sectoroffset<<","<<readlength<< endl;
1810#endif
1811 for (__uint32 blocknum=startblocknum;blocknum<=endblocknum;blocknum++)
1812 {
1813#if (SONGDEBUG == 1)
1814 string* bla=Convert::int32tohex(blocksector[blocknum]);
1815 cout << *bla << "-3" << endl; // maintenance mode
1816 delete bla;
1817#endif
1818 // now read trackblocksize_in_sectors sectors from sector blocksec into buffer
1819 parentfs->readsectors(parentfs->devhd24,
1820 blocksector[blocknum]+sectoroffset,
1821 &buffer[firsttrackoffset],
1822 readlength); // raw audio read, no fstfix needed
1823 }
1824 return firstsamnum%tracksamples_per_block;
1825}
1826
1827void hd24song::interlaceblock(unsigned char* sourcebuffer,unsigned char* targetbuffer)
1828{
1829 /* This is needed for high sample rates as high sample rate recordings
1830 take up two physical channels for each logical audio channel */
1831 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
1832 __uint32 blocksize_in_bytes=blocksize_in_sectors*SECTORSIZE;
1833 __uint32 blocksize_doubleblock=blocksize_in_bytes/logical_channels();
1834 __uint32 blocksize_halfblock=blocksize_in_bytes/physical_channels();
1835
1836 __uint32 bits=(this->bitdepth());
1837 __uint32 bytes_per_sample=bits/8;
1838 __uint32 tracksamples_per_halfblock=(blocksize_halfblock/bytes_per_sample);
1839 __uint32 choffset=0;
1840 for (__uint32 ch=0;ch<logical_channels();ch++)
1841 {
1842 for (__uint32 i=0;i<tracksamples_per_halfblock;i++)
1843 {
1844 __uint32 samoff_target=i*bytes_per_sample+choffset;
1845 __uint32 samoff_source=2*i*bytes_per_sample+choffset;
1846 for (__uint32 j=0;j<bytes_per_sample;j++) {
1847 targetbuffer[samoff_target+j]
1848 =sourcebuffer[samoff_source+j];
1849 targetbuffer[samoff_target+j+bytes_per_sample]
1850 =sourcebuffer[samoff_source+j+blocksize_halfblock];
1851 }
1852 }
1853 choffset+=blocksize_doubleblock;
1854 }
1855}
1856
1857void hd24song::deinterlaceblock(unsigned char* sourcebuffer,unsigned char* targetbuffer)
1858{
1859 /* This is needed for high sample rates as high sample rate recordings
1860 take up two physical channels for each logical audio channel */
1861 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
1862 __uint32 blocksize_in_bytes=blocksize_in_sectors*SECTORSIZE;
1863 __uint32 blocksize_doubleblock=blocksize_in_bytes/logical_channels();
1864 __uint32 blocksize_halfblock=blocksize_in_bytes/physical_channels();
1865
1866 __uint32 bits=(this->bitdepth());
1867 __uint32 bytes_per_sample=bits/8;
1868 __uint32 tracksamples_per_halfblock=(blocksize_halfblock/bytes_per_sample);
1869 __uint32 choffset=0;
1870 for (__uint32 ch=0;ch<logical_channels();ch++)
1871 {
1872 for (__uint32 i=0;i<tracksamples_per_halfblock;i++)
1873 {
1874 __uint32 samoff_source=i*bytes_per_sample+choffset;
1875 __uint32 samoff_target=2*i*bytes_per_sample+choffset;
1876 for (__uint32 j=0;j<bytes_per_sample;j++) {
1877 targetbuffer[samoff_target+j]
1878 =sourcebuffer[samoff_source+j];
1879 targetbuffer[samoff_target+j+bytes_per_sample]
1880 =sourcebuffer[samoff_source+j+blocksize_halfblock];
1881 }
1882 }
1883 choffset+=blocksize_doubleblock;
1884 }
1885}
1886
1887int hd24song::putmtrackaudiodata(__uint32 firstsamnum,__uint32 samples,unsigned char* writebuffer,int writemode)
1888{
1889// cout << " first 30 bytes of write buffer: " ;
1890// for (int i=0;i<30;i++) { cout << " " << (short)((unsigned char)writebuffer[i]); }
1891// cout << endl;
1892 /*
1893 This procedure is intended for writing audio data to disk.
1894 Contrary to reading audio (where realtime mode is OK to drop
1895 some audio during heavy seeking), write mode should always
1896 write reliably- caching is not allowed.
1897 As such only sequential operation is allowed.
1898
1899 NOTE: THIS FUNCTION WAS NOT TESTED FOR REALTIME OPERATION.
1900
1901 Before writing, you need to arm the tracks that you want to
1902 write to (using the unarmtrack and armtrack functions),
1903 then enable record mode (function startrecord).
1904
1905 Startrecord will disable seeking while recording and perform
1906 any tasks needed to initialize drive usage administration.
1907
1908 When no tracks are armed or record mode is not enabled,
1909 nothing will be written to disk. (A rehearse mode may be
1910 added at some point to prevent writing to disk even in
1911 record mode).
1912
1913 After writing, you need to call stoprecord. This will
1914 re-enable seek operations and write out any drive usage
1915 information, increase file length etc, should any space have
1916 been allocated during the write operation.
1917
1918 Before calling this function, the write buffer needs to contain
1919 the audio to record in the tracks that are armed.
1920
1921 After calling this function, the write buffer contents will be
1922 altered: the non-armed tracks will contain the audio that
1923 was already on disk.
1924
1925 The write buffer should be sufficiently large to hold the total
1926 audio size for all tracks.
1927
1928 */
1929
1930 currentreadmode=writemode;
1931
1932 __uint32 blocksize_in_sectors=parentfs->getblocksizeinsectors();
1933 __uint32 blocksize_in_bytes=blocksize_in_sectors*SECTORSIZE;
1934
1935 __uint32 bits=(this->bitdepth());
1936 __uint32 bytes_per_sample=bits/8;
1937 __uint32 tracks_per_song=logical_channels();
1938 __uint32 tracksamples_per_block=(blocksize_in_bytes / bytes_per_sample) / tracks_per_song;
1939 __uint32 trackbytes_per_block=(blocksize_in_bytes / tracks_per_song);
1940
1941 __uint32 startblocknum=((firstsamnum-(firstsamnum%tracksamples_per_block))/(tracksamples_per_block));
1942 __uint32 lastsamnum=firstsamnum+samples-1;
1943 __uint32 endblocknum=((lastsamnum-(lastsamnum%tracksamples_per_block))/(tracksamples_per_block));
1944 for (__uint32 blocknum=startblocknum;blocknum<=endblocknum;blocknum++)
1945 {
1946 // now read trackblocksize_in_sectors sectors from sector blocksec into buffer
1947 //cout << "Reading sec " << blocksector[blocknum] << endl;
1948
1949 if (blocksector[blocknum]<0x1397f6) {
1950 // safety feature- drop out of write mode when superblock is targeted.
1951 cout << "Detected audio write request to administration area. " << endl;
1952 cout << "Possible bug, dropping out of write mode. " << endl;
1953 setrehearsemode(true);
1954 }
1955
1956 parentfs->readsectors(parentfs->devhd24,
1957 blocksector[blocknum],
1958 scratchbook,
1959 blocksize_in_sectors); // raw audio read, no fstfix needed
1960
1961 // now overwrite only the armed tracks with contents of buffer
1962 __uint32 numtracks=0;
1963 if (!(this->isrehearsemode())) {
1964
1965 for (__uint32 tracknum=1; tracknum<=tracks_per_song; tracknum++) {
1966 if (!(this->trackarmed(tracknum))) {
1967 continue;
1968 }
1969 numtracks++;
1970 //cout << "track "<<tracknum<<" is armed." <<endl;
1971 __uint32 firsttrackbyte=(tracknum-1)*trackbytes_per_block;
1972 for (__uint32 q=0; q<trackbytes_per_block;q++) {
1973 if (q<10) {
1974//nn cout << "scratchbook[" << firsttrackbyte+q <<"]=writebuffer[dito]=" << (int)((unsigned char)writebuffer[firsttrackbyte+q]) << endl;
1975 }
1976 scratchbook[firsttrackbyte+q]=(unsigned char)writebuffer[firsttrackbyte+q];
1977 }
1978 }
1979 if (numtracks>0) {
1980 //cout << "writing back " << numtracks
1981 // << " tracks to sector "<< blocksector[blocknum] << endl;
1982 parentfs->writesectors(parentfs->devhd24,
1983 blocksector[blocknum],
1984 scratchbook,
1985 blocksize_in_sectors);
1986 }
1987 }
1988 }
1989 return firstsamnum%tracksamples_per_block;
1990}
1991
1992void hd24song::startrecord(int recordmode)
1993{
1994 // TODO: recordmode to distinguish between realtime and copy mode
1995 recordmode=recordmode;
1996 this->busyrecording=true;
1997}
1998
1999void hd24song::stoprecord()
2000{
2001 this->busyrecording=false;
2002}
2003
2004bool hd24song::recording()
2005{
2006 return (this->busyrecording);
2007}
2008
2009
2010void hd24song::readenabletrack(__uint32 tracknum,bool enable)
2011{
2012 if (tracknum<1) return;
2013 if (tracknum>24) return;
2014 if (tracknum>logical_channels()) return;
2015 track_readenabled[tracknum-1]=enable;
2016}
2017
2018void hd24song::readenabletrack(__uint32 tracknum)
2019{
2020 readenabletrack(tracknum,true);
2021}
2022
2023bool hd24song::isrehearsemode()
2024{
2025 return this->rehearsemode;
2026}
2027
2028void hd24song::setrehearsemode(bool p_rehearsemode)
2029{
2030 this->rehearsemode=p_rehearsemode;
2031 return;
2032}
2033
2034void hd24song::trackarmed(__uint32 tracknum,bool arm)
2035{
2036 if (tracknum<1) return;
2037 if (tracknum>24) return;
2038 if (tracknum>logical_channels()) return;
2039 track_armed[tracknum-1]=arm;
2040 return;
2041}
2042
2043bool hd24song::trackarmed(__uint32 tracknum)
2044{
2045 if (tracknum<1) return false;
2046 if (tracknum>24) return false;
2047 return track_armed[tracknum-1];
2048}
2049
2050bool hd24song::istrackmonitoringinput(__uint32 tracknum)
2051{
2052 // TODO: PROPERLY SET TRANSPORT STATUS! (for now done by GUI)
2053
2054 if (tracknum<1) return false;
2055 if (tracknum>(this->logical_channels())) return false;
2056
2057 // indicates if a given track is (supposed to be)
2058 // monitoring input (if false, playback is being monitored).
2059 // This is based on the following decision matrix:
2060 //
2061 // All input | auto input | Track rec-enabled | Transport status | result
2062 // ----------+------------+-------------------+------------------+--------
2063 // on | | don't care | don't care | true
2064 // off | off | false | stop | false
2065 // off | off | false | play | false
2066 // off | off | false | rec | false
2067 // off | off | true | stop | true
2068 // off | off | true | play | true
2069 // off | off | true | rec | true
2070 // off | on | false | stop | false
2071 // off | on | false | play | false
2072 // off | on | false | rec | false
2073 // off | on | true | stop | true
2074 // off | on | true | play | false
2075 // off | on | true | rec | true
2076 // ----------+------------+-------------------+------------------+--------
2077 if (parentfs->isallinput()) {
2078 return true;
2079 }
2080 if (!(this->trackarmed(tracknum))) return false;
2081
2082 if (this->parentfs->transportstatus==hd24fs::TRANSPORTSTATUS_PLAY) {
2083 if (this->parentfs->isautoinput()) {
2084 return false;
2085 }
2086 }
2087 return true;
2088}
2089
2090__uint32 hd24song::getnextfreesector(__uint32 lastallocsector)
2091{
2092 /* Based on the alloc info of the current song, this function
2093 will return the sector number of the next unallocated cluster.
2094 When no unallocated sectors are found, the function will return 0.
2095
2096 Sector 0 is never in the data area, so this will allow us to
2097 distinguish between this situation and real cluster numbers.
2098 Sector 0 is the superblock- as allocation implies writing to the
2099 drive, the code calling this function MUST verify the result.
2100
2101 When the allocation info cannot be decided upon based on just
2102 the unallocated song sectors within the last allocated cluster
2103 for the song, this function will ask the file system for the
2104 sector number of the next unused cluster.
2105
2106 */
2107#if (SONGDEBUG==1)
2108 cout << "Song::getnextfreesec(" << lastallocsector << ")" << endl;
2109#endif
2110 // lastallocentrynum=last used allocation entry
2111 __uint32 allocsector=Convert::getint32(buffer,SONGINFO_ALLOCATIONLIST
2112 +(ALLOCINFO_ENTRYLEN*lastallocentrynum)+ALLOCINFO_SECTORNUM);
2113 __uint32 allocblocks=Convert::getint32(buffer,SONGINFO_ALLOCATIONLIST
2114 +(ALLOCINFO_ENTRYLEN*lastallocentrynum)+ALLOCINFO_AUDIOBLOCKSINBLOCK);
2115 __uint32 nextsec=0;
2116
2117 if ((allocsector==0) && (lastallocsector==0))
2118 {
2119 // no sectors allocated yet within song.
2120 nextsec=this->parentfs->getnextfreesector(CLUSTER_UNDEFINED);
2121 } else {
2122 // find out first cluster used by allocation unit
2123 __uint32 alloccluster;
2124 __uint32 blockspercluster;
2125 __uint32 clustersused;
2126 __uint32 lastalloccluster;
2127 if (allocsector==0) {
2128 lastalloccluster=parentfs->sector2cluster(lastallocsector);
2129 } else {
2130 alloccluster=parentfs->sector2cluster(allocsector);
2131 blockspercluster=parentfs->getblockspercluster();
2132 clustersused=allocblocks/blockspercluster;
2133 lastalloccluster=alloccluster+(clustersused-1);
2134 }
2135
2136 // check if allocation entry fills up the current cluster word
2137 // if not, allocate another cluster within current alloc entry
2138 // otherwise, ask the FS for drive space
2139 // (update song alloc info)
2140
2141 nextsec=this->parentfs->getnextfreesector(lastalloccluster);
2142 }
2143
2144 if (nextsec==0)
2145 {
2146 /*
2147 TODO: safety feature: If getnextfreesector returns 0, record
2148 mode will be disabled to prevent accidentally overwriting the
2149 superblock. (Alternatively transport may be stopped but
2150 auto-stop hasn't been fully designed yet). */
2151 // write protect of some sort
2152 setrehearsemode(true);
2153 }
2154 return nextsec;
2155}
2156
2157void hd24song::save()
2158{
2159 __uint32 songsector=parentproject->getsongsectornum(this->mysongid);
2160#if (SONGDEBUG == 1)
2161 cout << "writing buffer to sector " << songsector << ", " <<TOTAL_SECTORS_PER_SONG<<" sectors" << endl;
2162#endif
2163
2164 parentfs->fstfix(buffer,TOTAL_SECTORS_PER_SONG*512); // sector is now once again in native format
2165
2166 parentfs->setsectorchecksum(buffer,0,songsector,2); // checksum for 2 sectors of song data
2167 parentfs->setsectorchecksum(buffer,2*512,songsector+2,5); // checksum for 5 sectors of allocation data
2168
2169 parentfs->writesectors(parentfs->devhd24,
2170 songsector,
2171 buffer,TOTAL_SECTORS_PER_SONG);
2172
2173 parentfs->fstfix(buffer,TOTAL_SECTORS_PER_SONG*512); // sector is now in 'fixed' format again
2174 if (this->lengthened)
2175 {
2176#if (SONGDEBUG == 1)
2177 cout << "song was lengthened, update of drive usage needed." << endl;
2178#endif
2179 parentfs->savedriveusage();
2180 this->lengthened=false;
2181 } else
2182 {
2183#if (SONGDEBUG == 1)
2184 cout << "song was not lengthened, no update of drive usage needed." << endl;
2185#endif
2186 }
2187 parentfs->commit();
2188}