aboutsummaryrefslogtreecommitdiff
path: root/src/lib/hd24project.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/hd24project.cpp')
-rwxr-xr-xsrc/lib/hd24project.cpp477
1 files changed, 477 insertions, 0 deletions
diff --git a/src/lib/hd24project.cpp b/src/lib/hd24project.cpp
new file mode 100755
index 0000000..1111003
--- /dev/null
+++ b/src/lib/hd24project.cpp
@@ -0,0 +1,477 @@
1#define PROJDEBUG 0
2#define PROJINFO_PROJECTNAME_8 0x0
3#define PROJINFO_SONGCOUNT 0x0c
4#define PROJINFO_LASTSONG 0x10
5#define PROJINFO_SONGLIST 0x20
6#define PROJINFO_PROJECTNAME 0x1b8
7#define INVALID_SONGENTRY 0xFFFFFFFF
8#define RESULT_SUCCESS 0
9#define RESULT_FAIL 1
10#include <hd24utils.h>
11#include "memutils.h"
12void hd24project::initvars(hd24fs* p_parent,__sint32 p_myprojectid)
13{
14 this->myprojectid=p_myprojectid;
15 this->parentfs = p_parent;
16 return;
17}
18
19__sint32 hd24project::projectid()
20{
21 return this->myprojectid;
22}
23
24hd24project::hd24project(hd24fs* p_parent, __sint32 p_myprojectid,
25 __uint32 p_projectsector, const char* p_projectname,
26 bool isnew)
27{
28#if (PROJDEBUG == 1)
29 cout << "CONSTRUCT hd24project " << p_myprojectid << endl;
30#endif
31 // initialize a new project.
32 // Boolean is obligatory to prevent accidents;
33 // one can still create a project and not save it immediately.
34 this->myprojectid = p_myprojectid;
35 buffer = (unsigned char*)memutils::mymalloc("hd24project(1)",1024,1);
36 parentfs = p_parent;
37 if (!isnew) {
38 p_parent->readsector(p_parent->devhd24,
39 p_parent->getprojectsectornum(myprojectid),
40 buffer); // fstfix follows
41
42 p_parent->fstfix(buffer, 512);
43 projectname(p_projectname);
44 } else {
45#if (PROJDEBUG == 1)
46 cout << "Create new project " <<projectname << " with id "
47 << p_myprojectid << " on sec " <<p_projectsector << endl;
48#endif
49
50 for (int i=0;i<1024;i++) {
51 buffer[i]=0;
52 }
53 projectname(p_projectname);
54 this->save(p_projectsector);
55 }
56}
57
58hd24project::hd24project(hd24fs* p_parent, __sint32 p_myprojectid)
59{
60 // project id is 1-based
61#if (PROJDEBUG == 1)
62 cout << "Here we are. time to create the project object for proj. "
63 << p_myprojectid << endl;
64#endif
65 this->myprojectid = p_myprojectid;
66 buffer = (unsigned char*)memutils::mymalloc("hd24project(2)",1024,1);
67 if (buffer==NULL) {
68 return;
69 }
70 parentfs = p_parent;
71 __uint32 projsecnum=p_parent->getprojectsectornum(myprojectid);
72 if (projsecnum==0) {
73 for (int i=0;i<512;i++) {
74 buffer[i]=0;
75 }
76 } else {
77 p_parent->readsector(p_parent->devhd24,
78 projsecnum,
79 buffer); // fstfix follows
80
81 p_parent->fstfix(buffer, 512);
82 //this->sort();
83 }
84
85}
86
87hd24project::~hd24project()
88{
89#if (PROJDEBUG == 1)
90 cout << "DESTRUCT hd24project " << myprojectid << endl;
91#endif
92 if (buffer != NULL) memutils::myfree("hd24project::buffer",buffer);
93}
94
95string* hd24project::projectname()
96{
97 string* ver=parentfs->version();
98 if (*ver == "1.00")
99 {
100 delete ver;
101 // version 1.0 filesystem.
102 string* tmp = new string("");
103 string* dummy = Convert::readstring(buffer, PROJINFO_PROJECTNAME_8, 8);
104
105 *tmp += *dummy;
106 delete dummy;
107
108 if (tmp->length() == 8)
109 {
110 dummy = Convert::readstring(buffer, PROJINFO_PROJECTNAME_8 + 10, 2);
111 *tmp += *dummy;
112 delete dummy;
113 }
114
115 return tmp;
116 }
117 delete ver;
118 return Convert::readstring(buffer, PROJINFO_PROJECTNAME, 64);
119}
120
121void hd24project::projectname(string newname)
122{
123 hd24fs::setname(this->buffer,newname,PROJINFO_PROJECTNAME_8,PROJINFO_PROJECTNAME);
124 return;
125}
126
127unsigned long hd24project::maxsongs()
128{
129 return parentfs->maxsongsperproject();
130}
131
132unsigned long hd24project::getsongsectornum(int i)
133{
134 unsigned int songsec = Convert::getint32(buffer,
135 PROJINFO_SONGLIST + ((i - 1) * 4));
136 // FIXME: Check for sensible values.
137 return songsec;
138}
139
140void hd24project::setsongsectornum(int i,__uint32 sector)
141{
142 Convert::setint32(buffer,
143 PROJINFO_SONGLIST + ((i - 1) * 4),sector);
144 // FIXME: Check for sensible values.
145 return;
146}
147
148void hd24project::lastsongid(signed long songid)
149{
150 if (songid<1)
151 {
152 return;
153
154 }
155 int maxsongsperproj = maxsongs();
156 if (songid>maxsongsperproj)
157 {
158 return;
159 }
160 if (songid==lastsongid())
161 {
162 /* same 'last song id' as before-
163 nothing changes.
164 */
165 return;
166 }
167 Convert::setint32(buffer, PROJINFO_LASTSONG,getsongsectornum(songid));
168 this->save();
169 return;
170}
171
172signed long hd24project::lastsongid()
173{
174 unsigned int lastsongsec = Convert::getint32(buffer, PROJINFO_LASTSONG);
175
176 if (lastsongsec == 0)
177 {
178 return -1;
179 }
180
181 int maxsongsperproj = maxsongs();
182 for (int i = 1; i <= maxsongsperproj; i++)
183 {
184 unsigned int songsec = getsongsectornum(i);
185
186 if (songsec == lastsongsec)
187 {
188 return i;
189 }
190 }
191
192 if (maxsongsperproj >= 1)
193 {
194 return 1;
195 }
196
197 return -1;
198}
199
200__uint32 hd24project::songcount()
201{
202 if (this==NULL)
203 {
204 return 0;
205 }
206 if (myprojectid == -1)
207 {
208 return 0;
209 }
210 if (buffer==NULL) {
211 return 0;
212 }
213 __uint32 scount = Convert::getint32(buffer, PROJINFO_SONGCOUNT);
214
215 if (scount > 99)
216 {
217 return 99;
218 }
219
220 return scount;
221}
222
223hd24song* hd24project::getsong(unsigned long songid)
224{
225#if (PROJDEBUG == 1)
226 cout << "get song " << songid << endl;
227#endif
228 return new hd24song(this,songid);
229}
230
231void hd24project::save(__uint32 projsector)
232{
233#if (PROJDEBUG == 1)
234 cout << "save project info to sector " << projsector << endl;
235#endif
236 if (buffer==NULL)
237 {
238 return; // nothing to do!
239 }
240 parentfs->fstfix(buffer,512); // sector is now in native format again
241 parentfs->setsectorchecksum(buffer,0,projsector,1);
242 parentfs->writesectors(parentfs->devhd24,
243 projsector,
244 buffer,1);
245
246 parentfs->fstfix(buffer,512); // sector is now in 'fixed' format
247 parentfs->commit();
248}
249
250void hd24project::save()
251{
252 // This is capable of handling only 1-sector-per-project projects.
253 // save(projsector) is only intended for new projects.
254 __uint32 projsector=parentfs->getprojectsectornum(this->myprojectid);
255#if (PROJDEBUG == 1)
256 cout << "save project info to sector " << projsector << endl;
257#endif
258 if (projsector==0)
259 {
260 return; // safety measure
261 }
262 save(projsector);
263}
264
265__uint32 hd24project::getunusedsongslot()
266{
267 // Find the first unused song slot in the current project.
268 __uint32 unusedsongslot=INVALID_SONGENTRY;
269
270 int maxsongcount=this->maxsongs();
271 for (int j=1; j<=maxsongcount;j++)
272 {
273 // get song sector info.
274 __uint32 songsector = getsongsectornum(j);
275 if (songsector==0)
276 {
277 unusedsongslot=(j-1);
278 break;
279 }
280 }
281
282 return unusedsongslot;
283}
284
285hd24song* hd24project::createsong(const char* songname,__uint32 trackcount,
286 __uint32 samplerate)
287{
288 /* This creates a new song (with given songname)
289 on the drive (if possible).
290 NULL is returned when unsuccessful, a pointer to the
291 new song object otherwise.
292 */
293 __uint32 songslot=getunusedsongslot();
294 if (songslot==INVALID_SONGENTRY)
295 {
296 // project is full.
297 return NULL;
298 }
299
300 // Project is not full so there must be unused song sectors
301 // (if not, something seriously fishy is going on).
302 __uint32 newsongsector=this->parentfs->getunusedsongsector();
303 if (newsongsector==0)
304 {
305 // no songsector found (0 is not a valid songsector)
306 return NULL;
307 }
308
309 // So, we have got a free songsector and a free song slot.
310 unsigned char songbuf[512*7];
311 for (int i=0;i<(7*512);i++)
312 {
313 songbuf[i]=(unsigned char)(0);
314 }
315 hd24song::sectorinit(songbuf); // put some default info in there
316
317 hd24song::songname((unsigned char*)songbuf,songname);
318 string* setsongname=hd24song::songname(parentfs,songbuf);
319 delete setsongname;
320
321 hd24song::samplerate((unsigned char*)songbuf,samplerate);
322 hd24song::logical_channels((unsigned char*)songbuf,trackcount) ;// depends on samplerate
323 __uint32 songsector=newsongsector;
324
325 // - Create the empty song at the songsector
326 // (2 sectors in size)
327 // - Create empty allocation info at songsector+2
328 // (5 sectors in size)
329 // write song info to drive
330
331 parentfs->fstfix(songbuf,TOTAL_SECTORS_PER_SONG*512); // sector is now once again in native format
332 parentfs->setsectorchecksum(songbuf,0,songsector,2);
333 parentfs->setsectorchecksum(songbuf,2*512,songsector+2,5);
334 parentfs->writesectors(parentfs->devhd24,songsector,songbuf,TOTAL_SECTORS_PER_SONG);
335 parentfs->fstfix(songbuf,TOTAL_SECTORS_PER_SONG*512); // sector is now once again in fixed format
336
337 /////////////////////////////
338 // -Update the project slot info to point at that sector
339 Convert::setint32(buffer,PROJINFO_SONGLIST+(songslot*4),songsector);
340 this->lastsongid(songslot+1);
341 Convert::setint32(buffer,PROJINFO_SONGCOUNT,
342 Convert::getint32(buffer,PROJINFO_SONGCOUNT)+1);
343 this->save();
344 parentfs->refreshsongusage();
345
346 ////////////////////////
347 // Now commit the FS
348 parentfs->commit();
349
350 return getsong(songslot+1);
351}
352
353__uint32 hd24project::deletesong(__uint32 songid)
354{
355 hd24song* songtodel=this->getsong(songid);
356#if (PROJDEBUG == 1)
357 cout << "del song with id " << songid << endl;
358#endif
359 __uint32 songsector=getsongsectornum(songid);
360#if (PROJDEBUG == 1)
361 cout << "sector " << songsector << endl;
362#endif
363 songsector++; songsector--; // prevent 'variable not used' warning
364
365 if (songtodel==NULL)
366 {
367#if (PROJDEBUG == 1)
368 cout << "song to del==null " << endl;
369#endif
370 return RESULT_FAIL;
371 }
372 songtodel->songlength_in_samples(0,false);
373 songtodel->save();
374
375 // delete song from project list by shifting left
376 // all other songs...
377 for (__uint32 i=songid;i<99;i++)
378 {
379#if (PROJDEBUG == 1)
380 cout << "set new sector for song id " << i <<" to " << getsongsectornum(i+1) << endl;
381#endif
382 setsongsectornum(i,getsongsectornum(i+1));
383 }
384 setsongsectornum(99,0); // ...and clearing the last entry.
385 __uint32 scount = Convert::getint32(buffer, PROJINFO_SONGCOUNT);
386 Convert::setint32(buffer,PROJINFO_SONGCOUNT,scount-1);
387#if (PROJDEBUG == 1)
388 cout << "set new song count to " << (scount-1) << endl;
389#endif
390
391 // set 'last accessed song' to first song in list
392 // (if there are no songs anymore, this automatically
393 // results in 'last song' to be on sector zero.
394#if (PROJDEBUG ==1)
395 cout << "set default project song to song 1 with sectornum " << getsongsectornum(1) << endl;
396#endif
397 Convert::setint32(buffer, PROJINFO_LASTSONG,getsongsectornum(1));
398#if (PROJDEBUG ==1)
399 cout << "save project." << endl;
400#endif
401
402 this->save();
403#if (PROJDEBUG ==1)
404 cout << "refresh song usage table (+superblock) " << endl;
405#endif
406 parentfs->refreshsongusage(); // or calcsongusage?
407
408 unsigned char* sectors_driveusage=parentfs->getsectors_driveusage();
409
410 // now, we still have the song object songtodel,
411 // plus its original sector number.
412#if (PROJDEBUG ==1)
413 cout << "Reset song length" << endl;
414#endif
415#if (PROJDEBUG ==1)
416 cout << "Unmark used clusters " << endl;
417#endif
418 songtodel->unmark_used_clusters(sectors_driveusage);
419#if (PROJDEBUG ==1)
420 cout << "Destruct song object." << endl;
421#endif
422 delete(songtodel);
423#if (PROJDEBUG ==1)
424 cout << "Save drive usage." << endl;
425#endif
426 parentfs->savedriveusage();
427#if (PROJDEBUG ==1)
428 cout << "Commit FS" << endl;
429#endif
430 parentfs->commit();
431 return RESULT_SUCCESS;
432}
433
434void hd24project::sort()
435{
436 // a max. of 99 elements is still doable by bubble sort.
437 int songs=this->songcount();
438 if (songs<2) return; // nothing to sort!
439 string** songnames=(string**)memutils::mymalloc("hd24project::sort",99,sizeof(string*));
440 hd24song* song1=NULL;
441
442 int i, j;
443 int arrayLength = songs;
444 for (i=1;i<=arrayLength;i++)
445 {
446 song1=getsong(i);
447 songnames[i-1]=song1->songname();
448 delete song1;
449 song1=NULL;
450 }
451
452 for(i = 1; i <= arrayLength ; i++)
453 {
454 for (j=0; j < (arrayLength -1); j++)
455 {
456 int compare=strncmp(songnames[j]->c_str(),songnames[j+1]->c_str(),64);
457 if (compare>0)
458 {
459 // swap entries
460 __uint32 a=getsongsectornum(j+1);
461 __uint32 b=getsongsectornum(j+2);
462 setsongsectornum(j+2,a);
463 setsongsectornum(j+1,b);
464 string* tmp=songnames[j];
465 songnames[j]=songnames[j+1];
466 songnames[j+1]=tmp;
467 }
468 }
469 }
470
471 for (i=1;i<=arrayLength;i++)
472 {
473 free(songnames[i-1]);
474 }
475 free(songnames);
476 return;
477}