diff options
Diffstat (limited to 'src/lib/hd24project.cpp')
-rwxr-xr-x | src/lib/hd24project.cpp | 477 |
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" | ||
12 | void 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 | |||
24 | hd24project::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 | |||
58 | hd24project::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 | |||
87 | hd24project::~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 | |||
95 | string* 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 | |||
121 | void hd24project::projectname(string newname) | ||
122 | { | ||
123 | hd24fs::setname(this->buffer,newname,PROJINFO_PROJECTNAME_8,PROJINFO_PROJECTNAME); | ||
124 | return; | ||
125 | } | ||
126 | |||
127 | unsigned long hd24project::maxsongs() | ||
128 | { | ||
129 | return parentfs->maxsongsperproject(); | ||
130 | } | ||
131 | |||
132 | unsigned 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 | |||
140 | void 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 | |||
148 | void 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 | |||
172 | signed 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 | |||
223 | hd24song* 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 | |||
231 | void 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 | |||
250 | void 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 | |||
285 | hd24song* 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 | |||
434 | void 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 | } | ||