diff options
author | Mike Crute <mcrute@gmail.com> | 2015-07-28 21:02:14 -0700 |
---|---|---|
committer | Mike Crute <mcrute@gmail.com> | 2015-07-28 21:02:14 -0700 |
commit | a771c74e76a22099bbedee3ff32829c465429d90 (patch) | |
tree | 77c957b0974f96444012185e23edcc606719c54f /src | |
download | hd24tools-a771c74e76a22099bbedee3ff32829c465429d90.tar.bz2 hd24tools-a771c74e76a22099bbedee3ff32829c465429d90.tar.xz hd24tools-a771c74e76a22099bbedee3ff32829c465429d90.zip |
Diffstat (limited to 'src')
263 files changed, 31904 insertions, 0 deletions
diff --git a/src/frontend/WidgetPDial.fl b/src/frontend/WidgetPDial.fl new file mode 100644 index 0000000..5b7ec05 --- /dev/null +++ b/src/frontend/WidgetPDial.fl | |||
@@ -0,0 +1,131 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0105 | ||
3 | header_name {.h} | ||
4 | code_name {.cc} | ||
5 | decl {//Copyright (c) 2003-2005 Nasca Octavian Paul} {} | ||
6 | |||
7 | decl {//License: GNU GPL version 2 or later} {} | ||
8 | |||
9 | decl {\#include <FL/Fl_Dial.H>} {public | ||
10 | } | ||
11 | |||
12 | decl {\#include <FL/fl_draw.H>} {public | ||
13 | } | ||
14 | |||
15 | decl {\#include <stdio.h>} {public | ||
16 | } | ||
17 | |||
18 | decl {\#include <math.h>} {public | ||
19 | } | ||
20 | |||
21 | class WidgetPDial {: {public Fl_Dial} | ||
22 | } { | ||
23 | Function {WidgetPDial(int x,int y, int w, int h, const char *label=0):Fl_Dial(x,y,w,h,label)} {} { | ||
24 | code {oldvalue=0.0;} {} | ||
25 | } | ||
26 | Function {handle(int event)} {return_type int | ||
27 | } { | ||
28 | code {double dragsize,v,min=minimum(),max=maximum(); | ||
29 | int my; | ||
30 | |||
31 | switch (event){ | ||
32 | case FL_PUSH:oldvalue=value(); | ||
33 | case FL_DRAG: | ||
34 | my=-(Fl::event_y()-y()-h()/2); | ||
35 | |||
36 | dragsize=200.0; | ||
37 | if (Fl::event_state(FL_BUTTON1)==0) dragsize*=10; | ||
38 | v=oldvalue+my/dragsize*(max-min); | ||
39 | if (v<min) v=min; | ||
40 | else if (v>max) v=max; | ||
41 | |||
42 | //printf("%d %g %g\\n",my,v,oldvalue); | ||
43 | value(v); | ||
44 | value_damage(); | ||
45 | if (this->when()!=0) do_callback(); | ||
46 | return(1); | ||
47 | break; | ||
48 | case FL_RELEASE: | ||
49 | if (this->when()==0) do_callback(); | ||
50 | return(1); | ||
51 | break; | ||
52 | }; | ||
53 | return(0);} {selected | ||
54 | } | ||
55 | } | ||
56 | Function {drawgradient(int cx,int cy,int sx,double m1,double m2)} {return_type void | ||
57 | } { | ||
58 | code {for (int i=(int)(m1*sx);i<(int)(m2*sx);i++){ | ||
59 | double tmp=1.0-pow(i*1.0/sx,2.0); | ||
60 | pdialcolor(140+(int) (tmp*90),140+(int)(tmp*90),140+(int) (tmp*100)); | ||
61 | fl_arc(cx+sx/2-i/2,cy+sx/2-i/2,i,i,0,360); | ||
62 | };} {} | ||
63 | } | ||
64 | Function {draw()} {} { | ||
65 | code {int cx=x(),cy=y(),sx=w(),sy=h(); | ||
66 | |||
67 | |||
68 | //clears the button face | ||
69 | pdialcolor(190,190,200); | ||
70 | fl_pie(cx-1,cy-1,sx+2,sy+2,0,360); | ||
71 | |||
72 | //Draws the button face (gradinet) | ||
73 | drawgradient(cx,cy,sx,0.5,1.0); | ||
74 | |||
75 | double val=(value()-minimum())/(maximum()-minimum()); | ||
76 | |||
77 | //draws the scale | ||
78 | pdialcolor(220,220,250); | ||
79 | double a1=angle1(),a2=angle2(); | ||
80 | for (int i=0;i<12;i++){ | ||
81 | double a=-i/12.0*360.0-val*(a2-a1)-a1; | ||
82 | fl_pie(cx,cy,sx,sy,a+270-3,a+3+270); | ||
83 | }; | ||
84 | |||
85 | drawgradient(cx,cy,sx,0.0,0.75); | ||
86 | |||
87 | //draws the value | ||
88 | double a=-(a2-a1)*val-a1; | ||
89 | |||
90 | |||
91 | |||
92 | |||
93 | |||
94 | //draws the max and min points | ||
95 | pdialcolor(0,100,200); | ||
96 | int xp=(int)(cx+sx/2.0+sx/2.0*sin(angle1()/180.0*3.141592)); | ||
97 | int yp=(int)(cy+sy/2.0+sy/2.0*cos(angle1()/180.0*3.141592)); | ||
98 | fl_pie(xp-2,yp-2,4,4,0,360); | ||
99 | |||
100 | xp=(int)(cx+sx/2.0+sx/2.0*sin(angle2()/180.0*3.141592)); | ||
101 | yp=(int)(cy+sy/2.0+sy/2.0*cos(angle2()/180.0*3.141592)); | ||
102 | fl_pie(xp-2,yp-2,4,4,0,360); | ||
103 | |||
104 | |||
105 | |||
106 | |||
107 | |||
108 | fl_push_matrix(); | ||
109 | |||
110 | fl_translate(cx+sx/2,cy+sy/2); | ||
111 | fl_rotate(a-90.0); | ||
112 | |||
113 | fl_translate(sx/2,0); | ||
114 | |||
115 | |||
116 | fl_begin_polygon(); | ||
117 | pdialcolor(0,0,0); | ||
118 | fl_vertex(-10,-4); | ||
119 | fl_vertex(-10,4); | ||
120 | fl_vertex(0,0); | ||
121 | fl_end_polygon(); | ||
122 | |||
123 | |||
124 | fl_pop_matrix();} {} | ||
125 | } | ||
126 | Function {pdialcolor(int r,int g,int b)} {} { | ||
127 | code {if (active_r()) fl_color(r,g,b); | ||
128 | else fl_color(160-(160-r)/3,160-(160-b)/3,160-(160-b)/3);} {} | ||
129 | } | ||
130 | decl {double oldvalue;} {} | ||
131 | } | ||
diff --git a/src/frontend/dialog_choosedevice.fl b/src/frontend/dialog_choosedevice.fl new file mode 100755 index 0000000..142b5f5 --- /dev/null +++ b/src/frontend/dialog_choosedevice.fl | |||
@@ -0,0 +1,99 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0109 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <hd24devicenamegenerator.h>} {public | ||
9 | } | ||
10 | |||
11 | decl {\#include <vector>} {public | ||
12 | } | ||
13 | |||
14 | class dialog_choosedevice {open | ||
15 | } { | ||
16 | decl {int buttonclicked;} {public | ||
17 | } | ||
18 | decl {int choice_startloc;} {public | ||
19 | } | ||
20 | decl {hd24fs* currfs;} {public | ||
21 | } | ||
22 | decl {int devnums[10000];} {} | ||
23 | decl {string* devicename;} {public | ||
24 | } | ||
25 | Function {fill_devices()} {open return_type void | ||
26 | } { | ||
27 | code {hd24devicenamegenerator* dng=new hd24devicenamegenerator(); | ||
28 | |||
29 | __uint32 totnames=dng->getnumberofnames(); | ||
30 | device->add("--Use other device--",0,NULL,(void*)this); | ||
31 | int n=0; | ||
32 | for (__uint32 i=0;i<totnames;i++) | ||
33 | { | ||
34 | string* devname=dng->getdevicename(i); | ||
35 | if (currfs->isexistingdevice(devname)) | ||
36 | { | ||
37 | device->add(devname->c_str(),0,NULL,(void*)this); | ||
38 | n++; | ||
39 | devnums[n]=i; | ||
40 | } | ||
41 | delete(devname); | ||
42 | } | ||
43 | device->value(1);} {} | ||
44 | } | ||
45 | Function {make_window(hd24fs* p_currfs)} {open | ||
46 | } { | ||
47 | Fl_Window {} { | ||
48 | label {Choose HD24 device} open selected | ||
49 | xywh {389 296 590 115} type Double color 52 labelsize 12 | ||
50 | code0 {buttonclicked=0;} | ||
51 | code1 {currfs=p_currfs;} | ||
52 | code2 {currdev->value(currfs->getdevicename()->c_str());} modal visible | ||
53 | } { | ||
54 | Fl_Button button_ok { | ||
55 | label OK | ||
56 | callback {buttonclicked=1; //OK | ||
57 | if (device->value()==0) { | ||
58 | devicename=new string(otherdevice->value()); | ||
59 | } else { | ||
60 | hd24devicenamegenerator* dng=new hd24devicenamegenerator(); | ||
61 | devicename=dng->getdevicename((__uint32)devnums[device->value()]); | ||
62 | delete dng; | ||
63 | } | ||
64 | //choice_startloc=fromloc->value(); | ||
65 | //choice_endloc=toloc->value(); | ||
66 | Fl_Window * x = Fl::first_window(); | ||
67 | x->~Fl_Window();} | ||
68 | xywh {430 85 70 25} | ||
69 | } | ||
70 | Fl_Button button_cancel { | ||
71 | label Cancel | ||
72 | callback {buttonclicked=2; //Cancel | ||
73 | Fl_Window * x = Fl::first_window(); | ||
74 | x->~Fl_Window();} | ||
75 | xywh {505 85 70 25} | ||
76 | } | ||
77 | Fl_Choice device { | ||
78 | label {Choose device:} | ||
79 | callback {if (device->value()!=0) { | ||
80 | otherdevice->deactivate(); | ||
81 | } else { | ||
82 | otherdevice->activate(); | ||
83 | otherdevice->take_focus(); | ||
84 | }} open | ||
85 | xywh {115 30 460 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
86 | code0 {fill_devices();} | ||
87 | } {} | ||
88 | Fl_Input otherdevice { | ||
89 | label {Other device:} | ||
90 | xywh {115 55 460 20} labelsize 12 textsize 12 deactivate | ||
91 | code0 {o->maximum_size(64);} | ||
92 | } | ||
93 | Fl_Output currdev { | ||
94 | label {Current device:} | ||
95 | xywh {115 5 240 20} box FLAT_BOX color 53 labelsize 12 textsize 12 | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | } | ||
diff --git a/src/frontend/dialog_filesize.fl b/src/frontend/dialog_filesize.fl new file mode 100755 index 0000000..df67208 --- /dev/null +++ b/src/frontend/dialog_filesize.fl | |||
@@ -0,0 +1,131 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <FL/fl_ask.H>} {public | ||
9 | } | ||
10 | |||
11 | class dialog_filesize {open | ||
12 | } { | ||
13 | decl {int buttonclicked;} {public | ||
14 | } | ||
15 | decl {__uint32 lastsector;} {public | ||
16 | } | ||
17 | Function {make_window()} {open | ||
18 | } { | ||
19 | Fl_Window filesizewindow { | ||
20 | label {Image size} open | ||
21 | xywh {351 357 340 105} type Double color 52 labelsize 12 | ||
22 | code0 {buttonclicked=0;} modal visible | ||
23 | } { | ||
24 | Fl_Button button_ok { | ||
25 | label OK | ||
26 | callback {buttonclicked=1; //OK | ||
27 | //char dest[66]; | ||
28 | //strncpy(&dest[0],currname->value(),64); | ||
29 | //dest[64]='\\0'; | ||
30 | //itemname=new string(dest); | ||
31 | __uint64 sizeval=strtol(filesize->value(),0,10); | ||
32 | switch (sizeunit->value()) { | ||
33 | case 0: | ||
34 | sizeval*=2048; | ||
35 | break; | ||
36 | case 1: | ||
37 | sizeval*=1024*2048; | ||
38 | break; | ||
39 | default: | ||
40 | break; | ||
41 | } | ||
42 | sizeval--; | ||
43 | if (sizeval>0xFFFFFFFF) { | ||
44 | sizeval=0xFFFFFFFF; | ||
45 | } | ||
46 | this->lastsector=(__uint32)(sizeval & 0xFFFFFFFF); | ||
47 | Fl_Window * x = Fl::first_window(); | ||
48 | x->~Fl_Window();} | ||
49 | xywh {185 80 70 20} labelsize 12 | ||
50 | } | ||
51 | Fl_Button button_cancel { | ||
52 | label Cancel | ||
53 | callback {buttonclicked=2; //Cancel | ||
54 | Fl_Window * x = Fl::first_window(); | ||
55 | x->~Fl_Window();} | ||
56 | xywh {260 80 70 20} labelsize 12 | ||
57 | } | ||
58 | Fl_Input filesize { | ||
59 | label {Enter size:} | ||
60 | xywh {120 55 120 20} labelsize 12 textsize 12 | ||
61 | code0 {o->maximum_size(16);} | ||
62 | code1 {o->take_focus();} | ||
63 | } | ||
64 | Fl_Choice preset { | ||
65 | label {Select preset size} open selected | ||
66 | xywh {120 10 210 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
67 | code0 {o->value(0);} | ||
68 | } { | ||
69 | MenuItem {} { | ||
70 | label {Specified below} | ||
71 | callback {sizeunit->activate(); | ||
72 | filesize->activate();} | ||
73 | xywh {0 0 34 21} labelsize 12 | ||
74 | } | ||
75 | MenuItem {} { | ||
76 | label {DVD+R (Single layer)} | ||
77 | callback {sizeunit->value(2); | ||
78 | filesize->value("9180416"); | ||
79 | sizeunit->deactivate(); | ||
80 | filesize->deactivate();} | ||
81 | xywh {10 10 34 21} labelsize 12 | ||
82 | } | ||
83 | MenuItem {} { | ||
84 | label {DVD-R (Single layer)} | ||
85 | callback {sizeunit->value(2); | ||
86 | filesize->value("9193984"); | ||
87 | sizeunit->deactivate(); | ||
88 | filesize->deactivate();} | ||
89 | xywh {20 20 34 21} labelsize 12 | ||
90 | } | ||
91 | MenuItem {} { | ||
92 | label {DVD+R (Dual Layer)} | ||
93 | callback {sizeunit->value(2); | ||
94 | filesize->value("16695296"); | ||
95 | sizeunit->deactivate(); | ||
96 | filesize->deactivate();} | ||
97 | xywh {20 20 34 21} labelsize 12 | ||
98 | } | ||
99 | MenuItem {} { | ||
100 | label {DVD-R (Dual layer)} | ||
101 | callback {sizeunit->value(2); | ||
102 | filesize->value("16686848"); | ||
103 | sizeunit->deactivate(); | ||
104 | filesize->deactivate();} | ||
105 | xywh {30 30 34 21} labelsize 12 | ||
106 | } | ||
107 | } | ||
108 | Fl_Choice sizeunit {open | ||
109 | xywh {245 55 85 20} down_box BORDER_BOX labelsize 12 | ||
110 | code0 {o->value(1);} | ||
111 | } { | ||
112 | MenuItem {} { | ||
113 | label MB | ||
114 | xywh {10 10 34 21} | ||
115 | } | ||
116 | MenuItem {} { | ||
117 | label GB | ||
118 | xywh {20 20 34 21} | ||
119 | } | ||
120 | MenuItem {} { | ||
121 | label Sectors | ||
122 | xywh {20 20 34 21} | ||
123 | } | ||
124 | } | ||
125 | Fl_Box {} { | ||
126 | label {- OR -} | ||
127 | xywh {85 33 35 17} labelsize 12 | ||
128 | } | ||
129 | } | ||
130 | } | ||
131 | } | ||
diff --git a/src/frontend/dialog_fromto.fl b/src/frontend/dialog_fromto.fl new file mode 100755 index 0000000..2c5ecb4 --- /dev/null +++ b/src/frontend/dialog_fromto.fl | |||
@@ -0,0 +1,50 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | class dialog_fromto {open | ||
9 | } { | ||
10 | decl {int buttonclicked;} {public | ||
11 | } | ||
12 | decl {int choice_startloc;} {public | ||
13 | } | ||
14 | decl {int choice_endloc;} {public | ||
15 | } | ||
16 | Function {make_window(hd24song* currsong)} {open | ||
17 | } { | ||
18 | Fl_Window {} { | ||
19 | label {Set range} open selected | ||
20 | xywh {315 299 360 85} type Double color 52 | ||
21 | code0 {buttonclicked=0;} | ||
22 | code1 {currsong=currsong;} modal visible | ||
23 | } { | ||
24 | Fl_Button button_ok { | ||
25 | label OK | ||
26 | callback {buttonclicked=1; //OK | ||
27 | choice_startloc=fromloc->value(); | ||
28 | choice_endloc=toloc->value(); | ||
29 | Fl_Window * x = Fl::first_window(); | ||
30 | x->~Fl_Window();} | ||
31 | xywh {210 55 70 25} | ||
32 | } | ||
33 | Fl_Button button_cancel { | ||
34 | label Cancel | ||
35 | callback {buttonclicked=2; //Cancel | ||
36 | Fl_Window * x = Fl::first_window(); | ||
37 | x->~Fl_Window();} | ||
38 | xywh {285 55 70 25} | ||
39 | } | ||
40 | Fl_Choice fromloc { | ||
41 | label {From location:} open | ||
42 | xywh {115 5 240 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
43 | } {} | ||
44 | Fl_Choice toloc { | ||
45 | label {To location:} open | ||
46 | xywh {115 30 240 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
47 | } {} | ||
48 | } | ||
49 | } | ||
50 | } | ||
diff --git a/src/frontend/dialog_newproject.fl b/src/frontend/dialog_newproject.fl new file mode 100755 index 0000000..2de1335 --- /dev/null +++ b/src/frontend/dialog_newproject.fl | |||
@@ -0,0 +1,86 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <convertlib.h>} {public | ||
9 | } | ||
10 | |||
11 | class dialog_newproject {open | ||
12 | } { | ||
13 | decl {int buttonclicked;} {public | ||
14 | } | ||
15 | decl {char projectname[65];} {public | ||
16 | } | ||
17 | Function {make_window()} {open | ||
18 | } { | ||
19 | Fl_Window {} { | ||
20 | label {New project} open | ||
21 | xywh {247 417 500 85} type Double color 52 | ||
22 | code0 {buttonclicked=0;} modal visible | ||
23 | } { | ||
24 | Fl_Button button_ok { | ||
25 | label OK | ||
26 | callback { | ||
27 | for (int i=0;i<65;i++) { | ||
28 | projectname[i]=0; | ||
29 | } | ||
30 | strncpy(projectname,currname->value(),64); | ||
31 | buttonclicked=1; //OK | ||
32 | Fl_Window * x = Fl::first_window(); | ||
33 | x->~Fl_Window();} selected | ||
34 | xywh {345 60 70 20} labelsize 12 | ||
35 | } | ||
36 | Fl_Button button_cancel { | ||
37 | label Cancel | ||
38 | callback {buttonclicked=2; //Cancel | ||
39 | Fl_Window * x = Fl::first_window(); | ||
40 | x->~Fl_Window();} | ||
41 | xywh {420 60 70 20} labelsize 12 | ||
42 | } | ||
43 | Fl_Input currname { | ||
44 | label {Project name:} | ||
45 | callback {char filteredname[65]; | ||
46 | int x=strlen(o->value()); | ||
47 | if (x>64) { x=64; } | ||
48 | int src=0; | ||
49 | int filtered=0; | ||
50 | for (int i=0;i<x;i++) { | ||
51 | if ( | ||
52 | (o->value()[i]=='\\\\') | ||
53 | || (o->value()[i]=='/') | ||
54 | || (o->value()[i]==':') | ||
55 | || (o->value()[i]=='*') | ||
56 | || (o->value()[i]=='?') | ||
57 | || (o->value()[i]=='"') | ||
58 | || (o->value()[i]=='<') | ||
59 | || (o->value()[i]=='>') | ||
60 | || (o->value()[i]=='\\\\') | ||
61 | || (o->value()[i]=='|')) | ||
62 | { | ||
63 | filtered=1; | ||
64 | continue; | ||
65 | } | ||
66 | filteredname[src]=o->value()[i]; | ||
67 | src++; | ||
68 | } | ||
69 | filteredname[src]='\\0'; | ||
70 | if (filtered==1) { | ||
71 | int pos=o->position()-1; | ||
72 | if (pos<0) pos=0; | ||
73 | o->value(filteredname); | ||
74 | o->position(pos,pos); | ||
75 | }} | ||
76 | xywh {100 35 390 20} labelsize 12 when 1 textsize 12 | ||
77 | code0 {o->maximum_size(64);} | ||
78 | code1 {o->value("Proj Name"); o->take_focus();} | ||
79 | } | ||
80 | Fl_Box {} { | ||
81 | label {Please specify the name for the new project below:} | ||
82 | xywh {5 8 485 19} labelfont 1 labelsize 12 align 20 | ||
83 | } | ||
84 | } | ||
85 | } | ||
86 | } | ||
diff --git a/src/frontend/dialog_newsong.fl b/src/frontend/dialog_newsong.fl new file mode 100755 index 0000000..3974649 --- /dev/null +++ b/src/frontend/dialog_newsong.fl | |||
@@ -0,0 +1,352 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <convertlib.h>} {public | ||
9 | } | ||
10 | |||
11 | class dialog_newsong {open | ||
12 | } { | ||
13 | decl {int buttonclicked;} {public | ||
14 | } | ||
15 | decl {char songname[65];} {public | ||
16 | } | ||
17 | decl {unsigned long songlength_in_samples;} {public | ||
18 | } | ||
19 | decl {__uint32 samplerate;} {public | ||
20 | } | ||
21 | decl {__uint32 trackcount;} {public | ||
22 | } | ||
23 | decl {int mode;} {public | ||
24 | } | ||
25 | decl {int useasrange;} {public | ||
26 | } | ||
27 | decl {int locnum;} {} | ||
28 | decl {int subsecmax;} {} | ||
29 | Function {make_window()} {open | ||
30 | } { | ||
31 | Fl_Window {} { | ||
32 | label {New song} open | ||
33 | xywh {212 241 500 180} type Double color 52 | ||
34 | code0 {buttonclicked=0; mode=2; songname[0]='\\0';} | ||
35 | code1 {subsecmax=29; samplerate=44100; trackcount=24;} | ||
36 | code2 {setuiloc(0);} modal visible | ||
37 | } { | ||
38 | Fl_Button button_ok { | ||
39 | label OK | ||
40 | callback {buttonclicked=1; //OK | ||
41 | strncpy(songname,currname->value(),64); | ||
42 | songlength_in_samples=getsonglen(); | ||
43 | Fl_Window * x = Fl::first_window(); | ||
44 | x->~Fl_Window();} | ||
45 | xywh {345 155 70 20} labelsize 12 | ||
46 | } | ||
47 | Fl_Button button_cancel { | ||
48 | label Cancel | ||
49 | callback {buttonclicked=2; //Cancel | ||
50 | useasrange=0; | ||
51 | Fl_Window * x = Fl::first_window(); | ||
52 | x->~Fl_Window();} | ||
53 | xywh {420 155 70 20} labelsize 12 | ||
54 | } | ||
55 | Fl_Input hr { | ||
56 | label {Length: } | ||
57 | callback {setuiloc(getsonglen());} | ||
58 | xywh {100 130 50 20} type Int labelsize 12 textsize 12 | ||
59 | code0 {o->maximum_size(2);} | ||
60 | } | ||
61 | Fl_Input min { | ||
62 | label {:} | ||
63 | callback {setuiloc(getsonglen());} | ||
64 | xywh {160 130 45 20} type Int labelfont 1 labelsize 12 textsize 12 | ||
65 | code0 {o->maximum_size(2);} | ||
66 | } | ||
67 | Fl_Input sec { | ||
68 | label {:} | ||
69 | callback {setuiloc(getsonglen());} | ||
70 | xywh {215 130 45 20} type Int labelfont 1 labelsize 12 textsize 12 | ||
71 | code0 {o->maximum_size(2);} | ||
72 | } | ||
73 | Fl_Input subsec { | ||
74 | label {.} | ||
75 | callback {setuiloc(getsonglen());} | ||
76 | xywh {270 130 60 20} type Int labelfont 1 labelsize 12 textsize 12 | ||
77 | code0 {o->maximum_size(5);} | ||
78 | } | ||
79 | Fl_Button button_mode { | ||
80 | label Frames | ||
81 | callback {setplchan(); | ||
82 | |||
83 | mode=(mode+1)%3; | ||
84 | switch(mode) { | ||
85 | case 0: | ||
86 | { | ||
87 | o->label("Sec/100"); | ||
88 | subsecmax=99; | ||
89 | break; | ||
90 | } | ||
91 | case 1: | ||
92 | { | ||
93 | |||
94 | if ((pchan /lchan)==2) { | ||
95 | o->label("2*Sams"); | ||
96 | } else { | ||
97 | o->label("Samples"); | ||
98 | } | ||
99 | subsecmax=samplerate/(pchan/lchan); | ||
100 | break; | ||
101 | } | ||
102 | case 2: | ||
103 | { | ||
104 | o->label("Frames"); | ||
105 | subsecmax=29; | ||
106 | break; | ||
107 | } | ||
108 | } | ||
109 | setuiloc(songlength_in_samples);} | ||
110 | xywh {270 110 60 20} labelsize 12 align 18 | ||
111 | } | ||
112 | Fl_Box {} { | ||
113 | label Hr | ||
114 | xywh {100 113 50 17} labelsize 12 | ||
115 | } | ||
116 | Fl_Box {} { | ||
117 | label Min | ||
118 | xywh {160 113 45 17} labelsize 12 | ||
119 | } | ||
120 | Fl_Box {} { | ||
121 | label Sec | ||
122 | xywh {215 113 45 17} labelsize 12 | ||
123 | } | ||
124 | Fl_Input currname { | ||
125 | label {Song name:} | ||
126 | callback {char filteredname[65]; | ||
127 | int x=strlen(o->value()); | ||
128 | if (x>64) { x=64; } | ||
129 | int src=0; | ||
130 | int filtered=0; | ||
131 | for (int i=0;i<x;i++) { | ||
132 | if ( | ||
133 | (o->value()[i]=='\\\\') | ||
134 | || (o->value()[i]=='/') | ||
135 | || (o->value()[i]==':') | ||
136 | || (o->value()[i]=='*') | ||
137 | || (o->value()[i]=='?') | ||
138 | || (o->value()[i]=='"') | ||
139 | || (o->value()[i]=='<') | ||
140 | || (o->value()[i]=='>') | ||
141 | || (o->value()[i]=='\\\\') | ||
142 | || (o->value()[i]=='|')) | ||
143 | { | ||
144 | filtered=1; | ||
145 | continue; | ||
146 | } | ||
147 | filteredname[src]=o->value()[i]; | ||
148 | src++; | ||
149 | } | ||
150 | filteredname[src]='\\0'; | ||
151 | if (filtered==1) { | ||
152 | int pos=o->position()-1; | ||
153 | if (pos<0) pos=0; | ||
154 | o->value(filteredname); | ||
155 | o->position(pos,pos); | ||
156 | }} | ||
157 | xywh {100 35 390 20} labelsize 12 when 1 textsize 12 | ||
158 | code0 {o->maximum_size(64);} | ||
159 | code1 {o->value("Song Name"); o->take_focus();} | ||
160 | } | ||
161 | Fl_Choice ratechoice { | ||
162 | label {Sample rate:} open | ||
163 | xywh {100 60 145 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
164 | code0 {o->value(0);} | ||
165 | } { | ||
166 | MenuItem {} { | ||
167 | label {44100 Hz} | ||
168 | callback {samplerate=44100; setuiloc(getsonglen());} | ||
169 | xywh {35 35 36 21} labelsize 12 | ||
170 | } | ||
171 | MenuItem {} { | ||
172 | label {48000 Hz} | ||
173 | callback {samplerate=48000;setuiloc(getsonglen());} | ||
174 | xywh {45 45 36 21} labelsize 12 | ||
175 | } | ||
176 | MenuItem {} { | ||
177 | label {88200 Hz} | ||
178 | callback {samplerate=88200; setuiloc(getsonglen()); | ||
179 | if (numtracks->value()>7) | ||
180 | { | ||
181 | numtracks->value(7); | ||
182 | trackcount=12; | ||
183 | }} | ||
184 | xywh {55 55 36 21} labelsize 12 | ||
185 | } | ||
186 | MenuItem {} { | ||
187 | label {96000 Hz} | ||
188 | callback {samplerate=96000; setuiloc(getsonglen()); | ||
189 | if (numtracks->value()>7) | ||
190 | { | ||
191 | numtracks->value(7); | ||
192 | trackcount=12; | ||
193 | }} | ||
194 | xywh {65 65 36 21} labelsize 12 | ||
195 | } | ||
196 | } | ||
197 | Fl_Choice numtracks { | ||
198 | label {\# of Tracks:} open | ||
199 | xywh {100 85 145 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
200 | code0 {o->value(10);} | ||
201 | } { | ||
202 | MenuItem {} { | ||
203 | label 1 | ||
204 | callback {trackcount=1;} | ||
205 | xywh {45 45 36 21} labelsize 12 | ||
206 | } | ||
207 | MenuItem {} { | ||
208 | label 2 | ||
209 | callback {trackcount=2;} | ||
210 | xywh {55 55 36 21} labelsize 12 | ||
211 | } | ||
212 | MenuItem {} { | ||
213 | label 3 | ||
214 | callback {trackcount=3;} | ||
215 | xywh {65 65 36 21} labelsize 12 | ||
216 | } | ||
217 | MenuItem {} { | ||
218 | label 4 | ||
219 | callback {trackcount=4;} | ||
220 | xywh {75 75 36 21} labelsize 12 | ||
221 | } | ||
222 | MenuItem {} { | ||
223 | label 6 | ||
224 | callback {trackcount=6;} | ||
225 | xywh {85 85 36 21} labelsize 12 | ||
226 | } | ||
227 | MenuItem {} { | ||
228 | label 8 | ||
229 | callback {trackcount=8;} | ||
230 | xywh {95 95 36 21} labelsize 12 | ||
231 | } | ||
232 | MenuItem {} { | ||
233 | label 9 | ||
234 | callback {trackcount=9;} | ||
235 | xywh {105 105 36 21} labelsize 12 | ||
236 | } | ||
237 | MenuItem {} { | ||
238 | label 12 | ||
239 | callback {trackcount=12;} | ||
240 | xywh {105 105 36 21} labelsize 12 | ||
241 | } | ||
242 | MenuItem {} { | ||
243 | label 16 | ||
244 | callback {trackcount=16; | ||
245 | if (samplerate>=88200) | ||
246 | { | ||
247 | trackcount=12; | ||
248 | numtracks->value(7); | ||
249 | }} | ||
250 | xywh {115 115 36 21} labelsize 12 | ||
251 | } | ||
252 | MenuItem {} { | ||
253 | label 18 | ||
254 | callback {trackcount=18; | ||
255 | if (samplerate>=88200) | ||
256 | { | ||
257 | trackcount=12; | ||
258 | numtracks->value(7); | ||
259 | }} | ||
260 | xywh {125 125 36 21} labelsize 12 | ||
261 | } | ||
262 | MenuItem {} { | ||
263 | label 24 | ||
264 | callback {trackcount=24; | ||
265 | if (samplerate>=88200) | ||
266 | { | ||
267 | trackcount=12; | ||
268 | numtracks->value(7); | ||
269 | }} | ||
270 | xywh {135 135 36 21} labelsize 12 | ||
271 | } | ||
272 | } | ||
273 | Fl_Box {} { | ||
274 | label {Please specify the parameters for the new song below:} | ||
275 | xywh {5 8 485 19} labelfont 1 labelsize 12 align 20 | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | Function {setuiloc(__uint32 offset)} {open return_type void | ||
280 | } { | ||
281 | code {setplchan(); | ||
282 | unsigned int chmult=(pchan/lchan); | ||
283 | unsigned long realrate=samplerate/chmult; | ||
284 | |||
285 | string* strhr=Convert::int2str(hd24song::display_hours(offset,realrate)); | ||
286 | hr->value(strhr->c_str()); | ||
287 | delete strhr; | ||
288 | |||
289 | string* strmin=Convert::int2str(hd24song::display_minutes(offset,realrate)); | ||
290 | min->value(strmin->c_str()); | ||
291 | delete strmin; | ||
292 | |||
293 | string* strsec=Convert::int2str(hd24song::display_seconds(offset,realrate)); | ||
294 | sec->value(strsec->c_str()); | ||
295 | delete strsec; | ||
296 | |||
297 | string* strsubsec; | ||
298 | |||
299 | long subseconds=hd24song::display_subseconds(offset,realrate); | ||
300 | long subsecval; | ||
301 | setplchan(); | ||
302 | |||
303 | switch(mode) { | ||
304 | case 0: subsecval=((subseconds*100)/ realrate ); break; | ||
305 | case 1: subsecval=(subseconds); break; | ||
306 | case 2: subsecval=((subseconds*30)/realrate ); break; | ||
307 | default: subsecval=0; | ||
308 | } | ||
309 | strsubsec=Convert::int2str(subsecval); | ||
310 | subsec->value(strsubsec->c_str()); | ||
311 | delete strsubsec;} {} | ||
312 | } | ||
313 | Function {setplchan()} {open | ||
314 | } { | ||
315 | code {lchan = trackcount; | ||
316 | if (this->samplerate>=88200) { | ||
317 | pchan=lchan*2; | ||
318 | } else { | ||
319 | pchan=lchan; | ||
320 | }} {} | ||
321 | } | ||
322 | decl {int pchan;} {} | ||
323 | decl {int lchan;} {} | ||
324 | Function {getsonglen()} {open return_type __uint32 | ||
325 | } { | ||
326 | code {setplchan(); | ||
327 | unsigned int chmult=(pchan/lchan); | ||
328 | unsigned long realrate=samplerate/chmult; | ||
329 | |||
330 | long frames=0; | ||
331 | switch(mode) { | ||
332 | case 0: frames=100; break; | ||
333 | case 1: frames=realrate; break; | ||
334 | case 2: frames=30; break; | ||
335 | } | ||
336 | |||
337 | __uint64 mylocpoint=((__uint64)3600* (__uint64)strtol( hr->value(),0,10) ) | ||
338 | +((__uint64) 60* (__uint64)strtol(min->value(),0,10) ) | ||
339 | +((__uint64) 1* (__uint64)strtol(sec->value(),0,10) ) | ||
340 | ; | ||
341 | |||
342 | mylocpoint=(__uint64)((__uint64)realrate*(__uint64)mylocpoint); | ||
343 | |||
344 | mylocpoint+=(__uint64)(strtol(subsec->value(),0,10)*samplerate/(frames*chmult)); | ||
345 | |||
346 | if (mylocpoint>0xFFFFFFFF) { | ||
347 | mylocpoint=0xFFFFFFFF; | ||
348 | } | ||
349 | return (__uint32)mylocpoint;} {selected | ||
350 | } | ||
351 | } | ||
352 | } | ||
diff --git a/src/frontend/dialog_options.fl b/src/frontend/dialog_options.fl new file mode 100755 index 0000000..39a3a54 --- /dev/null +++ b/src/frontend/dialog_options.fl | |||
@@ -0,0 +1,131 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <FL/fl_ask.H>} {public | ||
9 | } | ||
10 | |||
11 | class dialog_options {open | ||
12 | } { | ||
13 | decl {int buttonclicked;} {public | ||
14 | } | ||
15 | decl {hd24song* currsong;} {} | ||
16 | decl {string* itemname;} {public | ||
17 | } | ||
18 | Function {~dialog_options()} {open | ||
19 | } { | ||
20 | code {if (itemname!=NULL) delete itemname;} {} | ||
21 | } | ||
22 | decl {int locnum;} {} | ||
23 | Function {make_window()} {open | ||
24 | } { | ||
25 | Fl_Window optionswindow { | ||
26 | label options open | ||
27 | xywh {420 519 565 145} type Double color 52 hide | ||
28 | code0 {buttonclicked=0;} modal | ||
29 | } { | ||
30 | Fl_Tabs {} {open | ||
31 | xywh {0 0 565 145} | ||
32 | } { | ||
33 | Fl_Group {} { | ||
34 | label Catalog open | ||
35 | xywh {0 20 565 125} labelsize 12 hide | ||
36 | } { | ||
37 | Fl_Check_Button {} { | ||
38 | label {Include locate point information in drive catalog} | ||
39 | xywh {5 25 550 15} down_box DOWN_BOX labelsize 12 deactivate | ||
40 | } | ||
41 | Fl_Button button_catalogapply { | ||
42 | label Apply | ||
43 | callback {buttonclicked=1; //OK | ||
44 | char dest[66]; | ||
45 | strncpy(&dest[0],currname->value(),64); | ||
46 | dest[64]='\\0'; | ||
47 | itemname=new string(dest); | ||
48 | Fl_Window * x = Fl::first_window(); | ||
49 | x->~Fl_Window();} | ||
50 | xywh {480 110 70 20} labelsize 12 | ||
51 | } | ||
52 | Fl_Check_Button {} { | ||
53 | label {Keep catalog sorted alphabetically} | ||
54 | xywh {5 45 550 15} down_box DOWN_BOX labelsize 12 deactivate | ||
55 | } | ||
56 | } | ||
57 | Fl_Group {} { | ||
58 | label Transfers open | ||
59 | xywh {0 20 565 125} labelsize 12 | ||
60 | } { | ||
61 | Fl_Button button_ok { | ||
62 | label Apply | ||
63 | callback {buttonclicked=1; //OK | ||
64 | char dest[66]; | ||
65 | strncpy(&dest[0],currname->value(),64); | ||
66 | dest[64]='\\0'; | ||
67 | itemname=new string(dest); | ||
68 | Fl_Window * x = Fl::first_window(); | ||
69 | x->~Fl_Window();} | ||
70 | xywh {480 110 70 20} labelsize 12 | ||
71 | } | ||
72 | Fl_Input currname { | ||
73 | label {Output file name:} | ||
74 | callback {char filteredname[65]; | ||
75 | int x=strlen(o->value()); | ||
76 | if (x>64) { x=64; } | ||
77 | int src=0; | ||
78 | int filtered=0; | ||
79 | for (int i=0;i<x;i++) { | ||
80 | if ( | ||
81 | (o->value()[i]=='\\\\') | ||
82 | || (o->value()[i]=='/') | ||
83 | || (o->value()[i]==':') | ||
84 | || (o->value()[i]=='*') | ||
85 | || (o->value()[i]=='?') | ||
86 | || (o->value()[i]=='"') | ||
87 | || (o->value()[i]=='<') | ||
88 | || (o->value()[i]=='>') | ||
89 | || (o->value()[i]=='\\\\') | ||
90 | || (o->value()[i]=='|')) | ||
91 | { | ||
92 | filtered=1; | ||
93 | continue; | ||
94 | } | ||
95 | filteredname[src]=o->value()[i]; | ||
96 | src++; | ||
97 | } | ||
98 | filteredname[src]='\\0'; | ||
99 | if (filtered==1) { | ||
100 | int pos=o->position()-1; | ||
101 | if (pos<0) pos=0; | ||
102 | o->value(filteredname); | ||
103 | o->position(pos,pos); | ||
104 | }} | ||
105 | xywh {120 25 435 20} labelsize 12 when 1 textsize 12 | ||
106 | code0 {o->maximum_size(64);} | ||
107 | code1 {o->take_focus();} | ||
108 | } | ||
109 | Fl_Button button_transferhelp { | ||
110 | label Help | ||
111 | callback {fl_message("The following special sequences can be used:\\n" | ||
112 | "<drivename>\\t\\tThe volume label of the drive\\n" | ||
113 | "<projname>\\t\\tThe name of the project\\n" | ||
114 | "<songname>\\t\\tThe name of the song\\n" | ||
115 | "<projnum>\\t\\tThe sequence number of the project on disk\\n" | ||
116 | "<songnum>\\t\\tThe sequence number of the song within the project\\n" | ||
117 | "<tracknum>\\t\\tThe track number being transferred\\n" | ||
118 | "<tracknum+offset>\\tLikewise, prompt for offset before transfer\\n" | ||
119 | "<timestamp>\\t\\tCurrent date/time (YYYY-MM-DD HH:MI:SS)\\n" | ||
120 | );} selected | ||
121 | xywh {405 110 70 20} labelsize 12 | ||
122 | } | ||
123 | } | ||
124 | } | ||
125 | } | ||
126 | } | ||
127 | Function {dialog_options()} {open | ||
128 | } { | ||
129 | code {itemname=NULL;} {} | ||
130 | } | ||
131 | } | ||
diff --git a/src/frontend/dialog_rate.fl b/src/frontend/dialog_rate.fl new file mode 100755 index 0000000..9f397bf --- /dev/null +++ b/src/frontend/dialog_rate.fl | |||
@@ -0,0 +1,58 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <FL/fl_ask.H>} {public | ||
9 | } | ||
10 | |||
11 | class dialog_rename {open | ||
12 | } { | ||
13 | decl {int buttonclicked;} {public | ||
14 | } | ||
15 | decl {hd24song* currsong;} {} | ||
16 | decl {string* itemname;} {public | ||
17 | } | ||
18 | Function {~dialog_rename()} {open | ||
19 | } { | ||
20 | code {if (itemname!=NULL) delete itemname;} {} | ||
21 | } | ||
22 | decl {int locnum;} {} | ||
23 | Function {make_window(string* p_currname,string* p_title)} {open | ||
24 | } { | ||
25 | Fl_Window renamewindow { | ||
26 | label {Sample rate} open | ||
27 | xywh {277 310 490 75} type Double color 52 | ||
28 | code0 {buttonclicked=0;} | ||
29 | code1 {currname->value(p_currname->c_str());} | ||
30 | code2 {o->label(p_title->c_str());} modal visible | ||
31 | } { | ||
32 | Fl_Button button_ok { | ||
33 | label OK | ||
34 | callback {buttonclicked=1; //OK | ||
35 | char dest[66]; | ||
36 | strncpy(&dest[0],currname->value(),64); | ||
37 | dest[64]='\\0'; | ||
38 | itemname=new string(dest); | ||
39 | Fl_Window * x = Fl::first_window(); | ||
40 | x->~Fl_Window();} | ||
41 | xywh {330 40 70 25} | ||
42 | } | ||
43 | Fl_Button button_cancel { | ||
44 | label Cancel | ||
45 | callback {buttonclicked=2; //Cancel | ||
46 | Fl_Window * x = Fl::first_window(); | ||
47 | x->~Fl_Window();} | ||
48 | xywh {405 40 70 25} | ||
49 | } | ||
50 | Fl_Input currname { | ||
51 | label {New rate:} selected | ||
52 | xywh {90 10 385 20} labelsize 12 textsize 12 | ||
53 | code0 {o->maximum_size(64);} | ||
54 | code1 {o->take_focus();} | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | } | ||
diff --git a/src/frontend/dialog_rename.fl b/src/frontend/dialog_rename.fl new file mode 100755 index 0000000..d7bd419 --- /dev/null +++ b/src/frontend/dialog_rename.fl | |||
@@ -0,0 +1,89 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <FL/fl_ask.H>} {public | ||
9 | } | ||
10 | |||
11 | class dialog_rename {open | ||
12 | } { | ||
13 | decl {int buttonclicked;} {public | ||
14 | } | ||
15 | decl {hd24song* currsong;} {} | ||
16 | decl {string* itemname;} {public | ||
17 | } | ||
18 | Function {~dialog_rename()} {open | ||
19 | } { | ||
20 | code {if (itemname!=NULL) delete itemname;} {} | ||
21 | } | ||
22 | decl {int locnum;} {} | ||
23 | Function {make_window(string* p_currname,string* p_title)} {open | ||
24 | } { | ||
25 | Fl_Window renamewindow { | ||
26 | label Rename open | ||
27 | xywh {111 127 490 75} type Double color 52 | ||
28 | code0 {buttonclicked=0;} | ||
29 | code1 {currname->value(p_currname->c_str());} | ||
30 | code2 {o->label(p_title->c_str());} modal visible | ||
31 | } { | ||
32 | Fl_Button button_ok { | ||
33 | label OK | ||
34 | callback {buttonclicked=1; //OK | ||
35 | char dest[66]; | ||
36 | strncpy(&dest[0],currname->value(),64); | ||
37 | dest[64]='\\0'; | ||
38 | itemname=new string(dest); | ||
39 | Fl_Window * x = Fl::first_window(); | ||
40 | x->~Fl_Window();} | ||
41 | xywh {330 40 70 25} | ||
42 | } | ||
43 | Fl_Button button_cancel { | ||
44 | label Cancel | ||
45 | callback {buttonclicked=2; //Cancel | ||
46 | Fl_Window * x = Fl::first_window(); | ||
47 | x->~Fl_Window();} | ||
48 | xywh {405 40 70 25} | ||
49 | } | ||
50 | Fl_Input currname { | ||
51 | label {New Name:} | ||
52 | callback {char filteredname[65]; | ||
53 | int x=strlen(o->value()); | ||
54 | if (x>64) { x=64; } | ||
55 | int src=0; | ||
56 | int filtered=0; | ||
57 | for (int i=0;i<x;i++) { | ||
58 | if ( | ||
59 | (o->value()[i]=='\\\\') | ||
60 | || (o->value()[i]=='/') | ||
61 | || (o->value()[i]==':') | ||
62 | || (o->value()[i]=='*') | ||
63 | || (o->value()[i]=='?') | ||
64 | || (o->value()[i]=='"') | ||
65 | || (o->value()[i]=='<') | ||
66 | || (o->value()[i]=='>') | ||
67 | || (o->value()[i]=='\\\\') | ||
68 | || (o->value()[i]=='|')) | ||
69 | { | ||
70 | filtered=1; | ||
71 | continue; | ||
72 | } | ||
73 | filteredname[src]=o->value()[i]; | ||
74 | src++; | ||
75 | } | ||
76 | filteredname[src]='\\0'; | ||
77 | if (filtered==1) { | ||
78 | int pos=o->position()-1; | ||
79 | if (pos<0) pos=0; | ||
80 | o->value(filteredname); | ||
81 | o->position(pos,pos); | ||
82 | }} selected | ||
83 | xywh {90 10 385 20} labelsize 12 when 1 textsize 12 | ||
84 | code0 {o->maximum_size(64);} | ||
85 | code1 {o->take_focus();} | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | } | ||
diff --git a/src/frontend/dialog_setlength.fl b/src/frontend/dialog_setlength.fl new file mode 100755 index 0000000..1927f95 --- /dev/null +++ b/src/frontend/dialog_setlength.fl | |||
@@ -0,0 +1,204 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <convertlib.h>} {public | ||
9 | } | ||
10 | |||
11 | class dialog_setlength {open | ||
12 | } { | ||
13 | decl {int buttonclicked;} {public | ||
14 | } | ||
15 | decl {unsigned long locpoint;} {public | ||
16 | } | ||
17 | decl {int mode;} {public | ||
18 | } | ||
19 | decl {int useasrange;} {public | ||
20 | } | ||
21 | decl {hd24song* currsong;} {} | ||
22 | decl {int locnum;} {} | ||
23 | decl {int subsecmax;} {} | ||
24 | Function {make_window(hd24song* p_currsong,int p_locnum)} {open | ||
25 | } { | ||
26 | Fl_Window {} { | ||
27 | label {Set song length} open selected | ||
28 | xywh {160 246 455 300} type Double color 52 | ||
29 | code0 {currsong=p_currsong; buttonclicked=0; mode=2;} | ||
30 | code1 {locpoint=currsong->songlength_in_samples();} | ||
31 | code2 {setuiloc(locpoint); subsecmax=29;} | ||
32 | code3 {p_locnum=p_locnum;} modal visible | ||
33 | } { | ||
34 | Fl_Button button_ok { | ||
35 | label OK | ||
36 | callback {buttonclicked=1; //OK | ||
37 | Fl_Window * x = Fl::first_window(); | ||
38 | x->~Fl_Window();} | ||
39 | xywh {300 270 70 20} labelsize 12 | ||
40 | } | ||
41 | Fl_Button button_cancel { | ||
42 | label Cancel | ||
43 | callback {buttonclicked=2; //Cancel | ||
44 | useasrange=0; | ||
45 | Fl_Window * x = Fl::first_window(); | ||
46 | x->~Fl_Window();} | ||
47 | xywh {375 270 70 20} labelsize 12 | ||
48 | } | ||
49 | Fl_Input hr { | ||
50 | label {New song length: } | ||
51 | callback {unsigned int chmult=(currsong->physical_channels()/currsong->logical_channels()); | ||
52 | unsigned long realrate=currsong->samplerate()/chmult; | ||
53 | |||
54 | locpoint-=(unsigned long)(3600*realrate*(currsong->display_hours(locpoint))); | ||
55 | locpoint+=(unsigned long)(3600*realrate*(strtol(hr->value(),0,10))); | ||
56 | setuiloc(locpoint);} | ||
57 | xywh {150 65 50 20} type Int labelsize 12 textsize 12 | ||
58 | code0 {o->maximum_size(2);} | ||
59 | } | ||
60 | Fl_Input min { | ||
61 | label {:} | ||
62 | callback {unsigned int chmult=(currsong->physical_channels()/currsong->logical_channels()); | ||
63 | unsigned long realrate=currsong->samplerate()/chmult; | ||
64 | |||
65 | locpoint-=(unsigned long)(60*realrate*(currsong->display_minutes(locpoint))); | ||
66 | locpoint+=(unsigned long)(60*realrate*(strtol(min->value(),0,10))); | ||
67 | setuiloc(locpoint);} | ||
68 | xywh {210 65 45 20} type Int labelfont 1 labelsize 12 textsize 12 | ||
69 | code0 {o->maximum_size(2);} | ||
70 | } | ||
71 | Fl_Input sec { | ||
72 | label {:} | ||
73 | callback {unsigned int chmult=(currsong->physical_channels()/currsong->logical_channels()); | ||
74 | unsigned long realrate=currsong->samplerate()/chmult; | ||
75 | |||
76 | locpoint-=(unsigned long)(realrate*(currsong->display_seconds(locpoint))); | ||
77 | locpoint+=(unsigned long)(realrate*(strtol(sec->value(),0,10))); | ||
78 | setuiloc(locpoint);} | ||
79 | xywh {265 65 45 20} type Int labelfont 1 labelsize 12 textsize 12 | ||
80 | code0 {o->maximum_size(2);} | ||
81 | } | ||
82 | Fl_Input subsec { | ||
83 | label {.} | ||
84 | callback {if (strtol(subsec->value(),0,10)>subsecmax) { | ||
85 | string* strmax=Convert::int2str(subsecmax); | ||
86 | subsec->value(strmax->c_str()); | ||
87 | delete strmax; | ||
88 | |||
89 | } | ||
90 | |||
91 | unsigned int chmult=(currsong->physical_channels()/currsong->logical_channels()); | ||
92 | unsigned long realrate=currsong->samplerate()/chmult; | ||
93 | |||
94 | long subseconds=currsong->display_subseconds(locpoint); | ||
95 | |||
96 | locpoint-=subseconds; | ||
97 | |||
98 | long frames=0; | ||
99 | switch(mode) { | ||
100 | case 0: frames=100; break; | ||
101 | case 1: frames=realrate; break; | ||
102 | case 2: frames=30; break; | ||
103 | } | ||
104 | locpoint+=(unsigned long)(strtol(subsec->value(),0,10)*currsong->samplerate()/(frames*chmult)); | ||
105 | setuiloc(locpoint);} | ||
106 | xywh {320 65 60 20} type Int labelfont 1 labelsize 12 textsize 12 | ||
107 | code0 {o->maximum_size(5);} | ||
108 | } | ||
109 | Fl_Button button_mode { | ||
110 | label Frames | ||
111 | callback {mode=(mode+1)%3; | ||
112 | switch(mode) { | ||
113 | case 0: | ||
114 | { | ||
115 | o->label("Sec/100"); | ||
116 | subsecmax=99; | ||
117 | break; | ||
118 | } | ||
119 | case 1: | ||
120 | { | ||
121 | |||
122 | if ((currsong->physical_channels()/currsong->logical_channels())==2) { | ||
123 | o->label("2*Sams"); | ||
124 | } else { | ||
125 | o->label("Samples"); | ||
126 | } | ||
127 | subsecmax=currsong->samplerate()/(currsong->physical_channels()/currsong->logical_channels()); | ||
128 | break; | ||
129 | } | ||
130 | case 2: | ||
131 | { | ||
132 | o->label("Frames"); | ||
133 | subsecmax=29; | ||
134 | break; | ||
135 | } | ||
136 | } | ||
137 | setuiloc(locpoint);} | ||
138 | xywh {320 45 60 20} labelsize 12 align 18 | ||
139 | } | ||
140 | Fl_Box {} { | ||
141 | label Hr | ||
142 | xywh {150 48 50 17} labelsize 12 | ||
143 | } | ||
144 | Fl_Box {} { | ||
145 | label Min | ||
146 | xywh {210 48 45 17} labelsize 12 | ||
147 | } | ||
148 | Fl_Box {} { | ||
149 | label Sec | ||
150 | xywh {265 48 45 17} labelsize 12 | ||
151 | } | ||
152 | Fl_Box {} { | ||
153 | label {Set the approximate song length here. Round up when unsure.} | ||
154 | xywh {5 5 440 30} labelsize 12 align 20 | ||
155 | } | ||
156 | Fl_Box {} { | ||
157 | label {Note: This operation will requires about 40 MB of free space to write | ||
158 | recovery information to a header file on your computer. | ||
159 | |||
160 | This operation WILL NOT write to your HD24 drive, and as such should | ||
161 | be completely safe, while permitting you to save your missing audio. | ||
162 | Once this operation is complete, you should TRANSFER ALL AUDIO | ||
163 | that you want to keep from the HD24 drive and then re-format it, | ||
164 | before recording any more audio to it. | ||
165 | |||
166 | Cancel this dialog if you're not in need of a recovery.} | ||
167 | xywh {5 100 440 160} labelsize 12 align 21 | ||
168 | } | ||
169 | } | ||
170 | } | ||
171 | Function {setuiloc(unsigned long offset)} {open return_type void | ||
172 | } { | ||
173 | code {unsigned long maxoffset=0xFFFFFFFF; | ||
174 | if (offset>maxoffset) { | ||
175 | offset=maxoffset; | ||
176 | locpoint=offset; | ||
177 | } | ||
178 | string* strhr=Convert::int2str(currsong->display_hours(offset)); | ||
179 | hr->value(strhr->c_str()); | ||
180 | delete strhr; | ||
181 | |||
182 | string* strmin=Convert::int2str(currsong->display_minutes(offset)); | ||
183 | min->value(strmin->c_str()); | ||
184 | delete strmin; | ||
185 | |||
186 | string* strsec=Convert::int2str(currsong->display_seconds(offset)); | ||
187 | sec->value(strsec->c_str()); | ||
188 | delete strsec; | ||
189 | |||
190 | string* strsubsec; | ||
191 | |||
192 | long subseconds=currsong->display_subseconds(offset); | ||
193 | long subsecval; | ||
194 | switch(mode) { | ||
195 | case 0: subsecval=((subseconds*100)/ ( currsong->samplerate()/ (currsong->physical_channels()/currsong->logical_channels()) ) ); break; | ||
196 | case 1: subsecval=(subseconds); break; | ||
197 | case 2: subsecval=((subseconds*30)/( currsong->samplerate()/ (currsong->physical_channels()/currsong->logical_channels()) ) ); ; break; | ||
198 | default: subsecval=0; | ||
199 | } | ||
200 | strsubsec=Convert::int2str(subsecval); | ||
201 | subsec->value(strsubsec->c_str()); | ||
202 | delete strsubsec;} {} | ||
203 | } | ||
204 | } | ||
diff --git a/src/frontend/dialog_setlocate.fl b/src/frontend/dialog_setlocate.fl new file mode 100755 index 0000000..30de1a6 --- /dev/null +++ b/src/frontend/dialog_setlocate.fl | |||
@@ -0,0 +1,209 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <hd24fs.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <convertlib.h>} {public | ||
9 | } | ||
10 | |||
11 | class dialog_setlocate {open | ||
12 | } { | ||
13 | decl {int buttonclicked;} {public | ||
14 | } | ||
15 | decl {unsigned long locpoint;} {public | ||
16 | } | ||
17 | decl {int mode;} {public | ||
18 | } | ||
19 | decl {int useasrange;} {public | ||
20 | } | ||
21 | decl {hd24song* currsong;} {} | ||
22 | decl {int locnum;} {} | ||
23 | decl {int subsecmax;} {} | ||
24 | Function {make_window(hd24song* p_currsong,int p_locnum)} {open | ||
25 | } { | ||
26 | Fl_Window {} { | ||
27 | label {Edit locate point} open | ||
28 | xywh {160 247 385 100} type Double color 52 | ||
29 | code0 {currsong=p_currsong; buttonclicked=0; mode=2; locnum=p_locnum;} | ||
30 | code1 {locpoint=currsong->getlocatepos(locnum); locname->value(currsong->getlocatename(locnum)->c_str());} | ||
31 | code2 {setuiloc(currsong->getlocatepos(locnum)); subsecmax=29;} | ||
32 | code3 {if ((locnum!=1) && (locnum!=2)) { setasrange->hide(); }; if (locnum==1) { setasrange->label("Set as start of export range"); } if (locnum==2) { setasrange->label("Set as end of export range"); }} modal visible | ||
33 | } { | ||
34 | Fl_Button button_ok { | ||
35 | label OK | ||
36 | callback {buttonclicked=1; //OK | ||
37 | char dest[10]; | ||
38 | strncpy(&dest[0],locname->value(),8); | ||
39 | dest[9]='\\0'; | ||
40 | string* newname=new string(dest); | ||
41 | currsong->setlocatename(locnum,*newname); | ||
42 | currsong->setlocatepos(locnum,locpoint); | ||
43 | useasrange=setasrange->value(); | ||
44 | delete newname; | ||
45 | Fl_Window * x = Fl::first_window(); | ||
46 | x->~Fl_Window();} | ||
47 | xywh {235 75 70 20} labelsize 12 | ||
48 | } | ||
49 | Fl_Button button_cancel { | ||
50 | label Cancel | ||
51 | callback {buttonclicked=2; //Cancel | ||
52 | useasrange=0; | ||
53 | Fl_Window * x = Fl::first_window(); | ||
54 | x->~Fl_Window();} | ||
55 | xywh {310 75 70 20} labelsize 12 | ||
56 | } | ||
57 | Fl_Input hr { | ||
58 | label {New locate point:} | ||
59 | callback {unsigned int chmult=(currsong->physical_channels()/currsong->logical_channels()); | ||
60 | unsigned long realrate=currsong->samplerate()/chmult; | ||
61 | |||
62 | locpoint-=(unsigned long)(3600*realrate*(currsong->display_hours(locpoint))); | ||
63 | locpoint+=(unsigned long)(3600*realrate*(strtol(hr->value(),0,10))); | ||
64 | setuiloc(locpoint);} | ||
65 | xywh {150 45 50 20} type Int labelsize 12 textsize 12 | ||
66 | code0 {o->maximum_size(2);} | ||
67 | } | ||
68 | Fl_Input min { | ||
69 | label {:} | ||
70 | callback {unsigned int chmult=(currsong->physical_channels()/currsong->logical_channels()); | ||
71 | unsigned long realrate=currsong->samplerate()/chmult; | ||
72 | |||
73 | locpoint-=(unsigned long)(60*realrate*(currsong->display_minutes(locpoint))); | ||
74 | locpoint+=(unsigned long)(60*realrate*(strtol(min->value(),0,10))); | ||
75 | setuiloc(locpoint);} | ||
76 | xywh {210 45 45 20} type Int labelfont 1 labelsize 12 textsize 12 | ||
77 | code0 {o->maximum_size(2);} | ||
78 | } | ||
79 | Fl_Input sec { | ||
80 | label {:} | ||
81 | callback {unsigned int chmult=(currsong->physical_channels()/currsong->logical_channels()); | ||
82 | unsigned long realrate=currsong->samplerate()/chmult; | ||
83 | |||
84 | locpoint-=(unsigned long)(realrate*(currsong->display_seconds(locpoint))); | ||
85 | locpoint+=(unsigned long)(realrate*(strtol(sec->value(),0,10))); | ||
86 | setuiloc(locpoint);} | ||
87 | xywh {265 45 45 20} type Int labelfont 1 labelsize 12 textsize 12 | ||
88 | code0 {o->maximum_size(2);} | ||
89 | } | ||
90 | Fl_Input subsec { | ||
91 | label {.} | ||
92 | callback {if (strtol(subsec->value(),0,10)>subsecmax) { | ||
93 | string* strmax=Convert::int2str(subsecmax); | ||
94 | subsec->value(strmax->c_str()); | ||
95 | delete strmax; | ||
96 | |||
97 | } | ||
98 | |||
99 | unsigned int chmult=(currsong->physical_channels()/currsong->logical_channels()); | ||
100 | unsigned long realrate=currsong->samplerate()/chmult; | ||
101 | |||
102 | long subseconds=currsong->display_subseconds(locpoint); | ||
103 | |||
104 | locpoint-=subseconds; | ||
105 | |||
106 | long frames=0; | ||
107 | switch(mode) { | ||
108 | case 0: frames=100; break; | ||
109 | case 1: frames=realrate; break; | ||
110 | case 2: frames=30; break; | ||
111 | } | ||
112 | locpoint+=(unsigned long)(strtol(subsec->value(),0,10)*currsong->samplerate()/(frames*chmult)); | ||
113 | setuiloc(locpoint);} | ||
114 | xywh {320 45 60 20} type Int labelfont 1 labelsize 12 textsize 12 | ||
115 | code0 {o->maximum_size(5);} | ||
116 | } | ||
117 | Fl_Button button_mode { | ||
118 | label Frames | ||
119 | callback {mode=(mode+1)%3; | ||
120 | switch(mode) { | ||
121 | case 0: | ||
122 | { | ||
123 | o->label("Sec/100"); | ||
124 | subsecmax=99; | ||
125 | break; | ||
126 | } | ||
127 | case 1: | ||
128 | { | ||
129 | |||
130 | if ((currsong->physical_channels()/currsong->logical_channels())==2) { | ||
131 | o->label("2*Sams"); | ||
132 | } else { | ||
133 | o->label("Samples"); | ||
134 | } | ||
135 | subsecmax=currsong->samplerate()/(currsong->physical_channels()/currsong->logical_channels()); | ||
136 | break; | ||
137 | } | ||
138 | case 2: | ||
139 | { | ||
140 | o->label("Frames"); | ||
141 | subsecmax=29; | ||
142 | break; | ||
143 | } | ||
144 | } | ||
145 | setuiloc(locpoint);} | ||
146 | xywh {320 25 60 20} labelsize 12 align 18 | ||
147 | } | ||
148 | Fl_Input locname { | ||
149 | label {Location Name:} | ||
150 | callback {char templabel[10]; | ||
151 | strncpy(&templabel[0],o->value(),8); | ||
152 | templabel[8]='\\0'; | ||
153 | o->value(templabel);} | ||
154 | xywh {150 5 115 20} labelsize 12 textsize 12 | ||
155 | code0 {o->maximum_size(8);} | ||
156 | } | ||
157 | Fl_Check_Button setasrange { | ||
158 | label {Set as start of export range} | ||
159 | xywh {25 75 205 20} down_box DOWN_BOX value 1 labelsize 12 | ||
160 | } | ||
161 | Fl_Box {} { | ||
162 | label Hr | ||
163 | xywh {150 28 50 17} labelsize 12 | ||
164 | } | ||
165 | Fl_Box {} { | ||
166 | label Min | ||
167 | xywh {210 28 45 17} labelsize 12 | ||
168 | } | ||
169 | Fl_Box {} { | ||
170 | label Sec | ||
171 | xywh {265 28 45 17} labelsize 12 | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | Function {setuiloc(unsigned long offset)} {open return_type void | ||
176 | } { | ||
177 | code {unsigned long maxoffset=currsong->getlocatepos(25); | ||
178 | if (offset>maxoffset) { | ||
179 | offset=maxoffset; | ||
180 | locpoint=offset; | ||
181 | } | ||
182 | string* strhr=Convert::int2str(currsong->display_hours(offset)); | ||
183 | hr->value(strhr->c_str()); | ||
184 | delete strhr; | ||
185 | |||
186 | string* strmin=Convert::int2str(currsong->display_minutes(offset)); | ||
187 | min->value(strmin->c_str()); | ||
188 | delete strmin; | ||
189 | |||
190 | string* strsec=Convert::int2str(currsong->display_seconds(offset)); | ||
191 | sec->value(strsec->c_str()); | ||
192 | delete strsec; | ||
193 | |||
194 | string* strsubsec; | ||
195 | |||
196 | long subseconds=currsong->display_subseconds(offset); | ||
197 | long subsecval; | ||
198 | switch(mode) { | ||
199 | case 0: subsecval=((subseconds*100)/ ( currsong->samplerate()/ (currsong->physical_channels()/currsong->logical_channels()) ) ); break; | ||
200 | case 1: subsecval=(subseconds); break; | ||
201 | case 2: subsecval=((subseconds*30)/( currsong->samplerate()/ (currsong->physical_channels()/currsong->logical_channels()) ) ); ; break; | ||
202 | default: subsecval=0; | ||
203 | } | ||
204 | strsubsec=Convert::int2str(subsecval); | ||
205 | subsec->value(strsubsec->c_str()); | ||
206 | delete strsubsec;} {selected | ||
207 | } | ||
208 | } | ||
209 | } | ||
diff --git a/src/frontend/hd24connect.cpp b/src/frontend/hd24connect.cpp new file mode 100755 index 0000000..b31b758 --- /dev/null +++ b/src/frontend/hd24connect.cpp | |||
@@ -0,0 +1,326 @@ | |||
1 | #define MAINDEBUG 0 | ||
2 | #include <FL/Fl.H> | ||
3 | #include <FL/Fl_Window.H> | ||
4 | #include <FL/Fl_Box.H> | ||
5 | #include "ui_hd24connect.h" | ||
6 | #include <hd24fs.h> | ||
7 | #include <hd24utils.h> | ||
8 | #include <FL/x.H> //dave | ||
9 | #ifdef LINUX | ||
10 | #include <X11/xpm.h> //dave | ||
11 | #endif | ||
12 | #include "images/hd24connect_64x64.xpm" //dave | ||
13 | #include <iostream> | ||
14 | #include <string> | ||
15 | #include <stdlib.h> | ||
16 | #include <hd24utils.h> | ||
17 | #ifndef MAX_PATH | ||
18 | #define MAX_PATH 127 | ||
19 | #endif | ||
20 | |||
21 | #ifdef WINDOWS | ||
22 | #include <windows.h> | ||
23 | #define IDI_ICON1 101 | ||
24 | #endif | ||
25 | string device; | ||
26 | string headerfilename; | ||
27 | int force; | ||
28 | int maintmode; | ||
29 | int wavefixmode; | ||
30 | int testmode; | ||
31 | #ifdef LINUX | ||
32 | #define TIMEOUT 0.03 | ||
33 | #endif | ||
34 | #define ARGDEV "--dev=" | ||
35 | #define ARGHEADER "--header=" | ||
36 | #define ARGFORCE "--force" | ||
37 | #define ARGMAINT "--maint" | ||
38 | #define ARGWAVEFIX "--wavefix" | ||
39 | #define ARGTEST "--test" | ||
40 | |||
41 | #include "selftest.cpp" | ||
42 | |||
43 | int parsecommandline(int argc, char ** argv) | ||
44 | { | ||
45 | int invalid=0; | ||
46 | force=0; | ||
47 | maintmode=0; | ||
48 | wavefixmode=0; | ||
49 | testmode=0; | ||
50 | device=""; | ||
51 | for (int c=1;c<argc;c++) { | ||
52 | |||
53 | string arg=argv[c]; | ||
54 | if (arg.substr(0,1)=="-") { | ||
55 | if (arg.substr(1,1)!="-") { | ||
56 | continue; // skip single-dash arguments | ||
57 | // for instance to skip -display | ||
58 | // and to skip macOS process number | ||
59 | } | ||
60 | } | ||
61 | if (arg.substr(0,strlen(ARGTEST))==ARGTEST) { | ||
62 | testmode=1; | ||
63 | continue; | ||
64 | } | ||
65 | if (arg.substr(0,strlen(ARGDEV))==ARGDEV) { | ||
66 | device=arg.substr(strlen(ARGDEV)); | ||
67 | continue; | ||
68 | } | ||
69 | if (arg.substr(0,strlen(ARGMAINT))==ARGMAINT) { | ||
70 | maintmode=1; | ||
71 | #if (MAINDEBUG==1) | ||
72 | cout << "Running in maintenance mode." << endl; | ||
73 | #endif | ||
74 | continue; | ||
75 | } | ||
76 | if (arg.substr(0,strlen(ARGWAVEFIX))==ARGWAVEFIX) { | ||
77 | wavefixmode=1; | ||
78 | #if (MAINDEBUG==1) | ||
79 | cout << "Running in wavefix mode." << endl; | ||
80 | #endif | ||
81 | continue; | ||
82 | } | ||
83 | if (arg.substr(0,strlen(ARGHEADER))==ARGHEADER) { | ||
84 | headerfilename=arg.substr(strlen(ARGHEADER)); | ||
85 | continue; | ||
86 | } | ||
87 | if (arg.substr(0,strlen(ARGFORCE))==(ARGFORCE)) { | ||
88 | force=1; | ||
89 | continue; | ||
90 | } | ||
91 | #ifdef DARWIN | ||
92 | // on MacOS ignore all crap on the command line | ||
93 | // (system adds process ID info etc) | ||
94 | continue; | ||
95 | #endif | ||
96 | |||
97 | #if (MAINDEBUG==1) | ||
98 | cout << "Invalid argument: " << arg << endl; | ||
99 | #endif | ||
100 | invalid=1; | ||
101 | } | ||
102 | return invalid; | ||
103 | } | ||
104 | |||
105 | int isabsolutepath(const char* pathname) { | ||
106 | if (pathname[0]=='/') return (1==1); | ||
107 | if (pathname[0]=='\\') return (1==1); | ||
108 | if (pathname[1]==':') return (1==1); | ||
109 | return (1==0); | ||
110 | } | ||
111 | |||
112 | void getprogdir(const char* currpath,const char* callpath,char* result) { | ||
113 | if (isabsolutepath(callpath)) { | ||
114 | strncpy(result,callpath,strlen(callpath)+1); | ||
115 | return; | ||
116 | } | ||
117 | strcat(result,currpath); | ||
118 | #ifdef WINDOWS | ||
119 | strcat(result,"\\\0"); | ||
120 | #else | ||
121 | strcat(result,"/\0"); | ||
122 | #endif | ||
123 | |||
124 | if (strcmp(callpath,"./")!=0) { | ||
125 | strcat(result,callpath); | ||
126 | } | ||
127 | return; | ||
128 | } | ||
129 | |||
130 | |||
131 | int main(int argc, char **argv) { | ||
132 | |||
133 | int result=0; | ||
134 | |||
135 | /* First, the program will figure out its own | ||
136 | absolute program path. This will be used | ||
137 | for loading libraries after program startup, | ||
138 | rather than having hard dependencies *during*. */ | ||
139 | char* currentworkingdir=(char*)malloc(2048); | ||
140 | #if (MAINDEBUG==1) | ||
141 | cout << "Welcome to HD24connect" << endl; | ||
142 | #endif | ||
143 | string currname=argv[0]; | ||
144 | string rawname=""; | ||
145 | #if (MAINDEBUG==1) | ||
146 | cout << "Currname=" << currname << endl; | ||
147 | #endif | ||
148 | do { | ||
149 | string lastchar=""; | ||
150 | lastchar+=currname.substr(currname.length()-1,1); | ||
151 | if ((lastchar=="/") || (lastchar=="\\")) { | ||
152 | break; | ||
153 | } | ||
154 | rawname=currname.substr(currname.length()-1,1)+rawname; | ||
155 | currname=currname.substr(0,currname.length()-1); | ||
156 | |||
157 | if (currname=="") break; | ||
158 | } while (1==1); | ||
159 | // currname=path given on commandline | ||
160 | |||
161 | char cwd[2048]; | ||
162 | char* mycwd=getcwd(&cwd[0],2048); | ||
163 | mycwd=&cwd[0]; | ||
164 | #if (MAINDEBUG==1) | ||
165 | cout << "cwd=" << cwd << endl; | ||
166 | #endif | ||
167 | char absprogpath[2048]; | ||
168 | char fullname[2048]; | ||
169 | absprogpath[0]='\0'; | ||
170 | getprogdir(&cwd[0],currname.c_str(),&absprogpath[0]); | ||
171 | |||
172 | #if (MAINDEBUG==1) | ||
173 | cout << "absprogpath=" << absprogpath << endl; | ||
174 | #endif | ||
175 | free(currentworkingdir); | ||
176 | |||
177 | /* | ||
178 | * Either absprogpath now contains absolute program path | ||
179 | * (if called from current path or by specifying path) | ||
180 | * or we need to traverse the OS PATH. | ||
181 | */ | ||
182 | strncpy(fullname,absprogpath,2048); | ||
183 | strcat(fullname,rawname.c_str()); | ||
184 | #if (MAINDEBUG==1) | ||
185 | cout << "fullname=" << fullname << endl; | ||
186 | #endif | ||
187 | if (!(hd24utils::fileExists(fullname))) { | ||
188 | /* File according to full name does not exist. */ | ||
189 | #if (MAINDEBUG==1) | ||
190 | cout << "rawname=" << rawname << ", path=" << getenv("PATH") << endl; | ||
191 | #endif | ||
192 | hd24utils::findfile(&rawname[0],getenv("PATH"),&absprogpath[0]); | ||
193 | if (strlen(absprogpath)==0) { | ||
194 | cout << "Cannot find executable. "<< endl; | ||
195 | return 0; | ||
196 | } | ||
197 | } | ||
198 | // The final word on which path contains the exe is absprogpath. | ||
199 | #if (MAINDEBUG==1) | ||
200 | cout << "The final word on where the exe is, is: " << absprogpath << endl; | ||
201 | cout << "main debugmode enabled." << endl; | ||
202 | cout << " Sizeof float=" << sizeof(float) << endl; | ||
203 | #endif | ||
204 | char initial_path[MAX_PATH]; | ||
205 | mycwd=getcwd(initial_path,MAX_PATH); | ||
206 | // This prints the path+filename to ourselves: | ||
207 | // If we run from current dir, argv is just filename; | ||
208 | // otherwise missing part of path+filename. | ||
209 | // So initial path+filename always renders the complete path. | ||
210 | int invalid=parsecommandline(argc,argv); | ||
211 | if (invalid!=0) { | ||
212 | return invalid; | ||
213 | } | ||
214 | //force=0; | ||
215 | |||
216 | hd24fs* sysob=NULL; | ||
217 | if (testmode==1) | ||
218 | { | ||
219 | #ifdef LINUX | ||
220 | fl_open_display(); | ||
221 | #endif | ||
222 | HD24UserInterface ui(argc,argv,absprogpath); | ||
223 | // testmode active- run self test. | ||
224 | result=runselftest(&ui); | ||
225 | cout << "Selftest run complete - Thank you for using HD24connect." << endl; | ||
226 | ui.finish(); | ||
227 | return result; | ||
228 | } | ||
229 | |||
230 | string* imagedir=hd24utils::getlastdir("driveimagedir"); | ||
231 | #if (MAINDEBUG==1) | ||
232 | cout << "imagedir="<<*imagedir<< endl; | ||
233 | #endif | ||
234 | if (device=="") { | ||
235 | sysob=new hd24fs(imagedir->c_str(),hd24fs::MODE_RDWR); | ||
236 | } else { | ||
237 | cout << "Trying to use " << device << " as hd24 device." << endl; | ||
238 | sysob=new hd24fs(imagedir->c_str(),hd24fs::MODE_RDWR,&device,(force==1)); | ||
239 | if (!(sysob->isOpen())) | ||
240 | { | ||
241 | if (!force) { | ||
242 | cout << "Cannot open hd24 device" << endl; | ||
243 | delete sysob; | ||
244 | return 1; | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | delete imagedir; | ||
249 | if (headerfilename!="") | ||
250 | { | ||
251 | if (!(sysob->useheaderfile(headerfilename))) | ||
252 | { | ||
253 | cout << "Couldn't load header file "<<headerfilename << endl; | ||
254 | }; | ||
255 | } | ||
256 | #if (MAINDEBUG==1) | ||
257 | cout << "mdb(2)" << endl; | ||
258 | #endif | ||
259 | // Fl::scheme("gtk+"); | ||
260 | #ifdef LINUX | ||
261 | fl_open_display(); | ||
262 | #endif | ||
263 | HD24UserInterface ui(argc,argv,absprogpath); | ||
264 | #if (MAINDEBUG==1) | ||
265 | cout << "mdb(3b)" << endl; | ||
266 | #endif | ||
267 | sysob->setmaintenancemode(maintmode); | ||
268 | sysob->setwavefixmode(wavefixmode); | ||
269 | #if (MAINDEBUG==1) | ||
270 | cout << "mdb(3c)" << endl; | ||
271 | #endif | ||
272 | Fl_Window *window = ui.make_window(sysob); | ||
273 | #if (MAINDEBUG==1) | ||
274 | cout << "mdb(3d)" << endl; | ||
275 | #endif | ||
276 | #ifdef WINDOWS | ||
277 | |||
278 | window->icon((char *)LoadIcon(fl_display,MAKEINTRESOURCE(IDI_ICON1))); | ||
279 | #endif | ||
280 | window->end(); | ||
281 | window->show(); //argc, argv); | ||
282 | |||
283 | #ifdef LINUX //dave | ||
284 | Pixmap p, mask; | ||
285 | XpmCreatePixmapFromData(fl_display,DefaultRootWindow(fl_display),(char **)hd24connect_xpm, &p, &mask, NULL); | ||
286 | |||
287 | /* | ||
288 | FLTK support for transparent background is broken. So instead of this: | ||
289 | window->icon((char *)p); | ||
290 | We will write the following: */ | ||
291 | XWMHints *hints=NULL; | ||
292 | hints = XGetWMHints(fl_display, fl_xid(window)); | ||
293 | hints->icon_pixmap = p; | ||
294 | hints->icon_mask = mask; | ||
295 | hints->flags = IconPixmapHint | IconMaskHint; | ||
296 | XSetWMHints(fl_display, fl_xid(window), hints); | ||
297 | /* -- end of transparency fix */ | ||
298 | #endif | ||
299 | #if (MAINDEBUG==1) | ||
300 | cout << "mdb(3)" << endl; | ||
301 | #endif | ||
302 | #if (MAINDEBUG==1) | ||
303 | cout << "mdb(4)" << endl; | ||
304 | #endif | ||
305 | if (!(sysob->isOpen())) | ||
306 | { | ||
307 | window->deactivate(); | ||
308 | fl_message("No valid HD24 drive is connected to the system.\nUse the File menu to resolve this problem."); | ||
309 | window->activate(); | ||
310 | } | ||
311 | // run normally. | ||
312 | result= Fl::run(); | ||
313 | ui.control->ready(0); | ||
314 | #ifndef WINDOWS | ||
315 | cout << "Thank you for using HD24connect." << endl; | ||
316 | #endif | ||
317 | // ui.finish(); | ||
318 | |||
319 | #ifdef hints | ||
320 | if (hints!=NULL) | ||
321 | { | ||
322 | delete hints; | ||
323 | } | ||
324 | #endif | ||
325 | return result; | ||
326 | } | ||
diff --git a/src/frontend/hd24connect.ico b/src/frontend/hd24connect.ico new file mode 100644 index 0000000..72a6e89 --- /dev/null +++ b/src/frontend/hd24connect.ico | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_0.gif b/src/frontend/images/7seg_0.gif new file mode 100644 index 0000000..58e66fe --- /dev/null +++ b/src/frontend/images/7seg_0.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_1.gif b/src/frontend/images/7seg_1.gif new file mode 100644 index 0000000..07c0b19 --- /dev/null +++ b/src/frontend/images/7seg_1.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_2.gif b/src/frontend/images/7seg_2.gif new file mode 100644 index 0000000..6b8061c --- /dev/null +++ b/src/frontend/images/7seg_2.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_3.gif b/src/frontend/images/7seg_3.gif new file mode 100644 index 0000000..60556e5 --- /dev/null +++ b/src/frontend/images/7seg_3.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_4.gif b/src/frontend/images/7seg_4.gif new file mode 100644 index 0000000..c3e1e96 --- /dev/null +++ b/src/frontend/images/7seg_4.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_5.gif b/src/frontend/images/7seg_5.gif new file mode 100644 index 0000000..927bf60 --- /dev/null +++ b/src/frontend/images/7seg_5.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_6.gif b/src/frontend/images/7seg_6.gif new file mode 100644 index 0000000..5dbf489 --- /dev/null +++ b/src/frontend/images/7seg_6.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_7.gif b/src/frontend/images/7seg_7.gif new file mode 100644 index 0000000..f7e215b --- /dev/null +++ b/src/frontend/images/7seg_7.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_8.gif b/src/frontend/images/7seg_8.gif new file mode 100644 index 0000000..4fd1568 --- /dev/null +++ b/src/frontend/images/7seg_8.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/7seg_9.gif b/src/frontend/images/7seg_9.gif new file mode 100644 index 0000000..42cefe9 --- /dev/null +++ b/src/frontend/images/7seg_9.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix.gif b/src/frontend/images/HD24_matrix.gif new file mode 100644 index 0000000..33dfe22 --- /dev/null +++ b/src/frontend/images/HD24_matrix.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_100.gif b/src/frontend/images/HD24_matrix_100.gif new file mode 100644 index 0000000..89fa45a --- /dev/null +++ b/src/frontend/images/HD24_matrix_100.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_101.gif b/src/frontend/images/HD24_matrix_101.gif new file mode 100644 index 0000000..b8bf231 --- /dev/null +++ b/src/frontend/images/HD24_matrix_101.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_102.gif b/src/frontend/images/HD24_matrix_102.gif new file mode 100644 index 0000000..94412f4 --- /dev/null +++ b/src/frontend/images/HD24_matrix_102.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_103.gif b/src/frontend/images/HD24_matrix_103.gif new file mode 100644 index 0000000..3e281a7 --- /dev/null +++ b/src/frontend/images/HD24_matrix_103.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_104.gif b/src/frontend/images/HD24_matrix_104.gif new file mode 100644 index 0000000..c037ce9 --- /dev/null +++ b/src/frontend/images/HD24_matrix_104.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_105.gif b/src/frontend/images/HD24_matrix_105.gif new file mode 100644 index 0000000..bddeb44 --- /dev/null +++ b/src/frontend/images/HD24_matrix_105.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_106.gif b/src/frontend/images/HD24_matrix_106.gif new file mode 100644 index 0000000..90c3f05 --- /dev/null +++ b/src/frontend/images/HD24_matrix_106.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_107.gif b/src/frontend/images/HD24_matrix_107.gif new file mode 100644 index 0000000..e4d1fc8 --- /dev/null +++ b/src/frontend/images/HD24_matrix_107.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_108.gif b/src/frontend/images/HD24_matrix_108.gif new file mode 100644 index 0000000..cd3f56b --- /dev/null +++ b/src/frontend/images/HD24_matrix_108.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_109.gif b/src/frontend/images/HD24_matrix_109.gif new file mode 100644 index 0000000..84c3aeb --- /dev/null +++ b/src/frontend/images/HD24_matrix_109.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_110.gif b/src/frontend/images/HD24_matrix_110.gif new file mode 100644 index 0000000..a900e54 --- /dev/null +++ b/src/frontend/images/HD24_matrix_110.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_111.gif b/src/frontend/images/HD24_matrix_111.gif new file mode 100644 index 0000000..97e9c1c --- /dev/null +++ b/src/frontend/images/HD24_matrix_111.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_112.gif b/src/frontend/images/HD24_matrix_112.gif new file mode 100644 index 0000000..2a15b94 --- /dev/null +++ b/src/frontend/images/HD24_matrix_112.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_113.gif b/src/frontend/images/HD24_matrix_113.gif new file mode 100644 index 0000000..2dced00 --- /dev/null +++ b/src/frontend/images/HD24_matrix_113.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_114.gif b/src/frontend/images/HD24_matrix_114.gif new file mode 100644 index 0000000..4a09605 --- /dev/null +++ b/src/frontend/images/HD24_matrix_114.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_115.gif b/src/frontend/images/HD24_matrix_115.gif new file mode 100644 index 0000000..3fd5273 --- /dev/null +++ b/src/frontend/images/HD24_matrix_115.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_116.gif b/src/frontend/images/HD24_matrix_116.gif new file mode 100644 index 0000000..d8e539d --- /dev/null +++ b/src/frontend/images/HD24_matrix_116.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_117.gif b/src/frontend/images/HD24_matrix_117.gif new file mode 100644 index 0000000..778df49 --- /dev/null +++ b/src/frontend/images/HD24_matrix_117.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_118.gif b/src/frontend/images/HD24_matrix_118.gif new file mode 100644 index 0000000..3363a9d --- /dev/null +++ b/src/frontend/images/HD24_matrix_118.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_119.gif b/src/frontend/images/HD24_matrix_119.gif new file mode 100644 index 0000000..4ea9b64 --- /dev/null +++ b/src/frontend/images/HD24_matrix_119.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_120.gif b/src/frontend/images/HD24_matrix_120.gif new file mode 100644 index 0000000..08dd4b9 --- /dev/null +++ b/src/frontend/images/HD24_matrix_120.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_121.gif b/src/frontend/images/HD24_matrix_121.gif new file mode 100644 index 0000000..0a7d586 --- /dev/null +++ b/src/frontend/images/HD24_matrix_121.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_122.gif b/src/frontend/images/HD24_matrix_122.gif new file mode 100644 index 0000000..3c1ff79 --- /dev/null +++ b/src/frontend/images/HD24_matrix_122.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_123.gif b/src/frontend/images/HD24_matrix_123.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_123.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_124.gif b/src/frontend/images/HD24_matrix_124.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_124.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_125.gif b/src/frontend/images/HD24_matrix_125.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_125.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_126.gif b/src/frontend/images/HD24_matrix_126.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_126.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_127.gif b/src/frontend/images/HD24_matrix_127.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_127.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_32.gif b/src/frontend/images/HD24_matrix_32.gif new file mode 100644 index 0000000..63304b1 --- /dev/null +++ b/src/frontend/images/HD24_matrix_32.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_33.gif b/src/frontend/images/HD24_matrix_33.gif new file mode 100644 index 0000000..0437f42 --- /dev/null +++ b/src/frontend/images/HD24_matrix_33.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_34.gif b/src/frontend/images/HD24_matrix_34.gif new file mode 100644 index 0000000..d7aa4e1 --- /dev/null +++ b/src/frontend/images/HD24_matrix_34.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_35.gif b/src/frontend/images/HD24_matrix_35.gif new file mode 100644 index 0000000..a73ab5f --- /dev/null +++ b/src/frontend/images/HD24_matrix_35.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_36.gif b/src/frontend/images/HD24_matrix_36.gif new file mode 100644 index 0000000..f741bb0 --- /dev/null +++ b/src/frontend/images/HD24_matrix_36.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_37.gif b/src/frontend/images/HD24_matrix_37.gif new file mode 100644 index 0000000..b335468 --- /dev/null +++ b/src/frontend/images/HD24_matrix_37.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_38.gif b/src/frontend/images/HD24_matrix_38.gif new file mode 100644 index 0000000..a41c62b --- /dev/null +++ b/src/frontend/images/HD24_matrix_38.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_39.gif b/src/frontend/images/HD24_matrix_39.gif new file mode 100644 index 0000000..4cb9ff7 --- /dev/null +++ b/src/frontend/images/HD24_matrix_39.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_40.gif b/src/frontend/images/HD24_matrix_40.gif new file mode 100644 index 0000000..e65298d --- /dev/null +++ b/src/frontend/images/HD24_matrix_40.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_41.gif b/src/frontend/images/HD24_matrix_41.gif new file mode 100644 index 0000000..b33b736 --- /dev/null +++ b/src/frontend/images/HD24_matrix_41.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_42.gif b/src/frontend/images/HD24_matrix_42.gif new file mode 100644 index 0000000..5dc29ea --- /dev/null +++ b/src/frontend/images/HD24_matrix_42.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_43.gif b/src/frontend/images/HD24_matrix_43.gif new file mode 100644 index 0000000..23b4d9a --- /dev/null +++ b/src/frontend/images/HD24_matrix_43.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_44.gif b/src/frontend/images/HD24_matrix_44.gif new file mode 100644 index 0000000..3813d69 --- /dev/null +++ b/src/frontend/images/HD24_matrix_44.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_45.gif b/src/frontend/images/HD24_matrix_45.gif new file mode 100644 index 0000000..0ab8c42 --- /dev/null +++ b/src/frontend/images/HD24_matrix_45.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_46.gif b/src/frontend/images/HD24_matrix_46.gif new file mode 100644 index 0000000..902ec61 --- /dev/null +++ b/src/frontend/images/HD24_matrix_46.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_47.gif b/src/frontend/images/HD24_matrix_47.gif new file mode 100644 index 0000000..d40524a --- /dev/null +++ b/src/frontend/images/HD24_matrix_47.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_48.gif b/src/frontend/images/HD24_matrix_48.gif new file mode 100644 index 0000000..28e1580 --- /dev/null +++ b/src/frontend/images/HD24_matrix_48.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_49.gif b/src/frontend/images/HD24_matrix_49.gif new file mode 100644 index 0000000..8583186 --- /dev/null +++ b/src/frontend/images/HD24_matrix_49.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_50.gif b/src/frontend/images/HD24_matrix_50.gif new file mode 100644 index 0000000..2cc053f --- /dev/null +++ b/src/frontend/images/HD24_matrix_50.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_51.gif b/src/frontend/images/HD24_matrix_51.gif new file mode 100644 index 0000000..d528bea --- /dev/null +++ b/src/frontend/images/HD24_matrix_51.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_52.gif b/src/frontend/images/HD24_matrix_52.gif new file mode 100644 index 0000000..c133802 --- /dev/null +++ b/src/frontend/images/HD24_matrix_52.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_53.gif b/src/frontend/images/HD24_matrix_53.gif new file mode 100644 index 0000000..3b63434 --- /dev/null +++ b/src/frontend/images/HD24_matrix_53.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_54.gif b/src/frontend/images/HD24_matrix_54.gif new file mode 100644 index 0000000..52a912a --- /dev/null +++ b/src/frontend/images/HD24_matrix_54.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_55.gif b/src/frontend/images/HD24_matrix_55.gif new file mode 100644 index 0000000..913fa29 --- /dev/null +++ b/src/frontend/images/HD24_matrix_55.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_56.gif b/src/frontend/images/HD24_matrix_56.gif new file mode 100644 index 0000000..d84897c --- /dev/null +++ b/src/frontend/images/HD24_matrix_56.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_57.gif b/src/frontend/images/HD24_matrix_57.gif new file mode 100644 index 0000000..03fa842 --- /dev/null +++ b/src/frontend/images/HD24_matrix_57.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_58.gif b/src/frontend/images/HD24_matrix_58.gif new file mode 100644 index 0000000..2205a71 --- /dev/null +++ b/src/frontend/images/HD24_matrix_58.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_59.gif b/src/frontend/images/HD24_matrix_59.gif new file mode 100644 index 0000000..55a05e5 --- /dev/null +++ b/src/frontend/images/HD24_matrix_59.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_60.gif b/src/frontend/images/HD24_matrix_60.gif new file mode 100644 index 0000000..6717578 --- /dev/null +++ b/src/frontend/images/HD24_matrix_60.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_61.gif b/src/frontend/images/HD24_matrix_61.gif new file mode 100644 index 0000000..d2d4337 --- /dev/null +++ b/src/frontend/images/HD24_matrix_61.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_62.gif b/src/frontend/images/HD24_matrix_62.gif new file mode 100644 index 0000000..4dd41f8 --- /dev/null +++ b/src/frontend/images/HD24_matrix_62.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_63.gif b/src/frontend/images/HD24_matrix_63.gif new file mode 100644 index 0000000..7437751 --- /dev/null +++ b/src/frontend/images/HD24_matrix_63.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_64.gif b/src/frontend/images/HD24_matrix_64.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_64.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_65.gif b/src/frontend/images/HD24_matrix_65.gif new file mode 100644 index 0000000..3751e69 --- /dev/null +++ b/src/frontend/images/HD24_matrix_65.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_66.gif b/src/frontend/images/HD24_matrix_66.gif new file mode 100644 index 0000000..757dc9b --- /dev/null +++ b/src/frontend/images/HD24_matrix_66.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_67.gif b/src/frontend/images/HD24_matrix_67.gif new file mode 100644 index 0000000..c3448a5 --- /dev/null +++ b/src/frontend/images/HD24_matrix_67.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_68.gif b/src/frontend/images/HD24_matrix_68.gif new file mode 100644 index 0000000..9f43eba --- /dev/null +++ b/src/frontend/images/HD24_matrix_68.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_69.gif b/src/frontend/images/HD24_matrix_69.gif new file mode 100644 index 0000000..5a972dc --- /dev/null +++ b/src/frontend/images/HD24_matrix_69.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_70.gif b/src/frontend/images/HD24_matrix_70.gif new file mode 100644 index 0000000..659ee77 --- /dev/null +++ b/src/frontend/images/HD24_matrix_70.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_71.gif b/src/frontend/images/HD24_matrix_71.gif new file mode 100644 index 0000000..b8d498a --- /dev/null +++ b/src/frontend/images/HD24_matrix_71.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_72.gif b/src/frontend/images/HD24_matrix_72.gif new file mode 100644 index 0000000..9f4e79d --- /dev/null +++ b/src/frontend/images/HD24_matrix_72.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_73.gif b/src/frontend/images/HD24_matrix_73.gif new file mode 100644 index 0000000..7049d5b --- /dev/null +++ b/src/frontend/images/HD24_matrix_73.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_74.gif b/src/frontend/images/HD24_matrix_74.gif new file mode 100644 index 0000000..2d22554 --- /dev/null +++ b/src/frontend/images/HD24_matrix_74.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_75.gif b/src/frontend/images/HD24_matrix_75.gif new file mode 100644 index 0000000..4c75258 --- /dev/null +++ b/src/frontend/images/HD24_matrix_75.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_76.gif b/src/frontend/images/HD24_matrix_76.gif new file mode 100644 index 0000000..3fb4747 --- /dev/null +++ b/src/frontend/images/HD24_matrix_76.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_77.gif b/src/frontend/images/HD24_matrix_77.gif new file mode 100644 index 0000000..43f8fac --- /dev/null +++ b/src/frontend/images/HD24_matrix_77.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_78.gif b/src/frontend/images/HD24_matrix_78.gif new file mode 100644 index 0000000..3b37dc3 --- /dev/null +++ b/src/frontend/images/HD24_matrix_78.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_79.gif b/src/frontend/images/HD24_matrix_79.gif new file mode 100644 index 0000000..8be50ea --- /dev/null +++ b/src/frontend/images/HD24_matrix_79.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_80.gif b/src/frontend/images/HD24_matrix_80.gif new file mode 100644 index 0000000..e9dda05 --- /dev/null +++ b/src/frontend/images/HD24_matrix_80.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_81.gif b/src/frontend/images/HD24_matrix_81.gif new file mode 100644 index 0000000..2e3e5b0 --- /dev/null +++ b/src/frontend/images/HD24_matrix_81.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_82.gif b/src/frontend/images/HD24_matrix_82.gif new file mode 100644 index 0000000..a209e00 --- /dev/null +++ b/src/frontend/images/HD24_matrix_82.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_83.gif b/src/frontend/images/HD24_matrix_83.gif new file mode 100644 index 0000000..37bed7f --- /dev/null +++ b/src/frontend/images/HD24_matrix_83.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_84.gif b/src/frontend/images/HD24_matrix_84.gif new file mode 100644 index 0000000..2bea274 --- /dev/null +++ b/src/frontend/images/HD24_matrix_84.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_85.gif b/src/frontend/images/HD24_matrix_85.gif new file mode 100644 index 0000000..f02f416 --- /dev/null +++ b/src/frontend/images/HD24_matrix_85.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_86.gif b/src/frontend/images/HD24_matrix_86.gif new file mode 100644 index 0000000..b9642bc --- /dev/null +++ b/src/frontend/images/HD24_matrix_86.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_87.gif b/src/frontend/images/HD24_matrix_87.gif new file mode 100644 index 0000000..c9c2813 --- /dev/null +++ b/src/frontend/images/HD24_matrix_87.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_88.gif b/src/frontend/images/HD24_matrix_88.gif new file mode 100644 index 0000000..93d7d19 --- /dev/null +++ b/src/frontend/images/HD24_matrix_88.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_89.gif b/src/frontend/images/HD24_matrix_89.gif new file mode 100644 index 0000000..e9bfb57 --- /dev/null +++ b/src/frontend/images/HD24_matrix_89.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_90.gif b/src/frontend/images/HD24_matrix_90.gif new file mode 100644 index 0000000..f106d72 --- /dev/null +++ b/src/frontend/images/HD24_matrix_90.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_91.gif b/src/frontend/images/HD24_matrix_91.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_91.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_92.gif b/src/frontend/images/HD24_matrix_92.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_92.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_93.gif b/src/frontend/images/HD24_matrix_93.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_93.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_94.gif b/src/frontend/images/HD24_matrix_94.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_94.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_95.gif b/src/frontend/images/HD24_matrix_95.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_95.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_96.gif b/src/frontend/images/HD24_matrix_96.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_96.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_97.gif b/src/frontend/images/HD24_matrix_97.gif new file mode 100644 index 0000000..a0fbde3 --- /dev/null +++ b/src/frontend/images/HD24_matrix_97.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_98.gif b/src/frontend/images/HD24_matrix_98.gif new file mode 100644 index 0000000..89c3f8a --- /dev/null +++ b/src/frontend/images/HD24_matrix_98.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_99.gif b/src/frontend/images/HD24_matrix_99.gif new file mode 100644 index 0000000..1596771 --- /dev/null +++ b/src/frontend/images/HD24_matrix_99.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_arrowleft.gif b/src/frontend/images/HD24_matrix_arrowleft.gif new file mode 100644 index 0000000..0950acb --- /dev/null +++ b/src/frontend/images/HD24_matrix_arrowleft.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_arrowright.gif b/src/frontend/images/HD24_matrix_arrowright.gif new file mode 100644 index 0000000..60101ec --- /dev/null +++ b/src/frontend/images/HD24_matrix_arrowright.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_realsize.gif b/src/frontend/images/HD24_matrix_realsize.gif new file mode 100644 index 0000000..991c59c --- /dev/null +++ b/src/frontend/images/HD24_matrix_realsize.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_writeenabled.gif b/src/frontend/images/HD24_matrix_writeenabled.gif new file mode 100644 index 0000000..19b59d3 --- /dev/null +++ b/src/frontend/images/HD24_matrix_writeenabled.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/HD24_matrix_writeprotected.gif b/src/frontend/images/HD24_matrix_writeprotected.gif new file mode 100644 index 0000000..14ef331 --- /dev/null +++ b/src/frontend/images/HD24_matrix_writeprotected.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/aqua.bmp b/src/frontend/images/aqua.bmp new file mode 100644 index 0000000..3ad5445 --- /dev/null +++ b/src/frontend/images/aqua.bmp | |||
Binary files differ | |||
diff --git a/src/frontend/images/aqua.rar b/src/frontend/images/aqua.rar new file mode 100644 index 0000000..63e877e --- /dev/null +++ b/src/frontend/images/aqua.rar | |||
Binary files differ | |||
diff --git a/src/frontend/images/aquabutton_down.gif b/src/frontend/images/aquabutton_down.gif new file mode 100644 index 0000000..ecf4092 --- /dev/null +++ b/src/frontend/images/aquabutton_down.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/aquabutton_up.gif b/src/frontend/images/aquabutton_up.gif new file mode 100644 index 0000000..2b12ec2 --- /dev/null +++ b/src/frontend/images/aquabutton_up.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button.gif b/src/frontend/images/button.gif new file mode 100644 index 0000000..070d82b --- /dev/null +++ b/src/frontend/images/button.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button.xcf b/src/frontend/images/button.xcf new file mode 100644 index 0000000..d80fd3c --- /dev/null +++ b/src/frontend/images/button.xcf | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_ffwd.gif b/src/frontend/images/button_ffwd.gif new file mode 100644 index 0000000..f09258e --- /dev/null +++ b/src/frontend/images/button_ffwd.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_ffwd_dn.gif b/src/frontend/images/button_ffwd_dn.gif new file mode 100644 index 0000000..2c18d91 --- /dev/null +++ b/src/frontend/images/button_ffwd_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_lrc.gif b/src/frontend/images/button_lrc.gif new file mode 100644 index 0000000..f2ab406 --- /dev/null +++ b/src/frontend/images/button_lrc.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_lrc_dn.gif b/src/frontend/images/button_lrc_dn.gif new file mode 100644 index 0000000..dcf5cad --- /dev/null +++ b/src/frontend/images/button_lrc_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_lrc_led.gif b/src/frontend/images/button_lrc_led.gif new file mode 100644 index 0000000..7c84600 --- /dev/null +++ b/src/frontend/images/button_lrc_led.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_lrc_led_dn.gif b/src/frontend/images/button_lrc_led_dn.gif new file mode 100644 index 0000000..2cec7c7 --- /dev/null +++ b/src/frontend/images/button_lrc_led_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_lrc_led_on.gif b/src/frontend/images/button_lrc_led_on.gif new file mode 100644 index 0000000..b149d30 --- /dev/null +++ b/src/frontend/images/button_lrc_led_on.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_lrc_led_on_dn.gif b/src/frontend/images/button_lrc_led_on_dn.gif new file mode 100644 index 0000000..e2f9143 --- /dev/null +++ b/src/frontend/images/button_lrc_led_on_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_mute.gif b/src/frontend/images/button_mute.gif new file mode 100644 index 0000000..b29e443 --- /dev/null +++ b/src/frontend/images/button_mute.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_mute_dn.gif b/src/frontend/images/button_mute_dn.gif new file mode 100644 index 0000000..4f44a69 --- /dev/null +++ b/src/frontend/images/button_mute_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_play.gif b/src/frontend/images/button_play.gif new file mode 100644 index 0000000..5e26985 --- /dev/null +++ b/src/frontend/images/button_play.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_play_dn.gif b/src/frontend/images/button_play_dn.gif new file mode 100644 index 0000000..1dad7fe --- /dev/null +++ b/src/frontend/images/button_play_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_rec.gif b/src/frontend/images/button_rec.gif new file mode 100644 index 0000000..af2ad76 --- /dev/null +++ b/src/frontend/images/button_rec.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_rec_dn.gif b/src/frontend/images/button_rec_dn.gif new file mode 100644 index 0000000..9293d04 --- /dev/null +++ b/src/frontend/images/button_rec_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_rew.gif b/src/frontend/images/button_rew.gif new file mode 100644 index 0000000..1dd8501 --- /dev/null +++ b/src/frontend/images/button_rew.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_rew_dn.gif b/src/frontend/images/button_rew_dn.gif new file mode 100644 index 0000000..e00f65f --- /dev/null +++ b/src/frontend/images/button_rew_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_small.gif b/src/frontend/images/button_small.gif new file mode 100644 index 0000000..762af63 --- /dev/null +++ b/src/frontend/images/button_small.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_small_dn.gif b/src/frontend/images/button_small_dn.gif new file mode 100644 index 0000000..0f96f67 --- /dev/null +++ b/src/frontend/images/button_small_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_solo.gif b/src/frontend/images/button_solo.gif new file mode 100644 index 0000000..f70004e --- /dev/null +++ b/src/frontend/images/button_solo.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_solo_dn.gif b/src/frontend/images/button_solo_dn.gif new file mode 100644 index 0000000..847d366 --- /dev/null +++ b/src/frontend/images/button_solo_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_stop.gif b/src/frontend/images/button_stop.gif new file mode 100644 index 0000000..06b5581 --- /dev/null +++ b/src/frontend/images/button_stop.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_stop_dn.gif b/src/frontend/images/button_stop_dn.gif new file mode 100644 index 0000000..b526b8a --- /dev/null +++ b/src/frontend/images/button_stop_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/button_stop_uplit.gif b/src/frontend/images/button_stop_uplit.gif new file mode 100644 index 0000000..1b84f7e --- /dev/null +++ b/src/frontend/images/button_stop_uplit.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/ch21.gif b/src/frontend/images/ch21.gif new file mode 100644 index 0000000..2aece61 --- /dev/null +++ b/src/frontend/images/ch21.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/ch21.png b/src/frontend/images/ch21.png new file mode 100644 index 0000000..b564294 --- /dev/null +++ b/src/frontend/images/ch21.png | |||
Binary files differ | |||
diff --git a/src/frontend/images/down.gif b/src/frontend/images/down.gif new file mode 100644 index 0000000..6320f2a --- /dev/null +++ b/src/frontend/images/down.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/fader.gif b/src/frontend/images/fader.gif new file mode 100644 index 0000000..5ee05a2 --- /dev/null +++ b/src/frontend/images/fader.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/ffwd.gif b/src/frontend/images/ffwd.gif new file mode 100755 index 0000000..8029722 --- /dev/null +++ b/src/frontend/images/ffwd.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/hd24connect.png b/src/frontend/images/hd24connect.png new file mode 100755 index 0000000..4ad7bc6 --- /dev/null +++ b/src/frontend/images/hd24connect.png | |||
Binary files differ | |||
diff --git a/src/frontend/images/hd24connect.xpm b/src/frontend/images/hd24connect.xpm new file mode 100644 index 0000000..c3a2b33 --- /dev/null +++ b/src/frontend/images/hd24connect.xpm | |||
@@ -0,0 +1,38 @@ | |||
1 | /* XPM */ | ||
2 | const char * hd24connect_xpm[] = { | ||
3 | "32 32 3 1", | ||
4 | " c None", | ||
5 | ". c #FFFFFF", | ||
6 | "+ c #000000", | ||
7 | "....... .................. ", | ||
8 | ".+++++. .+++++.+++++++++++.. ", | ||
9 | ".+++++. .+++++..++++++++++++. ", | ||
10 | ".+++++.....+++++...++++++++++++.", | ||
11 | ".+++++++++++++++............+++.", | ||
12 | ".+++++++++++++++.++++.......+++.", | ||
13 | ".+++++.....+++++.++++++++++++++.", | ||
14 | ".+++++. .+++++.+++++++++++++. ", | ||
15 | ".+++++. .+++++.+++++++++++.. ", | ||
16 | "....... ...... ........... ", | ||
17 | " ", | ||
18 | " ", | ||
19 | " ", | ||
20 | " ............ ... ..... ", | ||
21 | " .++++++++++++. .+++. .+++++.", | ||
22 | ".++++++++++++++. .++++. .+++++.", | ||
23 | " .........+++++. .+++.....+++++.", | ||
24 | " .+++++++++++++..++++++++++++++.", | ||
25 | ".+++++++++++++. .++++++++++++++.", | ||
26 | ".+++++..........+++++++++++++++.", | ||
27 | ".++++++++++++++...........+++++.", | ||
28 | " .+++++++++++++. .+++++.", | ||
29 | " ............. .......", | ||
30 | " ", | ||
31 | " ", | ||
32 | "................................", | ||
33 | "..++.+++.+..+.+..+.+++..++.+++++", | ||
34 | ".+...+.+.++.+.++.+.+...+.....+..", | ||
35 | ".+...+.+.+.++.+.++.++..+.....+..", | ||
36 | ".+...+.+.+..+.+..+.+...+.....+..", | ||
37 | "..++.+++.+..+.+..+.+++..++...+..", | ||
38 | "................................"}; | ||
diff --git a/src/frontend/images/hd24connect_64x64.xpm b/src/frontend/images/hd24connect_64x64.xpm new file mode 100644 index 0000000..d087646 --- /dev/null +++ b/src/frontend/images/hd24connect_64x64.xpm | |||
@@ -0,0 +1,355 @@ | |||
1 | /* XPM */ | ||
2 | const char * hd24connect_xpm[] = { | ||
3 | "64 64 288 2", | ||
4 | " c None", | ||
5 | ". c #3B412D", | ||
6 | "+ c #343913", | ||
7 | "@ c #272E1D", | ||
8 | "# c #0C161A", | ||
9 | "$ c #10191D", | ||
10 | "% c #303437", | ||
11 | "& c #323A3E", | ||
12 | "* c #1C1C1C", | ||
13 | "= c #000000", | ||
14 | "- c #42161A", | ||
15 | "; c #121415", | ||
16 | "> c #4B1215", | ||
17 | ", c #0F1011", | ||
18 | "' c #0C0D0E", | ||
19 | ") c #070708", | ||
20 | "! c #040506", | ||
21 | "~ c #08090A", | ||
22 | "{ c #0A0C0C", | ||
23 | "] c #020203", | ||
24 | "^ c #060809", | ||
25 | "/ c #FAFAFA", | ||
26 | "( c #FEFEFE", | ||
27 | "_ c #C5C7C8", | ||
28 | ": c #6D6E6F", | ||
29 | "< c #4D4F50", | ||
30 | "[ c #828384", | ||
31 | "} c #FCFDFD", | ||
32 | "| c #F0F2F2", | ||
33 | "1 c #CCCFD0", | ||
34 | "2 c #8E9091", | ||
35 | "3 c #292A2A", | ||
36 | "4 c #222222", | ||
37 | "5 c #FBFBFC", | ||
38 | "6 c #FFFFFF", | ||
39 | "7 c #C6C8C8", | ||
40 | "8 c #6E6F70", | ||
41 | "9 c #4E4F50", | ||
42 | "0 c #252626", | ||
43 | "a c #D1D2D3", | ||
44 | "b c #F7F7F7", | ||
45 | "c c #444546", | ||
46 | "d c #16191B", | ||
47 | "e c #222728", | ||
48 | "f c #1D2122", | ||
49 | "g c #040505", | ||
50 | "h c #393A3B", | ||
51 | "i c #656767", | ||
52 | "j c #7B7C7D", | ||
53 | "k c #858686", | ||
54 | "l c #868686", | ||
55 | "m c #888989", | ||
56 | "n c #F7F8F8", | ||
57 | "o c #A8AAAA", | ||
58 | "p c #050606", | ||
59 | "q c #EEF0F0", | ||
60 | "r c #AEAEAE", | ||
61 | "s c #C8CACB", | ||
62 | "t c #080A0A", | ||
63 | "u c #737475", | ||
64 | "v c #070808", | ||
65 | "w c #0D0E10", | ||
66 | "x c #030404", | ||
67 | "y c #010101", | ||
68 | "z c #141516", | ||
69 | "A c #131516", | ||
70 | "B c #FCFCFC", | ||
71 | "C c #868889", | ||
72 | "D c #FAFAFB", | ||
73 | "E c #383B3C", | ||
74 | "F c #090A0A", | ||
75 | "G c #262829", | ||
76 | "H c #898A8B", | ||
77 | "I c #393C3C", | ||
78 | "J c #28292A", | ||
79 | "K c #E4E5E5", | ||
80 | "L c #848586", | ||
81 | "M c #BFC1C1", | ||
82 | "N c #050506", | ||
83 | "O c #2B3235", | ||
84 | "P c #212629", | ||
85 | "Q c #262A2D", | ||
86 | "R c #161617", | ||
87 | "S c #7A7C7D", | ||
88 | "T c #060606", | ||
89 | "U c #424546", | ||
90 | "V c #101212", | ||
91 | "W c #EFF1F1", | ||
92 | "X c #352427", | ||
93 | "Y c #F9FAFA", | ||
94 | "Z c #F8F8F8", | ||
95 | "` c #868888", | ||
96 | " . c #020202", | ||
97 | ".. c #ECEDEE", | ||
98 | "+. c #949696", | ||
99 | "@. c #0A0B0B", | ||
100 | "#. c #232323", | ||
101 | "$. c #727374", | ||
102 | "%. c #747575", | ||
103 | "&. c #5A5C5C", | ||
104 | "*. c #38393A", | ||
105 | "=. c #727373", | ||
106 | "-. c #212223", | ||
107 | ";. c #3E3F40", | ||
108 | ">. c #707172", | ||
109 | ",. c #5C5C5D", | ||
110 | "'. c #353637", | ||
111 | "). c #464A4B", | ||
112 | "!. c #202223", | ||
113 | "~. c #343637", | ||
114 | "{. c #191A1B", | ||
115 | "]. c #423135", | ||
116 | "^. c #1C1D1E", | ||
117 | "/. c #1A1D1E", | ||
118 | "(. c #3C3F41", | ||
119 | "_. c #212A2D", | ||
120 | ":. c #414146", | ||
121 | "<. c #35312B", | ||
122 | "[. c #282E20", | ||
123 | "}. c #2F2B26", | ||
124 | "|. c #394246", | ||
125 | "1. c #333739", | ||
126 | "2. c #373539", | ||
127 | "3. c #3D4044", | ||
128 | "4. c #151A19", | ||
129 | "5. c #161819", | ||
130 | "6. c #020303", | ||
131 | "7. c #44171A", | ||
132 | "8. c #24292C", | ||
133 | "9. c #1F2427", | ||
134 | "0. c #151819", | ||
135 | "a. c #4A4E50", | ||
136 | "b. c #252728", | ||
137 | "c. c #040606", | ||
138 | "d. c #0A0A0B", | ||
139 | "e. c #0A0B0C", | ||
140 | "f. c #0D0E0E", | ||
141 | "g. c #030304", | ||
142 | "h. c #000101", | ||
143 | "i. c #343434", | ||
144 | "j. c #242526", | ||
145 | "k. c #989A9B", | ||
146 | "l. c #D4D6D7", | ||
147 | "m. c #EDEEEE", | ||
148 | "n. c #F2F3F3", | ||
149 | "o. c #F3F4F4", | ||
150 | "p. c #E9EAEB", | ||
151 | "q. c #CCCECF", | ||
152 | "r. c #949697", | ||
153 | "s. c #363738", | ||
154 | "t. c #040404", | ||
155 | "u. c #212424", | ||
156 | "v. c #F1F2F2", | ||
157 | "w. c #E8EAEA", | ||
158 | "x. c #BEC0C2", | ||
159 | "y. c #101010", | ||
160 | "z. c #050607", | ||
161 | "A. c #C6C9CA", | ||
162 | "B. c #DADADB", | ||
163 | "C. c #797B7C", | ||
164 | "D. c #272829", | ||
165 | "E. c #DEDFDF", | ||
166 | "F. c #0A0A0A", | ||
167 | "G. c #2D3033", | ||
168 | "H. c #F4F4F5", | ||
169 | "I. c #D0D2D3", | ||
170 | "J. c #121313", | ||
171 | "K. c #949596", | ||
172 | "L. c #D5D6D7", | ||
173 | "M. c #F5F6F6", | ||
174 | "N. c #101112", | ||
175 | "O. c #AEB0B1", | ||
176 | "P. c #595A5C", | ||
177 | "Q. c #343739", | ||
178 | "R. c #303537", | ||
179 | "S. c #131414", | ||
180 | "T. c #9B9D9E", | ||
181 | "U. c #FAFCFC", | ||
182 | "V. c #161618", | ||
183 | "W. c #3C3E3E", | ||
184 | "X. c #C1C2C3", | ||
185 | "Y. c #F0F1F2", | ||
186 | "Z. c #A0A2A4", | ||
187 | "`. c #B0B1B2", | ||
188 | " + c #434646", | ||
189 | ".+ c #121314", | ||
190 | "++ c #EFF0F1", | ||
191 | "@+ c #030303", | ||
192 | "#+ c #454647", | ||
193 | "$+ c #959798", | ||
194 | "%+ c #E6E7E8", | ||
195 | "&+ c #F2F4F4", | ||
196 | "*+ c #FAFBFB", | ||
197 | "=+ c #E7E8E9", | ||
198 | "-+ c #2A2C2D", | ||
199 | ";+ c #ADAFB0", | ||
200 | ">+ c #FEFEFF", | ||
201 | ",+ c #FDFEFE", | ||
202 | "'+ c #C8C9CA", | ||
203 | ")+ c #151616", | ||
204 | "!+ c #C7C8C9", | ||
205 | "~+ c #D1D2D2", | ||
206 | "{+ c #999A9A", | ||
207 | "]+ c #98999A", | ||
208 | "^+ c #87898A", | ||
209 | "/+ c #656667", | ||
210 | "(+ c #2C2D2E", | ||
211 | "_+ c #333435", | ||
212 | ":+ c #646666", | ||
213 | "<+ c #818282", | ||
214 | "[+ c #8F9192", | ||
215 | "}+ c #939495", | ||
216 | "|+ c #959697", | ||
217 | "1+ c #F8F9F9", | ||
218 | "2+ c #242626", | ||
219 | "3+ c #8C8D8E", | ||
220 | "4+ c #8F9091", | ||
221 | "5+ c #0B0C0C", | ||
222 | "6+ c #2C3032", | ||
223 | "7+ c #1D1F20", | ||
224 | "8+ c #131415", | ||
225 | "9+ c #F4F4F4", | ||
226 | "0+ c #ECEEEE", | ||
227 | "a+ c #E8EAEB", | ||
228 | "b+ c #161818", | ||
229 | "c+ c #1E1F20", | ||
230 | "d+ c #2F2F2F", | ||
231 | "e+ c #545556", | ||
232 | "f+ c #D0D1D2", | ||
233 | "g+ c #161718", | ||
234 | "h+ c #252627", | ||
235 | "i+ c #545656", | ||
236 | "j+ c #727474", | ||
237 | "k+ c #838484", | ||
238 | "l+ c #7A7C7C", | ||
239 | "m+ c #6B6D6D", | ||
240 | "n+ c #2B2E31", | ||
241 | "o+ c #060707", | ||
242 | "p+ c #2A2E32", | ||
243 | "q+ c #1F2426", | ||
244 | "r+ c #212425", | ||
245 | "s+ c #101213", | ||
246 | "t+ c #0E1010", | ||
247 | "u+ c #222425", | ||
248 | "v+ c #303233", | ||
249 | "w+ c #585D5E", | ||
250 | "x+ c #2C2C2C", | ||
251 | "y+ c #0B0B0B", | ||
252 | "z+ c #262626", | ||
253 | "A+ c #242424", | ||
254 | "B+ c #202020", | ||
255 | "C+ c #191919", | ||
256 | "D+ c #303030", | ||
257 | "E+ c #1B1B1B", | ||
258 | "F+ c #212121", | ||
259 | "G+ c #171717", | ||
260 | "H+ c #292929", | ||
261 | "I+ c #080808", | ||
262 | "J+ c #090909", | ||
263 | "K+ c #0E0E0E", | ||
264 | "L+ c #070707", | ||
265 | "M+ c #050505", | ||
266 | "N+ c #121212", | ||
267 | "O+ c #272727", | ||
268 | "P+ c #3D3D3D", | ||
269 | "Q+ c #282828", | ||
270 | "R+ c #0D0D0D", | ||
271 | "S+ c #181818", | ||
272 | "T+ c #252525", | ||
273 | "U+ c #323232", | ||
274 | "V+ c #2E2E2E", | ||
275 | "W+ c #3C3C3C", | ||
276 | "X+ c #1F1F1F", | ||
277 | "Y+ c #111111", | ||
278 | "Z+ c #2B2B2B", | ||
279 | "`+ c #1E1E1E", | ||
280 | " @ c #141414", | ||
281 | ".@ c #626262", | ||
282 | "+@ c #161616", | ||
283 | "@@ c #5E5E5E", | ||
284 | "#@ c #414141", | ||
285 | "$@ c #131313", | ||
286 | "%@ c #1A1A1A", | ||
287 | "&@ c #0F0F0F", | ||
288 | "*@ c #393939", | ||
289 | "=@ c #383838", | ||
290 | "-@ c #565656", | ||
291 | ";@ c #3A3A3A", | ||
292 | " ", | ||
293 | " ", | ||
294 | " ", | ||
295 | " ", | ||
296 | " ", | ||
297 | " ", | ||
298 | " ", | ||
299 | " ", | ||
300 | ". + + + + + + + + + + + + + + + + + + @ # # # # # # # # # # # $ + + + + + + + + + + + + + + + % & ", | ||
301 | "* = = = = = = = = = = = - = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = ; > ", | ||
302 | "* = = , , , , , , ' = = - = = ) , , , , , , ! = = = ~ , , , , , , , , , , , , , , , , , , , , , { ] = = = = , ", | ||
303 | "* = ^ / ( ( ( ( ( _ = = - = = : ( ( ( ( ( ( < = = = [ ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( ( } | 1 2 3 = = 4 ", | ||
304 | "* = ^ 5 6 6 6 6 6 7 = = - = = 8 6 6 6 6 6 6 9 = = = 0 a 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 b c = = ", | ||
305 | "* = ^ 5 6 6 6 6 6 7 = = d e e e e e e e f = = 8 6 6 6 6 6 6 9 = = = = g h i j k l l l l l l l l l l l l l l m n 6 6 6 6 6 o = = ", | ||
306 | "* = ^ 5 6 6 6 6 6 7 = = = = = = = = = = = = = 8 6 6 6 6 6 6 9 = = = = = = = = = = = = = = = = = = = = = = = p q 6 6 6 6 6 r = = ", | ||
307 | "* = ^ 5 6 6 6 6 6 s t t t t t t t t t t t t t u 6 6 6 6 6 6 9 = = = v w w w w w w x = y ; z z z z z z A x = p q 6 6 6 6 6 r = = ", | ||
308 | "* = ^ 5 6 6 6 6 6 ( / / / / / / / / / / / / / B 6 6 6 6 6 6 9 = = = C D D D D D D E = F G = p q 6 6 6 6 6 r = = ", | ||
309 | "* = ^ 5 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 9 = = = H 6 6 6 6 6 6 I = F J = p q 6 6 6 6 6 r = = ", | ||
310 | "* = ^ 5 6 6 6 6 6 K L L L L L L L L L L L L L M 6 6 6 6 6 6 9 = = = H 6 6 6 6 6 6 I = N O P P P P P P Q R = p q 6 6 6 6 6 r = = ", | ||
311 | "* = ^ 5 6 6 6 6 6 7 = = = = = = = = = = = = = S 6 6 6 6 6 6 9 = = = H 6 6 6 6 6 6 I = = = = = = = = = = = = p q 6 6 6 6 6 r = = ", | ||
312 | "* = ^ 5 6 6 6 6 6 7 = = T ' ' ' ' ' ' ' ~ = = S 6 6 6 6 6 6 9 = = = H 6 6 6 6 6 6 U ' ' ' ' ' ' ' ' ' ' ' ' V W 6 6 6 6 6 r = = ", | ||
313 | "* = ^ 5 6 6 6 6 6 7 = = X = = S 6 6 6 6 6 6 9 = = = H 6 6 6 6 6 6 Y Z Z Z Z Z Z Z Z Z Z Z Z Z ( 6 6 6 6 6 ` = .", | ||
314 | "* = ^ 5 6 6 6 6 6 7 = = - = = S 6 6 6 6 6 6 9 = = = H 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 ..+.@.= #.", | ||
315 | "* = x $.%.%.%.%.%.&.= = - = = *.%.%.%.%.%.=.-.= = = ;.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.%.>.,.'.F = = .).", | ||
316 | "* = = = = = = = = = = = - = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = !. ", | ||
317 | "~.{.{.{.{.{.{.{.{.{.{.{.]. {.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.{.^./.(._. ", | ||
318 | " ", | ||
319 | " :.<.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.[.}.|. 1.1.1.1.1.2.3. 1.1.1.1.1.1.1.1.1.1.1. ", | ||
320 | " 4.5. .= = = = = = = = = = = = = = = = = = = = = = 6.5.7. 8.= = = = = = = = = p 9. 0.= = = = = = = = = = = a. ", | ||
321 | " b.= = = = c.d.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.e.F x = = = = f. g = g.e.e.e.v x = = = h. 0.= = e.e.e.e.e.e.~ = = a. ", | ||
322 | "i.= = j.k.l.m.n.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.o.n.p.q.r.s.= = t.u.= = C o.o.o.v.w.x.y.= z. 0.= T w.o.o.o.o.o.A.= = a. ", | ||
323 | " .= N B.6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 / C.= = = = D.o.6 6 6 6 6 E.F.= G. 0.= T H.6 6 6 6 6 I.= = a. ", | ||
324 | "= = J.K.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.+.L.6 6 6 6 6 M.N.= = y O.6 6 6 6 6 ( P.= = Q.R.R.R.R.R.S.= T H.6 6 6 6 6 I.= = a. ", | ||
325 | "= = = = = = = = = = = = = = = = = = = = = = = T.6 6 6 6 6 U.V.= = W.} 6 6 6 6 6 X.g.= = = = = = = = = = T Y.6 6 6 6 6 I.= = a. ", | ||
326 | "= = = = = = = x e.f.f.f.f.f.f.f.f.f.f.f.f.f.f.Z.6 6 6 6 6 U.V.= y `.6 6 6 6 6 B +f.f.f.f.f.f.f.f.f.f.f..+++6 6 6 6 6 I.= = a. ", | ||
327 | "= = = @+#+$+s %+| &+&+&+&+&+&+&+&+&+&+&+&+&+&+*+6 6 6 6 6 =+e.= -+B 6 6 6 6 6 ( o.&+&+&+&+&+&+&+&+&+&+&+o.( 6 6 6 6 6 I.= = a. ", | ||
328 | "= = ] ;+>+6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 ,+'+W.= = )+!+( 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 I.= = a. ", | ||
329 | "= = !.( 6 6 6 6 6 ~+{+{+{+{+{+{+{+{+{+{+{+{+{+{+]+^+/+(+@+= = = = g _+:+<+[+}+}+}+}+}+}+}+}+}+}+}+}+}+}+|+1+6 6 6 6 6 I.= = a. ", | ||
330 | "= = 2+( 6 6 6 6 6 3+= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = p q 6 6 6 6 6 I.= = a. ", | ||
331 | "= = 2+( 6 6 6 6 6 4+v v v v v v v v v v v v v v v v v v v v y = 5+6+7+8+5+p ! ! ! ! ! ! ! ! ! ! ! ! y = p q 6 6 6 6 6 I.= = a. ", | ||
332 | "= = , 9+6 6 6 6 6 b 0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+0+a+z = b+ c+= p q 6 6 6 6 6 I.= = a. ", | ||
333 | "d+= = e+f+} 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 U.V.= b+ -.= p q 6 6 6 6 6 I.= = a. ", | ||
334 | " g+= = ] h+i+j+<+k+k+k+k+k+k+k+k+k+k+k+k+k+k+k+k+k+k+k+k+<+5+= b+ -.= @+l+k+k+k+k+k+m+= = a. ", | ||
335 | " n+o+= = = = = = = = = = = = = = = = = = = = = = = = = = = = b+ -.= = = = = = = = = = = a. ", | ||
336 | " p+q+r+s+y.t+t+t+t+t+t+t+t+t+t+t+t+t+t+t+t+t+t+t+t+t+t+t+u+ v+t+t+t+t+t+t+t+t+t+t+t+w+ ", | ||
337 | " ", | ||
338 | " ", | ||
339 | " ", | ||
340 | " x+y+z+ A+B+C+d+ D+E+F+G+ ", | ||
341 | " H+= y I+J+= K+= L+L+= y+ = = M+ = N+ = = K+ = O+ = = = = = = K+T = J+T .P+ = = = = = = = = ", | ||
342 | " Q+= R+ S+= T+ U+= y. = = = z+ = N+ = = = V+ = O+ = R+ M+y W+ y.= = ", | ||
343 | " X+= H+ = I+ K+= = = X+T = N+ = t.E+Y+ = O+ = K+ Z+= `+ F.= = ", | ||
344 | " t.= = @ `+= = = .@T +@ = N+ = T @@y #@ = O+ = = = = = = $@= +@ F.= = ", | ||
345 | " y+= = %@ O+= = = H+t.B+= N+ = T #.y+F+= O+ = T = = = Y+= U+ F.= = ", | ||
346 | " U+= x+ . . M+= = = L+L+= N+ = T .L+= O+ = &@ *@= y. F.= = ", | ||
347 | " @+ .Z+ 4 4 = X+ O+= H+ = = =@= = N+ = T +@= = O+ = L+ C+= O+ * -@ F.= = ", | ||
348 | " N+= = = T `+ .= = .R+ = = y+= N+ = T @+= O+ = = = = = `+ H+ .= = .;@ N+T F. ", | ||
349 | " ", | ||
350 | " ", | ||
351 | " ", | ||
352 | " ", | ||
353 | " ", | ||
354 | " ", | ||
355 | " "}; | ||
diff --git a/src/frontend/images/led1.gif b/src/frontend/images/led1.gif new file mode 100644 index 0000000..0d12d05 --- /dev/null +++ b/src/frontend/images/led1.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/led10.gif b/src/frontend/images/led10.gif new file mode 100644 index 0000000..608f51c --- /dev/null +++ b/src/frontend/images/led10.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/led2.gif b/src/frontend/images/led2.gif new file mode 100644 index 0000000..cdda56d --- /dev/null +++ b/src/frontend/images/led2.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/led3.gif b/src/frontend/images/led3.gif new file mode 100644 index 0000000..1bf0030 --- /dev/null +++ b/src/frontend/images/led3.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/led4.gif b/src/frontend/images/led4.gif new file mode 100644 index 0000000..683243e --- /dev/null +++ b/src/frontend/images/led4.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/led5.gif b/src/frontend/images/led5.gif new file mode 100644 index 0000000..efbb09b --- /dev/null +++ b/src/frontend/images/led5.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/led6.gif b/src/frontend/images/led6.gif new file mode 100644 index 0000000..98a8f8d --- /dev/null +++ b/src/frontend/images/led6.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/led7.gif b/src/frontend/images/led7.gif new file mode 100644 index 0000000..85cebc2 --- /dev/null +++ b/src/frontend/images/led7.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/led8.gif b/src/frontend/images/led8.gif new file mode 100644 index 0000000..1e8e1db --- /dev/null +++ b/src/frontend/images/led8.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/led9.gif b/src/frontend/images/led9.gif new file mode 100644 index 0000000..c5f9522 --- /dev/null +++ b/src/frontend/images/led9.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/leds_3.gif b/src/frontend/images/leds_3.gif new file mode 100644 index 0000000..2ff9fcd --- /dev/null +++ b/src/frontend/images/leds_3.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/leds_32.gif b/src/frontend/images/leds_32.gif new file mode 100644 index 0000000..2ff9fcd --- /dev/null +++ b/src/frontend/images/leds_32.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/loop.gif b/src/frontend/images/loop.gif new file mode 100755 index 0000000..cd13fb0 --- /dev/null +++ b/src/frontend/images/loop.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/nextcue.gif b/src/frontend/images/nextcue.gif new file mode 100755 index 0000000..497a8ed --- /dev/null +++ b/src/frontend/images/nextcue.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/play.gif b/src/frontend/images/play.gif new file mode 100755 index 0000000..b773559 --- /dev/null +++ b/src/frontend/images/play.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/prevcue.gif b/src/frontend/images/prevcue.gif new file mode 100755 index 0000000..0d553c9 --- /dev/null +++ b/src/frontend/images/prevcue.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/rec.gif b/src/frontend/images/rec.gif new file mode 100755 index 0000000..b0926f8 --- /dev/null +++ b/src/frontend/images/rec.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/rew.gif b/src/frontend/images/rew.gif new file mode 100755 index 0000000..790b225 --- /dev/null +++ b/src/frontend/images/rew.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/rewindtozero.gif b/src/frontend/images/rewindtozero.gif new file mode 100755 index 0000000..aff7b12 --- /dev/null +++ b/src/frontend/images/rewindtozero.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/stop.gif b/src/frontend/images/stop.gif new file mode 100755 index 0000000..610c64a --- /dev/null +++ b/src/frontend/images/stop.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/up.gif b/src/frontend/images/up.gif new file mode 100644 index 0000000..8af2173 --- /dev/null +++ b/src/frontend/images/up.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/wave.gif b/src/frontend/images/wave.gif new file mode 100755 index 0000000..00d9c7e --- /dev/null +++ b/src/frontend/images/wave.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/xpbutton_dn.gif b/src/frontend/images/xpbutton_dn.gif new file mode 100644 index 0000000..c3d211a --- /dev/null +++ b/src/frontend/images/xpbutton_dn.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/xpbutton_up.gif b/src/frontend/images/xpbutton_up.gif new file mode 100644 index 0000000..5248a0d --- /dev/null +++ b/src/frontend/images/xpbutton_up.gif | |||
Binary files differ | |||
diff --git a/src/frontend/images/xpbutton_uplit.gif b/src/frontend/images/xpbutton_uplit.gif new file mode 100644 index 0000000..831f171 --- /dev/null +++ b/src/frontend/images/xpbutton_uplit.gif | |||
Binary files differ | |||
diff --git a/src/frontend/resource.rc b/src/frontend/resource.rc new file mode 100644 index 0000000..28e2b35 --- /dev/null +++ b/src/frontend/resource.rc | |||
@@ -0,0 +1,2 @@ | |||
1 | #define IDI_ICON1 101 | ||
2 | IDI_ICON1 ICON DISCARDABLE "src/frontend/hd24connect.ico" | ||
diff --git a/src/frontend/selftest.cpp b/src/frontend/selftest.cpp new file mode 100644 index 0000000..2f3f65a --- /dev/null +++ b/src/frontend/selftest.cpp | |||
@@ -0,0 +1,646 @@ | |||
1 | #include <FL/forms.H> | ||
2 | hd24fs* testfs; | ||
3 | |||
4 | void createimage_callback(void* y) | ||
5 | { | ||
6 | cout << "." << endl; | ||
7 | Fl::add_timeout(1.0,createimage_callback,y); | ||
8 | return; | ||
9 | } | ||
10 | int passcount; | ||
11 | int failcount; | ||
12 | #define MINSECTORS 1353964 | ||
13 | |||
14 | //#define BITBIGGER (MINSECTORS+10000) | ||
15 | /* this gives for a bit over 5 minutes at 48k, 24 tracks: */ | ||
16 | #define BITBIGGER (MINSECTORS+2073600) | ||
17 | |||
18 | /* constant is for pretty demo image. */ | ||
19 | void pass() | ||
20 | { | ||
21 | passcount++; | ||
22 | cout << "......................................................PASS" << endl; | ||
23 | } | ||
24 | void fail() | ||
25 | { | ||
26 | failcount++; | ||
27 | cout << "......................................................FAIL" << endl; | ||
28 | } | ||
29 | void fail(const char* reason) | ||
30 | { | ||
31 | failcount++; | ||
32 | cout << "......................................................FAIL" << endl; | ||
33 | cout << "Reason: "<<reason << endl; | ||
34 | } | ||
35 | void test_createimage() | ||
36 | { | ||
37 | cout << "Test if creating too small drive images is prevented... " << endl; | ||
38 | |||
39 | __uint32 lastsector=MINSECTORS-1; | ||
40 | |||
41 | string* strtest=new string("testimage.h24"); | ||
42 | char message[2048]; | ||
43 | message[0]='\0'; | ||
44 | Fl::add_timeout(1.0,createimage_callback,&message[0]); | ||
45 | int result=hd24utils::newdriveimage(strtest,lastsector,&message[0],NULL); | ||
46 | delete strtest; | ||
47 | Fl::remove_timeout(&createimage_callback); | ||
48 | if (result!=-1) fail(); else pass(); | ||
49 | //////////////////////////////////////////////////// | ||
50 | cout << "-----------------------------------------------" << endl; | ||
51 | cout << "Create minimum size empty drive image... please wait" << endl; | ||
52 | lastsector=MINSECTORS; | ||
53 | |||
54 | strtest=new string("testimage.h24"); | ||
55 | result=hd24utils::newdriveimage(strtest,lastsector,&message[0],NULL); | ||
56 | |||
57 | cout << "Image create messages=" << message << endl; | ||
58 | if (result==0) pass(); else fail(); | ||
59 | // Check expected drive image contents. | ||
60 | hd24fs* testfs=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,strtest,false); | ||
61 | /* we calculate free space based on 1 channel because it is much | ||
62 | more sensitive than free space based on 24 channels */ | ||
63 | string* freespace=testfs->freespace(48000,1); | ||
64 | |||
65 | cout << "Free space on drive: " << *freespace << endl; | ||
66 | delete testfs; | ||
67 | ////////////////////////////////////////////////////// | ||
68 | cout << "-----------------------------------------------" << endl; | ||
69 | cout << "Creating somewhat larger size empty drive image... please wait" << endl; | ||
70 | lastsector=BITBIGGER; | ||
71 | |||
72 | string* strtest2=new string("testimage2.h24"); | ||
73 | result=hd24utils::newdriveimage(strtest2,lastsector,&message[0],NULL); | ||
74 | |||
75 | cout << "Image create messages=" << message << endl; | ||
76 | if (result==0) pass(); else fail(); | ||
77 | // Check expected drive image contents. | ||
78 | hd24fs* testfs2=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,strtest2,false); | ||
79 | string* freespace2=testfs2->freespace(48000,1); | ||
80 | cout << "Free space on drive: " << *freespace2 << endl; | ||
81 | if (strcmp(freespace->c_str(),freespace2->c_str())==0) | ||
82 | { | ||
83 | fail("Images were supposed to have different sizes"); | ||
84 | } else { | ||
85 | pass(); | ||
86 | } | ||
87 | delete testfs2; | ||
88 | delete freespace2; | ||
89 | delete strtest2; | ||
90 | //*/ | ||
91 | delete freespace; | ||
92 | delete strtest; | ||
93 | return; | ||
94 | } | ||
95 | |||
96 | void test_useimage() | ||
97 | { | ||
98 | char failmsg[64]; | ||
99 | cout << "Try to use empty drive image... " << endl; | ||
100 | //false=force? | ||
101 | string* strtest=new string("testimage2.h24"); | ||
102 | testfs=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,strtest,false); | ||
103 | delete strtest; | ||
104 | strtest=NULL; | ||
105 | |||
106 | // Let's see if all is as expected. | ||
107 | if (!(testfs->isOpen())) fail(); else pass(); | ||
108 | string* freespace=testfs->freespace(48000,24); | ||
109 | cout << "Free space on drive: " << *freespace << endl; | ||
110 | delete freespace; | ||
111 | hd24raw* rawfs=new hd24raw(testfs); | ||
112 | /* | ||
113 | These functions are only available through raw FS | ||
114 | */ | ||
115 | int songsondisk=rawfs->songsondisk(); | ||
116 | cout << "Songs on disk=" << songsondisk << endl; | ||
117 | if (songsondisk!=0) fail(); else pass(); | ||
118 | |||
119 | __uint32 lastsector=rawfs->getlastsectornum(); | ||
120 | __uint32 expectedlastsector=BITBIGGER; | ||
121 | cout << "Last sectornum of drive image="<< lastsector << endl; | ||
122 | |||
123 | |||
124 | if (lastsector!=expectedlastsector) | ||
125 | { | ||
126 | sprintf(failmsg,"Expected last sector was %ld but found %ld",expectedlastsector,lastsector); | ||
127 | fail(failmsg); | ||
128 | } | ||
129 | else | ||
130 | { | ||
131 | pass(); | ||
132 | } | ||
133 | |||
134 | string* devname=testfs->getdevicename(); | ||
135 | cout <<"Device name="<<*devname<<endl; | ||
136 | if (*devname=="") | ||
137 | { | ||
138 | fail("Device name should always exist"); | ||
139 | } else pass(); | ||
140 | |||
141 | string* volname=testfs->volumename(); | ||
142 | cout <<"Volume name="<<*volname <<endl; | ||
143 | if (*volname=="") fail("Volume name of freshly formatted drive must be nonempty"); else pass(); | ||
144 | |||
145 | // set volume name, commit, then test if change OK | ||
146 | __uint32 projcount=testfs->projectcount(); | ||
147 | cout <<"Project count="<<projcount << endl; | ||
148 | if (projcount!=1) fail("Newly formatted image must have exactly 1 project."); else pass(); | ||
149 | hd24project* currproj=NULL; | ||
150 | if (projcount>0) | ||
151 | { | ||
152 | currproj=testfs->getproject(0); // must error | ||
153 | cout << "Check protection against getting project 0" << endl; | ||
154 | if (currproj!=NULL) fail(); else pass(); | ||
155 | |||
156 | delete currproj; | ||
157 | currproj=testfs->getproject(1); // must not error | ||
158 | cout << "Check zero songcount for supposedly empty project" << endl; | ||
159 | __uint32 songcount=currproj->songcount(); | ||
160 | if (songcount!=0) fail(); else pass(); | ||
161 | |||
162 | cout << "Check getting nonexisting/invalid project numbers" << endl; | ||
163 | int failed=0; | ||
164 | for (int i=2; i<=100; i++) | ||
165 | { | ||
166 | currproj=testfs->getproject(i); // must not error but must return null | ||
167 | if (currproj!=NULL) | ||
168 | { | ||
169 | failed=1; | ||
170 | } | ||
171 | } | ||
172 | if (failed!=0) fail(); else pass(); | ||
173 | } | ||
174 | |||
175 | cout << "set volume name in drive image" << endl; | ||
176 | testfs->setvolumename("myvol"); // only in memory!!! | ||
177 | // check if volume name has been set (in memory) | ||
178 | cout << "reading back volume name to see if set was successful" << endl; | ||
179 | |||
180 | volname=testfs->volumename(); | ||
181 | if (*volname!="myvol") fail(); else pass(); | ||
182 | |||
183 | cout << "set longer name in drive image" << endl; | ||
184 | testfs->setvolumename("mylongervolumename"); // only in memory!!! | ||
185 | volname=testfs->volumename(); | ||
186 | if (*volname!="mylongervolumename") fail(); else pass(); | ||
187 | |||
188 | cout << "Test truncating too long volume name in drive image" << endl; | ||
189 | testfs->setvolumename("myoverlylongvolumenamethemaximumissixtyfourcharactersbutwemakeitlongeranyway"); // only in memory!!! | ||
190 | volname=testfs->volumename(); | ||
191 | if (strlen(volname->c_str())!=64) fail(); else pass(); | ||
192 | cout << "Try to clear volume name" <<endl; | ||
193 | testfs->setvolumename(""); | ||
194 | volname=testfs->volumename(); | ||
195 | if (strlen(volname->c_str())!=0) fail(); else pass(); | ||
196 | cout << "Setting volume name " << endl; | ||
197 | testfs->setvolumename("MyVolume"); | ||
198 | cout << "and commiting for later readback." << endl; | ||
199 | testfs->savedriveinfo(); // auto-commit | ||
200 | cout << "Commit done." << endl; | ||
201 | return; | ||
202 | } | ||
203 | |||
204 | void test_commit() | ||
205 | { | ||
206 | string* strtest=new string("testimage2.h24"); | ||
207 | |||
208 | cout << "Delete testfs..." << endl; | ||
209 | delete testfs; | ||
210 | testfs=NULL; | ||
211 | |||
212 | pass(); | ||
213 | |||
214 | testfs=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,strtest,false); | ||
215 | delete strtest; | ||
216 | cout << "Reading back volume name" << endl; | ||
217 | string* volname=testfs->volumename(); | ||
218 | cout << "Read back " << *volname << endl; | ||
219 | if (*volname!="MyVolume") fail(); else pass(); | ||
220 | |||
221 | // after commit, drive size must be preserved. | ||
222 | hd24raw* rawfs=new hd24raw(testfs); | ||
223 | __uint32 lastsector=rawfs->getlastsectornum(); | ||
224 | __uint32 expectedlastsector=BITBIGGER; | ||
225 | cout << "Test if image has remained same size: "<< lastsector << endl; | ||
226 | if (lastsector!=expectedlastsector) fail(); else pass(); | ||
227 | |||
228 | |||
229 | testfs->setvolumename("Drive Name"); | ||
230 | testfs->savedriveinfo(); // commit tested before-assume it succeeds. | ||
231 | } | ||
232 | |||
233 | void test_project() | ||
234 | { | ||
235 | string* strtest=new string("testimage2.h24"); | ||
236 | |||
237 | cout << "Delete testfs..." << endl; | ||
238 | delete testfs; | ||
239 | testfs=NULL; | ||
240 | |||
241 | pass(); | ||
242 | |||
243 | testfs=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,strtest,false); | ||
244 | delete strtest; | ||
245 | hd24raw* rawfs=new hd24raw(testfs); | ||
246 | cout << "Checking current project count... (should be 1): "; | ||
247 | int pcount=testfs->projectcount(); | ||
248 | cout << pcount << endl; | ||
249 | if (pcount==1) pass(); else fail("Project count of formatted drive should be 1"); | ||
250 | |||
251 | cout << "Try to get project id 0 (should not be possible)" << endl; | ||
252 | hd24project* proj=testfs->getproject(0); | ||
253 | if (proj==NULL) pass(); else | ||
254 | { | ||
255 | delete proj; | ||
256 | proj=NULL; | ||
257 | fail("Project IDs should be 1 based but are not!"); | ||
258 | } | ||
259 | |||
260 | cout << "Try to get project id 1 (first and only project on drive" << endl; | ||
261 | proj=testfs->getproject(1); | ||
262 | if (proj==NULL) fail("Cannot get only project on drive"); else | ||
263 | { | ||
264 | delete proj; | ||
265 | proj=NULL; | ||
266 | pass(); | ||
267 | } | ||
268 | cout << "Try to get any but the first project on the drive" << endl; | ||
269 | cout << "(using legal project numbers and one too high number)" << endl; | ||
270 | int projsgot=0; | ||
271 | int i=0; | ||
272 | for (i=2; i<=100; i++) | ||
273 | { | ||
274 | if (proj!=NULL) | ||
275 | { | ||
276 | delete proj; | ||
277 | proj=NULL; | ||
278 | } | ||
279 | proj=testfs->getproject(i); | ||
280 | if (proj!=NULL) | ||
281 | { | ||
282 | projsgot++; | ||
283 | fail("Managed to get project number:"); | ||
284 | cout << i << endl; | ||
285 | delete proj; | ||
286 | proj=NULL; | ||
287 | } | ||
288 | } | ||
289 | if (proj!=NULL) | ||
290 | { | ||
291 | delete proj; | ||
292 | proj=NULL; | ||
293 | } | ||
294 | |||
295 | if (projsgot==0) pass(); | ||
296 | |||
297 | cout << "Try if only project on drive is protected from deleting" << endl; | ||
298 | testfs->deleteproject(1); | ||
299 | pcount=testfs->projectcount(); | ||
300 | cout << pcount << endl; | ||
301 | if (pcount==1) pass(); else fail("Only project on drive should not be deletable"); | ||
302 | |||
303 | cout << "Try to create a project..." << endl; | ||
304 | hd24project* newproj=testfs->createproject("selftest project 1"); | ||
305 | if (newproj==NULL) | ||
306 | { | ||
307 | fail("Creating project failed"); | ||
308 | } else { | ||
309 | pass(); | ||
310 | } | ||
311 | delete newproj; // we won't be using this object anymore. | ||
312 | |||
313 | cout << "Make sure project creation updates project count..." << endl; | ||
314 | pcount=testfs->projectcount(); | ||
315 | if (pcount==2) pass(); else fail("Project count should have been 2 at this stage."); | ||
316 | cout << "Trying to delete newly created project..." << endl; | ||
317 | testfs->deleteproject(2); | ||
318 | pcount=testfs->projectcount(); | ||
319 | if (pcount==1) pass(); else fail("Deletion successful"); | ||
320 | |||
321 | cout << "Trying to create 98 new projects (should be possible)..." << endl; | ||
322 | char projname[64]; | ||
323 | int failedcreate=0; | ||
324 | for (i=0;i<98;i++) | ||
325 | { | ||
326 | cout << "project=" << i << endl; | ||
327 | sprintf(projname,"selftest project %d",i+2); | ||
328 | hd24project* newproj=testfs->createproject(projname); | ||
329 | pcount=testfs->projectcount(); | ||
330 | if (pcount!=(i+2)) | ||
331 | { | ||
332 | sprintf(projname,"could not create project %d",i); | ||
333 | fail(projname); | ||
334 | failedcreate=1; | ||
335 | break; | ||
336 | }; | ||
337 | delete newproj; | ||
338 | } | ||
339 | if (failedcreate==0) | ||
340 | { | ||
341 | pass(); | ||
342 | } | ||
343 | cout << "Checking if project count is 99 as expected " << endl; | ||
344 | pcount=testfs->projectcount(); | ||
345 | if (pcount==99) pass(); else fail("Nope."); | ||
346 | |||
347 | cout << "Trying if creating more projects than allowed is prevented" << endl; | ||
348 | newproj=NULL; | ||
349 | newproj=testfs->createproject(projname); | ||
350 | if (newproj!=NULL) | ||
351 | { | ||
352 | fail("Project object was returned!"); | ||
353 | } else { | ||
354 | pass(); | ||
355 | } | ||
356 | |||
357 | pcount=testfs->projectcount(); | ||
358 | cout << "Verifying project count to still be 99" <<endl; | ||
359 | if (pcount==99) pass(); else fail("Project count unduely updated."); | ||
360 | |||
361 | cout << "Deleting last 50 projects" << endl; | ||
362 | /* this should leave 49 projects in place. */ | ||
363 | for (i=1;i<60;i++) | ||
364 | { | ||
365 | testfs->deleteproject(50); | ||
366 | } | ||
367 | pcount=testfs->projectcount(); | ||
368 | if (pcount==49) pass(); else fail("Incorrect project count."); | ||
369 | cout << "Creating 50th project again" << i << endl; | ||
370 | sprintf(projname,"selftest project %d",i+2); | ||
371 | if (newproj!=NULL) delete newproj; | ||
372 | |||
373 | newproj=testfs->createproject(projname); | ||
374 | pcount=testfs->projectcount(); | ||
375 | cout << "Expecting project count to be 50 now..." << endl; | ||
376 | if (pcount!=50) fail("Incorrect project count"); else pass(); | ||
377 | |||
378 | cout << "Checking project sector of first project (must be 0x14 or 20)" << endl; | ||
379 | __uint32 projsec= rawfs->getprojectsectornum(1); | ||
380 | cout << "Proj sector=" << projsec << endl; | ||
381 | if (projsec!=0x14) fail("Incorrect sector"); else pass(); | ||
382 | |||
383 | cout << "Deleting first project (to empty a slot)" << endl; | ||
384 | pcount=testfs->projectcount(); | ||
385 | cout << "project count BEFORE=" <<pcount <<endl; | ||
386 | |||
387 | testfs->deleteproject(1); | ||
388 | int pcount2=testfs->projectcount(); | ||
389 | cout << "Project count AFTER=" <<pcount2 << endl; | ||
390 | if (pcount2!=(pcount-1)) fail("Expected project count to be 49."); else pass(); | ||
391 | projsec= rawfs->getprojectsectornum(1); | ||
392 | cout << "Second project should originally have been on 0x15,"<<endl; | ||
393 | cout << "expecting first project to start on that sector now..." <<endl; | ||
394 | cout << "(in reality it is on " << projsec << ")" << endl; | ||
395 | if (projsec!=0x15) fail("Incorrect sector"); else pass(); | ||
396 | /* now create a new project-- this project must be on sector 0x14 | ||
397 | again */ | ||
398 | cout << "Creating new project - it should overwrite the first project block" << endl; | ||
399 | newproj=testfs->createproject(projname); | ||
400 | pcount=testfs->projectcount(); | ||
401 | cout << "Expecting project count of 50 again, in reality it is " << pcount << endl; | ||
402 | if (pcount!=50) fail("Incorrect project count"); else pass(); | ||
403 | __sint32 projid=newproj->projectid(); | ||
404 | cout << "Project id=" << projid << endl; | ||
405 | if (projid!=50) { | ||
406 | fail("Unexpected project id"); | ||
407 | } | ||
408 | projsec=rawfs->getprojectsectornum(projid); | ||
409 | cout << "Expecting project sector of project " << projid << " to be 0x14," ; | ||
410 | cout << " in reality it is " << projsec << endl; | ||
411 | |||
412 | if (projsec!=0x14) fail("Incorrect sector"); else pass(); | ||
413 | |||
414 | newproj->projectname("Changed Name"); | ||
415 | string* projcname=newproj->projectname(); | ||
416 | if (*projcname!="Changed Name") fail("Project name change unsuccessful"); else pass(); | ||
417 | delete projcname; | ||
418 | newproj->save(); | ||
419 | delete rawfs; | ||
420 | } | ||
421 | |||
422 | |||
423 | void test_proj2() | ||
424 | { | ||
425 | int pcount; | ||
426 | string* strtest=new string("testimage2.h24"); | ||
427 | |||
428 | cout << "Delete testfs..." << endl; | ||
429 | delete testfs; | ||
430 | testfs=NULL; | ||
431 | |||
432 | pass(); | ||
433 | |||
434 | testfs=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,strtest,false); | ||
435 | delete strtest; | ||
436 | cout << "Checking current project count... (should be 50): "; | ||
437 | |||
438 | pcount=testfs->projectcount(); | ||
439 | cout << "Expecting project count of 50 again, in reality it is " << pcount << endl; | ||
440 | if (pcount!=50) fail("Incorrect project count"); else pass(); | ||
441 | cout << "Getting existing project no. 50..." << endl; | ||
442 | hd24project* currproj=testfs->getproject(50); | ||
443 | if (currproj==NULL) { fail("Cannot get project"); } else {pass();} | ||
444 | cout << "Getting project name: "; | ||
445 | string* pname=currproj->projectname(); | ||
446 | cout << *pname << endl; | ||
447 | if (*pname!="Changed Name") fail("Project name change unsuccessful"); else pass(); | ||
448 | |||
449 | // delete rawfs; | ||
450 | |||
451 | } | ||
452 | |||
453 | void test_song() | ||
454 | { | ||
455 | string* strtest=new string("testimage2.h24"); | ||
456 | |||
457 | cout << "Delete testfs..." << endl; | ||
458 | delete testfs; | ||
459 | testfs=NULL; | ||
460 | |||
461 | pass(); | ||
462 | |||
463 | testfs=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,strtest,false); | ||
464 | delete strtest; | ||
465 | |||
466 | // Check on-disk songcount | ||
467 | hd24raw* rawfs=new hd24raw(testfs); | ||
468 | int songcount=rawfs->songsondisk(); | ||
469 | cout << "Checking if song count is still zero as it should be "<<endl; | ||
470 | if (songcount!=0) | ||
471 | { | ||
472 | fail("Song count of newly formatted drive should be 0."); | ||
473 | } else { | ||
474 | pass(); | ||
475 | } | ||
476 | |||
477 | delete rawfs; | ||
478 | |||
479 | } | ||
480 | |||
481 | void test_demoimage() | ||
482 | { | ||
483 | string* strtest=new string("testimage2.h24"); | ||
484 | |||
485 | cout << "Delete testfs..." << endl; | ||
486 | delete testfs; | ||
487 | testfs=NULL; | ||
488 | |||
489 | pass(); | ||
490 | |||
491 | testfs=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,strtest,false); | ||
492 | delete strtest; | ||
493 | |||
494 | testfs->setvolumename("Sizeable Hard Drive"); // only in memory!!! | ||
495 | testfs->commit(); | ||
496 | |||
497 | string* volname=testfs->volumename(); | ||
498 | if (*volname!="Sizeable Hard Drive") fail(); else pass(); | ||
499 | delete volname; | ||
500 | |||
501 | cout << "Checking FS version..." << endl; | ||
502 | string* version=testfs->version(); | ||
503 | if (*version!="1.10") fail("Unexpected FS version (expectation was 1.10)"); else pass(); | ||
504 | delete version; | ||
505 | |||
506 | cout << "Checking max. project count (99 expected)..." << endl; | ||
507 | __uint32 maxprojcount=testfs->maxprojects(); | ||
508 | if (maxprojcount!=99) fail("Unexpected max project count"); else pass(); | ||
509 | |||
510 | cout << "Checking block size..." << endl; | ||
511 | if (testfs->getblocksizeinsectors() != 0x480) fail("Unexpected block size"); else pass(); | ||
512 | |||
513 | // delete all but last project | ||
514 | while (testfs->projectcount()>1) | ||
515 | { | ||
516 | // leave only last project | ||
517 | testfs->deleteproject(2); | ||
518 | } | ||
519 | |||
520 | // now up the total project count to 42 | ||
521 | char projname[64]; | ||
522 | int i=1; | ||
523 | hd24project* newproj=NULL; | ||
524 | while (testfs->projectcount()!=42) | ||
525 | { | ||
526 | i++; | ||
527 | sprintf(projname,"selftest project %d",i+2); | ||
528 | int prevprojcount=testfs->projectcount(); | ||
529 | newproj=testfs->createproject(projname); | ||
530 | int newprojcount=testfs->projectcount(); | ||
531 | if (newprojcount==prevprojcount) | ||
532 | { | ||
533 | fail("Failed to create project."); | ||
534 | break; | ||
535 | } | ||
536 | if (newproj!=NULL) | ||
537 | { | ||
538 | delete newproj; | ||
539 | newproj=NULL; | ||
540 | } | ||
541 | |||
542 | } | ||
543 | if (newproj!=NULL) | ||
544 | { | ||
545 | delete newproj; // we won't be using this object anymore. | ||
546 | newproj=NULL; | ||
547 | } | ||
548 | |||
549 | // rename project now. | ||
550 | hd24project* currproj; | ||
551 | currproj=testfs->getproject(15); // must error | ||
552 | testfs->lastprojectid(15); | ||
553 | currproj->projectname("Client X"); | ||
554 | currproj->save(); | ||
555 | volname=testfs->volumename(); | ||
556 | cout <<"Volume name="<<*volname <<endl; | ||
557 | testfs->commit(); | ||
558 | delete currproj; | ||
559 | currproj=NULL; | ||
560 | currproj=testfs->getproject(15); | ||
561 | cout << "Test if project name change with commit works..." << endl; | ||
562 | cout << "Projname is supposed to be 'Client X', and is: "; | ||
563 | string* sprojname=currproj->projectname(); | ||
564 | cout << *sprojname << endl; | ||
565 | if (*sprojname!="Client X") fail("project name change failed."); else pass(); | ||
566 | delete sprojname; | ||
567 | cout << "Testing if song count is zero..." << endl; | ||
568 | if (currproj->songcount()==0) pass(); else fail("Should have been 0"); | ||
569 | |||
570 | // Now it's time to create some songs. | ||
571 | for (i=0;i<12;i++) | ||
572 | { | ||
573 | hd24song* currsong=currproj->createsong("A Huge Hit",24,48000); | ||
574 | currsong->save(); | ||
575 | delete currsong; | ||
576 | } | ||
577 | currproj->lastsongid(8); | ||
578 | currproj->save(); | ||
579 | testfs->commit(); | ||
580 | hd24song* currsong=currproj->getsong(currproj->lastsongid()); | ||
581 | cout << "Renaming song..." << endl; | ||
582 | currsong->songname("A Huge Hit (final take)"); | ||
583 | currsong->save(); | ||
584 | testfs->commit(); | ||
585 | delete currsong; | ||
586 | currsong=NULL; | ||
587 | currsong=currproj->getsong(currproj->lastsongid()); | ||
588 | cout << "Checking if song ID is equal to last set..." << endl; | ||
589 | if (currsong->songid()==8) pass(); else fail("Incorrect songid."); | ||
590 | string* freespacebefore=testfs->freespace(48000,24); | ||
591 | cout << "Lengthening song..." << endl; | ||
592 | __uint32 desiredlen=10416000; //00:03:37.00 | ||
593 | __uint32 newlen=currsong->songlength_in_samples(desiredlen); | ||
594 | if (newlen!=desiredlen) | ||
595 | { | ||
596 | fail("Song lengthening failed."); | ||
597 | cout << "Length in samples is " << newlen | ||
598 | << "instead of " << desiredlen << endl; | ||
599 | } else pass(); | ||
600 | |||
601 | currsong->setwriteprotected(true); | ||
602 | currsong->save(); | ||
603 | testfs->commit(); | ||
604 | cout << "Free space on drive before lengthening: " << *freespacebefore << endl; | ||
605 | string* freespace=testfs->freespace(48000,24); | ||
606 | cout << "Free space on drive after lengthening: " << *freespace << endl; | ||
607 | delete freespace; | ||
608 | } | ||
609 | |||
610 | int runselftest(HD24UserInterface* ui) | ||
611 | { | ||
612 | cout << "=======TESTMODE ACTIVATED=======" << endl; | ||
613 | passcount=0; | ||
614 | failcount=0; | ||
615 | test_createimage(); | ||
616 | test_useimage(); | ||
617 | test_commit(); | ||
618 | test_project(); | ||
619 | test_proj2(); | ||
620 | |||
621 | test_song(); | ||
622 | test_demoimage(); // create an interesting looking demo drive image | ||
623 | |||
624 | |||
625 | cout << "Create 1 project, 99 projects, try 100th project" << endl; | ||
626 | |||
627 | cout << "Create 1..99 songs" << endl; | ||
628 | |||
629 | cout << "rename projects, rename songs" << endl; | ||
630 | |||
631 | cout << "Delete 1.99 projects/songs" << endl; | ||
632 | |||
633 | cout << "Record audio to songs" << endl; | ||
634 | |||
635 | // Proceed to test gui. | ||
636 | |||
637 | Fl_Window* window=ui->make_window(testfs); | ||
638 | window->end(); | ||
639 | window->show(); | ||
640 | fl_message("Proceeding to test GUI."); | ||
641 | cout << "====================== TEST COMPLETE ===================" << endl; | ||
642 | cout << "PASS: " << passcount << endl; | ||
643 | cout << "FAIL: " << failcount << endl; | ||
644 | cout << "========================================================" << endl; | ||
645 | return 0; | ||
646 | } | ||
diff --git a/src/frontend/ui_hd24connect.fl b/src/frontend/ui_hd24connect.fl new file mode 100755 index 0000000..eae32ad --- /dev/null +++ b/src/frontend/ui_hd24connect.fl | |||
@@ -0,0 +1,4597 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0109 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {class HD24TrackChannel;} {public | ||
6 | } | ||
7 | |||
8 | decl {class TrackInfo;} {public | ||
9 | } | ||
10 | |||
11 | decl {class HD24UserInterface;} {public | ||
12 | } | ||
13 | |||
14 | decl {class MixerUI;} {public | ||
15 | } | ||
16 | |||
17 | decl {class RecorderUI;} {public | ||
18 | } | ||
19 | |||
20 | decl {class PortAudioWrapper;} {public | ||
21 | } | ||
22 | |||
23 | decl {class JackWrapper;} {public | ||
24 | } | ||
25 | |||
26 | decl {class hd24transferengine;} {public | ||
27 | } | ||
28 | |||
29 | decl {\#define HD24DEBUG 0} {public | ||
30 | } | ||
31 | |||
32 | decl {\#define BLINKRATE 25} {public | ||
33 | } | ||
34 | |||
35 | decl {\#define PA_FRAMESPERBUF 512} {public | ||
36 | } | ||
37 | |||
38 | decl {\#define MAXCHANNELS 24} {public | ||
39 | } | ||
40 | |||
41 | decl {\#define UIREFRESH 1 /* 1=best, 10=1/10 refresh rate */} {public | ||
42 | } | ||
43 | |||
44 | decl {\#define HD24MODE hd24fs::MODE_RDWR} {public | ||
45 | } | ||
46 | |||
47 | decl {\#define TIMEOUT 0.03} {public | ||
48 | } | ||
49 | |||
50 | decl {\#define SPLITFILESIZE_BYTES ((__uint64)(1024*1024*1024))} {public | ||
51 | } | ||
52 | |||
53 | decl {\#include <config.h>} {public | ||
54 | } | ||
55 | |||
56 | decl {\#include <string>} {public | ||
57 | } | ||
58 | |||
59 | decl {\#include <vector>} {public | ||
60 | } | ||
61 | |||
62 | decl {\#include <portwin.h>} {public | ||
63 | } | ||
64 | |||
65 | decl {\#include <soundlibs.h> /* portaudio, libjack */} {public | ||
66 | } | ||
67 | |||
68 | decl {\#include <iostream>} {public | ||
69 | } | ||
70 | |||
71 | decl {\#include <FL/FLTKstuff.H>} {public | ||
72 | } | ||
73 | |||
74 | decl {\#include <FL/Fl_Menu_Bar.H>} {public | ||
75 | } | ||
76 | |||
77 | decl {\#include <FL/Fl_File_Chooser.H>} {public | ||
78 | } | ||
79 | |||
80 | decl {\#include <FL/filename.H>} {public | ||
81 | } | ||
82 | |||
83 | decl {\#include <xplat_dlfcn.h>} {public | ||
84 | } | ||
85 | |||
86 | decl {\#include <sndfile.h>} {public | ||
87 | } | ||
88 | |||
89 | decl {\#include <convertlib.h>} {public | ||
90 | } | ||
91 | |||
92 | decl {\#include <memutils.h>} {public | ||
93 | } | ||
94 | |||
95 | decl {\#include <hd24fs.h>} {public | ||
96 | } | ||
97 | |||
98 | decl {\#include <hd24utils.h>} {public | ||
99 | } | ||
100 | |||
101 | decl {\#include <hd24transferengine.h>} {public | ||
102 | } | ||
103 | |||
104 | decl {\#include <smpte.h>} {public | ||
105 | } | ||
106 | |||
107 | decl {\#include <WidgetPDial.h>} {public | ||
108 | } | ||
109 | |||
110 | decl {\#include <dialog_newproject.h>} {public | ||
111 | } | ||
112 | |||
113 | decl {\#include <dialog_newsong.h>} {public | ||
114 | } | ||
115 | |||
116 | decl {\#include <dialog_setlocate.h>} {public | ||
117 | } | ||
118 | |||
119 | decl {\#include <dialog_filesize.h>} {public | ||
120 | } | ||
121 | |||
122 | decl {\#include <dialog_setlength.h>} {public | ||
123 | } | ||
124 | |||
125 | decl {\#include <dialog_fromto.h>} {public | ||
126 | } | ||
127 | |||
128 | decl {\#include <dialog_rename.h>} {public | ||
129 | } | ||
130 | |||
131 | decl {\#include <dialog_options.h>} {public | ||
132 | } | ||
133 | |||
134 | decl {\#include <dialog_choosedevice.h>} {public | ||
135 | } | ||
136 | |||
137 | decl {\#include <ui_help_about.h>} {public | ||
138 | } | ||
139 | |||
140 | decl {\#include <ui_mixer.h>} {public | ||
141 | } | ||
142 | |||
143 | decl {\#include <time.h>} {public | ||
144 | } | ||
145 | |||
146 | decl {\#include <math.h>} {public | ||
147 | } | ||
148 | |||
149 | decl {\#include <ui_hd24trackchannel.h>} {public | ||
150 | } | ||
151 | |||
152 | decl {\#include <ui_recorder.h>} {public | ||
153 | } | ||
154 | |||
155 | decl {class HD24UserInterface;} {public | ||
156 | } | ||
157 | |||
158 | decl {class HD24control;} {public | ||
159 | } | ||
160 | |||
161 | decl {class SoundFileWrapper;} {public | ||
162 | } | ||
163 | |||
164 | class HD24data {} { | ||
165 | decl {HD24UserInterface* parentui;} {} | ||
166 | decl {friend class HD24control;} {} | ||
167 | decl {int ready;} {public | ||
168 | } | ||
169 | } | ||
170 | |||
171 | class HD24control {} { | ||
172 | decl {HD24data* data;} {} | ||
173 | Function {parentui(HD24UserInterface* p_parentui)} {open | ||
174 | } { | ||
175 | code {data->parentui=p_parentui;} {} | ||
176 | } | ||
177 | Function {parentui()} {open return_type {HD24UserInterface*} | ||
178 | } { | ||
179 | code {return data->parentui;} {} | ||
180 | } | ||
181 | Function {HD24control()} {open | ||
182 | } { | ||
183 | code {data=new HD24data();} {} | ||
184 | } | ||
185 | Function {~HD24control()} {open | ||
186 | } { | ||
187 | code {delete data;} {} | ||
188 | } | ||
189 | Function {ready()} {open return_type int | ||
190 | } { | ||
191 | code {return data->ready;} {} | ||
192 | } | ||
193 | Function {ready(int p_ready)} {open return_type void | ||
194 | } { | ||
195 | code {data->ready=p_ready;} {} | ||
196 | } | ||
197 | } | ||
198 | |||
199 | decl {\#include <hd24sndfile.h>} {public | ||
200 | } | ||
201 | |||
202 | class HD24UserInterface {open | ||
203 | } { | ||
204 | decl {hd24transferengine* transeng;} {} | ||
205 | decl {HD24control* control;} {public | ||
206 | } | ||
207 | decl {PortAudioWrapper* portaudio;} {public | ||
208 | } | ||
209 | decl {SoundFileWrapper* soundfile;} {public | ||
210 | } | ||
211 | decl {JackWrapper* libjack;} {public | ||
212 | } | ||
213 | decl {int busy;} {public | ||
214 | } | ||
215 | decl {hd24fs* defaulthd24;} {} | ||
216 | decl {hd24fs* currenthd24;} {public | ||
217 | } | ||
218 | decl {int trackselected[24];} {public | ||
219 | } | ||
220 | decl {hd24project* currproj;} {public | ||
221 | } | ||
222 | decl {hd24song* currsong;} {public | ||
223 | } | ||
224 | decl {Fl_Check_Button* track[24];} {public | ||
225 | } | ||
226 | decl {int tracksave[24]; /* to keep track[24] settings */} {public | ||
227 | } | ||
228 | decl {vector<string> format_outputextension;} {public | ||
229 | } | ||
230 | decl {vector<string> format_shortdesc;} {public | ||
231 | } | ||
232 | Function {deactivate_ui()} {open return_type void | ||
233 | } { | ||
234 | code {drivename->deactivate(); | ||
235 | rename_drive->deactivate(); | ||
236 | projectname->deactivate(); | ||
237 | rename_project->deactivate(); | ||
238 | songname->deactivate(); | ||
239 | songinfogroup->deactivate(); | ||
240 | tabDrive->deactivate(); | ||
241 | rename_song->deactivate(); | ||
242 | locatepoints->deactivate(); | ||
243 | fromto->deactivate(); | ||
244 | transfercanvas->deactivate(); | ||
245 | menufile->deactivate(); | ||
246 | tabRecorder->deactivate(); | ||
247 | tabMixer->deactivate(); | ||
248 | menuhelp->deactivate();} {} | ||
249 | } | ||
250 | Function {disable_program_controls()} {return_type void | ||
251 | } { | ||
252 | code {drivename->deactivate(); | ||
253 | rename_drive->deactivate(); | ||
254 | projectname->deactivate(); | ||
255 | rename_project->deactivate(); | ||
256 | songname->deactivate(); | ||
257 | rename_song->deactivate(); | ||
258 | transfercanvas->deactivate(); | ||
259 | locatepoints->deactivate(); | ||
260 | fromto->deactivate(); | ||
261 | button_golocatepoint->deactivate(); | ||
262 | recorder->control->disable();} {} | ||
263 | } | ||
264 | Function {activate_ui()} {open return_type void | ||
265 | } { | ||
266 | code {drivename->activate(); | ||
267 | transfercanvas->activate(); | ||
268 | tabRecorder->activate(); | ||
269 | projectname->activate(); | ||
270 | songname->activate(); | ||
271 | songinfogroup->activate(); | ||
272 | tabDrive->activate(); | ||
273 | tabMixer->activate(); | ||
274 | locatepoints->activate(); | ||
275 | fromto->activate(); | ||
276 | menufile->activate(); | ||
277 | menuhelp->activate();} {} | ||
278 | } | ||
279 | Function {addsongtodropdown(int i)} {} { | ||
280 | code {\#if (HD24DEBUG==1) | ||
281 | cout << "addsongtodropdown " << i << endl; | ||
282 | cout << "set song" << endl; | ||
283 | \#endif | ||
284 | hd24song* song=currproj->getsong(i); | ||
285 | \#if (HD24DEBUG==1) | ||
286 | cout << "song is set" << endl; | ||
287 | \#endif | ||
288 | string* strsongname=Convert::int2str(i); | ||
289 | *strsongname+=": "; | ||
290 | string* actualname=song->songname(); | ||
291 | *strsongname+=*actualname; | ||
292 | delete actualname; | ||
293 | |||
294 | \#if (HD24DEBUG==1) | ||
295 | cout << "song is set2" << endl; | ||
296 | \#endif | ||
297 | songname->add(strsongname->c_str(),0,(void (*)(Fl_Widget*,void*))(&(songname_cb)),(void*)this); | ||
298 | \#if (HD24DEBUG==1) | ||
299 | cout << "song is set3" << endl; | ||
300 | \#endif | ||
301 | delete song; | ||
302 | delete(strsongname);} {} | ||
303 | } | ||
304 | Function {populate_projectlist(int projectid)} {return_type void | ||
305 | } { | ||
306 | code {/* Set project info */ | ||
307 | int i; | ||
308 | \#if (HD24DEBUG==1) | ||
309 | cout << "clear project list" << endl; | ||
310 | \#endif | ||
311 | for (i=0;i<=100;i++) { | ||
312 | projectname->remove(0); | ||
313 | } | ||
314 | int numprojs=0; | ||
315 | if (currenthd24==NULL) { | ||
316 | return; | ||
317 | } | ||
318 | numprojs=currenthd24->projectcount(); | ||
319 | for (i=1; i<=numprojs; i++) { | ||
320 | hd24project* currproj=currenthd24->getproject(i); | ||
321 | string* projname1=Convert::int2str(i); | ||
322 | *projname1+=": "; | ||
323 | string* currpname=currproj->projectname(); | ||
324 | *projname1+=*currpname; | ||
325 | projectname->add(projname1->c_str(),0,(void (*)(Fl_Widget*,void*))(&(projectname_cb)),(void*)this); | ||
326 | delete(currpname); | ||
327 | delete(projname1); | ||
328 | delete currproj; | ||
329 | } | ||
330 | |||
331 | select_project(projectid);} {} | ||
332 | } | ||
333 | Function {populate_songlist(int songid)} {open return_type void | ||
334 | } { | ||
335 | code {int i; | ||
336 | int numsongs=currproj->songcount(); | ||
337 | \#if (HD24DEBUG==1) | ||
338 | cout << "populate_songlist" << endl; | ||
339 | \#endif | ||
340 | if (numsongs==0) | ||
341 | { | ||
342 | \#if (HD24DEBUG==1) | ||
343 | cout << "no songs" << endl; | ||
344 | \#endif | ||
345 | for (i=0;i<=100;i++) { | ||
346 | songname->remove(0); | ||
347 | } | ||
348 | songname->add("-- Empty project --",0,NULL,(void*)this); | ||
349 | songname->value(0); | ||
350 | refresh(songname); | ||
351 | return; | ||
352 | } | ||
353 | songname->activate(); | ||
354 | \#if (HD24DEBUG==1) | ||
355 | cout << "clear songlist" << endl; | ||
356 | \#endif | ||
357 | for (i=0;i<=100;i++) { | ||
358 | songname->remove(0); | ||
359 | } | ||
360 | |||
361 | songname->add("-- All songs --",0,(void (*)(Fl_Widget*,void*))(&(songname_cb)),(void*)this); | ||
362 | |||
363 | \#if (HD24DEBUG==1) | ||
364 | cout << "Add songs to dropdown" << endl; | ||
365 | \#endif | ||
366 | for (i=1; i<=numsongs; i++) { | ||
367 | addsongtodropdown(i); | ||
368 | } | ||
369 | control->ready(1); | ||
370 | this->busy=0; | ||
371 | |||
372 | \#if (HD24DEBUG==1) | ||
373 | cout << "about to select last used song" << endl; | ||
374 | \#endif | ||
375 | signed long lastsong=currproj->lastsongid(); | ||
376 | if (lastsong<1) { | ||
377 | lastsong=0; | ||
378 | } | ||
379 | \#if (HD24DEBUG==1) | ||
380 | cout << "got last song id:" << lastsong << endl; | ||
381 | \#endif | ||
382 | if (lastsong==0) { | ||
383 | songname->value(0); | ||
384 | songname->redraw(); | ||
385 | return; | ||
386 | } | ||
387 | select_song(lastsong); | ||
388 | songname->redraw();} {} | ||
389 | } | ||
390 | Function {populate_drivelist(int driveid)} {open return_type void | ||
391 | } { | ||
392 | code {// when another drive has been selected, init dropdown lists. | ||
393 | for (unsigned int q=0;q<=99;q++) { | ||
394 | drivename->remove(0); | ||
395 | } | ||
396 | // find out how many ADAT drives are detected. | ||
397 | unsigned int devcount=defaulthd24->hd24devicecount(); | ||
398 | \#if (HD24DEBUG==1) | ||
399 | cout << "devcount=" << devcount << endl; | ||
400 | \#endif | ||
401 | unsigned int usedevcount=devcount; | ||
402 | if (devcount==0) usedevcount=1; // we are using a file image. | ||
403 | for (unsigned int devnum=0;devnum<usedevcount;devnum++) | ||
404 | { | ||
405 | \#if (HD24DEBUG==1) | ||
406 | cout << "devnum" << devnum << endl; | ||
407 | \#endif | ||
408 | // currhd24 is not a spelling error. it is for local use. | ||
409 | string* idir=hd24utils::getlastdir("driveimagedir"); | ||
410 | hd24fs* currhd24 = new hd24fs(idir->c_str(),defaulthd24->mode(),devnum); | ||
411 | delete idir; | ||
412 | if (!(currhd24->isOpen())) { | ||
413 | if (!(defaulthd24->isOpen())) { | ||
414 | disable_program_controls(); | ||
415 | } | ||
416 | } | ||
417 | \#if (HD24DEBUG==1) | ||
418 | cout << "newfs" << devnum << endl; | ||
419 | \#endif | ||
420 | |||
421 | string* drivename1=Convert::int2str(devnum+1); | ||
422 | |||
423 | *drivename1+=": "; | ||
424 | string* volname; | ||
425 | |||
426 | \#if (HD24DEBUG==1) | ||
427 | cout << "getvolname" << devnum << endl; | ||
428 | \#endif | ||
429 | |||
430 | if (devcount!=usedevcount) | ||
431 | { | ||
432 | volname=currenthd24->volumename(); | ||
433 | } else { | ||
434 | volname=currhd24->volumename(); | ||
435 | } | ||
436 | |||
437 | \#if (HD24DEBUG==1) | ||
438 | cout << "gotvolname" << devnum << endl; | ||
439 | \#endif | ||
440 | |||
441 | *drivename1+=*volname; | ||
442 | // NULL=callback | ||
443 | drivename->add(drivename1->c_str(),0,(void (*)(Fl_Widget*,void*))(&(drivename_cb)),(void*)this); | ||
444 | delete(currhd24); | ||
445 | delete(volname); | ||
446 | delete(drivename1); | ||
447 | } | ||
448 | |||
449 | /* Set drive info */ | ||
450 | \#if (HD24DEBUG==1) | ||
451 | cout << "set drivename dropdown value to " << driveid << endl; | ||
452 | \#endif | ||
453 | drivename->value(driveid);} {} | ||
454 | } | ||
455 | Function {populate_locatepoints(hd24song* locsong,Fl_Choice* lpoints)} {open return_type int | ||
456 | } { | ||
457 | code {int i; | ||
458 | int numpoints=0; | ||
459 | if (locsong!=NULL) | ||
460 | { | ||
461 | numpoints=locsong->locatepointcount(); | ||
462 | } | ||
463 | |||
464 | \#if (HD24DEBUG==1) | ||
465 | cout << "populate_lpoints" << endl; | ||
466 | \#endif | ||
467 | if (numpoints==0) | ||
468 | { | ||
469 | \#if (HD24DEBUG==1) | ||
470 | cout << "no locate points." << endl; | ||
471 | \#endif | ||
472 | for (i=0;i<=99;i++) { | ||
473 | lpoints->remove(0); | ||
474 | } | ||
475 | lpoints->deactivate(); | ||
476 | refresh(lpoints); | ||
477 | return numpoints; | ||
478 | } | ||
479 | lpoints->activate(); | ||
480 | \#if (HD24DEBUG==1) | ||
481 | cout << "clear lpoints" << endl; | ||
482 | \#endif | ||
483 | for (i=0;i<=99;i++) { | ||
484 | lpoints->remove(0); | ||
485 | } | ||
486 | for (i=0; i<numpoints+1; i++) { | ||
487 | // locatepoint (max+1) is a virtual locate point 'END'. | ||
488 | \#if (HD24DEBUG==1) | ||
489 | cout << "set locate point" << endl; | ||
490 | \#endif | ||
491 | __uint32 locatepos=locsong->getlocatepos(i); | ||
492 | \#if (HD24DEBUG==1) | ||
493 | cout << "locate pos "<<i<<" is " << locatepos << endl; | ||
494 | \#endif | ||
495 | string* locname1; | ||
496 | if ((i==0)||(i==numpoints)) { | ||
497 | locname1=locsong->getlocatename(i); | ||
498 | |||
499 | if ((locname1->length())>0) { | ||
500 | while (locname1->substr(0,1)==" ") { | ||
501 | *locname1=locname1->substr(1,locname1->length()-1); | ||
502 | } | ||
503 | while (locname1->substr(locname1->length()-1,1)==" ") { | ||
504 | *locname1=locname1->substr(0,locname1->length()-1); | ||
505 | } | ||
506 | } else { | ||
507 | *locname1+="START"; | ||
508 | } | ||
509 | *locname1+=": "; | ||
510 | if (i==numpoints) { | ||
511 | *locname1+="+"; | ||
512 | } | ||
513 | string* dur=locsong->display_duration(locatepos); | ||
514 | *locname1+=*dur; | ||
515 | delete (dur); | ||
516 | } else { | ||
517 | locname1=Convert::int2str(i,2,"0"); | ||
518 | *locname1+=": +"; | ||
519 | string* dur=locsong->display_duration(locatepos); | ||
520 | *locname1+=*dur; | ||
521 | delete (dur); | ||
522 | *locname1+=" "; | ||
523 | string* lni=locsong->getlocatename(i); | ||
524 | *locname1+=*lni; | ||
525 | delete(lni); | ||
526 | } | ||
527 | |||
528 | \#if (HD24DEBUG==1) | ||
529 | cout << "add lpoints" << endl; | ||
530 | \#endif | ||
531 | lpoints->add(locname1->c_str(),0,NULL,(void*)this); | ||
532 | delete locname1; | ||
533 | lpoints->redraw(); | ||
534 | \#if (HD24DEBUG==1) | ||
535 | cout << "added lpoints" << endl; | ||
536 | \#endif | ||
537 | } | ||
538 | |||
539 | button_setlocatepoint->activate(); | ||
540 | lpoints->value(0); | ||
541 | this->setlocbuttonlabel(0); | ||
542 | return numpoints;} {} | ||
543 | } | ||
544 | Function {init_vars()} {open return_type void | ||
545 | } { | ||
546 | code {\#if (HD24DEBUG == 1) | ||
547 | cout << "init_vars" << endl; | ||
548 | \#endif | ||
549 | //jackclient=NULL; | ||
550 | //jackmtsample=NULL; | ||
551 | currsong=NULL; | ||
552 | currproj=NULL; | ||
553 | //portaudiostream=NULL; | ||
554 | //inputParameters=new PaStreamParameters; | ||
555 | //outputParameters=new PaStreamParameters; | ||
556 | //portaudiooffset=0; | ||
557 | //pa_streamtime=0; | ||
558 | //portaudio_initialized=0; | ||
559 | //portaudio_mustloop=0; | ||
560 | //portaudio_looppos=0; | ||
561 | mustdisplaytimer=true; | ||
562 | mustdispsavemessage=false; | ||
563 | closingdown=false; | ||
564 | savemessage[0]='\\0'; | ||
565 | refreshingui=0; | ||
566 | //loopmode=0; | ||
567 | //dispwritecountdown=0; | ||
568 | init_gui(0); | ||
569 | Fl::add_timeout(TIMEOUT,poll_callback,this);} {} | ||
570 | } | ||
571 | Function {ui_refresh(const char* orig)} {open | ||
572 | } { | ||
573 | code {/* to prevent re-refresh by selecting current project | ||
574 | which will select a song which will refresh the current | ||
575 | ui again...(in case of corrupt 'unexpected end of song' | ||
576 | songs): */ | ||
577 | if (refreshingui>1) return; | ||
578 | refreshingui++; | ||
579 | |||
580 | // init dropdown lists. | ||
581 | \#if (HD24DEBUG==1) | ||
582 | cout << "==TRIGGER GUI REFRESH FROM "<<orig << "==" << endl; | ||
583 | cout << "going to clear dropdown lists" << endl; | ||
584 | \#endif | ||
585 | for (unsigned int q=0;q<=99;q++) { | ||
586 | projectname->remove(0); | ||
587 | songname->remove(0); | ||
588 | } | ||
589 | int devid=0; | ||
590 | if ((currenthd24!=NULL)&&(currenthd24!=defaulthd24)) | ||
591 | { | ||
592 | devid=currenthd24->getdeviceid(); | ||
593 | if (devid<0) | ||
594 | { | ||
595 | devid=0; | ||
596 | } | ||
597 | } | ||
598 | \#if (HD24DEBUG==1) | ||
599 | cout << "going to populate drive list (" << devid << ")" << endl; | ||
600 | \#endif | ||
601 | |||
602 | populate_drivelist(devid); | ||
603 | |||
604 | // following uses fsys (the default drive) | ||
605 | \#if (HD24DEBUG==1) | ||
606 | cout << "get projcount then?" << endl; | ||
607 | \#endif | ||
608 | string* nump=Convert::int2str(currenthd24->projectcount()); | ||
609 | \#if (HD24DEBUG==1) | ||
610 | cout << "got projcount=" << *nump << endl; | ||
611 | \#endif | ||
612 | number_of_projects->value(nump->c_str()); | ||
613 | delete (nump); | ||
614 | \#if (HD24DEBUG==1) | ||
615 | cout << "last project id=" << currenthd24->lastprojectid() << endl; | ||
616 | \#endif | ||
617 | |||
618 | populate_projectlist(currenthd24->lastprojectid()); | ||
619 | |||
620 | |||
621 | string* cat=new string(""); | ||
622 | if (hd24utils::gencatalog(this->currenthd24,cat)==0) { | ||
623 | this->catalogbuffer->remove(0,this->catalogbuffer->length()-1); | ||
624 | this->catalogbuffer->append(cat->c_str()); | ||
625 | |||
626 | // if (this->catalog->buffer()!=NULL) { | ||
627 | // free(this->catalog->buffer()); | ||
628 | // } | ||
629 | // this->catalog->buffer(cat->c_str()); | ||
630 | } | ||
631 | delete(cat); | ||
632 | \#if (HD24DEBUG==1) | ||
633 | cout << "get version" << endl; | ||
634 | \#endif | ||
635 | string* version1=currenthd24->version(); | ||
636 | \#if (HD24DEBUG==1) | ||
637 | cout << "got version" << endl; | ||
638 | \#endif | ||
639 | fsversion->value(version1->c_str()); | ||
640 | delete(version1); | ||
641 | |||
642 | calcspace(); | ||
643 | Fl::add_timeout(TIMEOUT,poll_callback,this); | ||
644 | |||
645 | refreshingui--;} {} | ||
646 | } | ||
647 | Function {init_gui(int drive)} {open return_type void | ||
648 | } { | ||
649 | code {// int drive is for multi drive support. | ||
650 | |||
651 | // deselect all tracks on ' copy to hd24 tab' | ||
652 | for (unsigned int i=1; i<=MAXCHANNELS; i++) { | ||
653 | trackselected[i-1]=0; | ||
654 | } | ||
655 | // Neither jack or portaudio were found by configure. | ||
656 | // This means no sound is available, so hide the transport controls. | ||
657 | recorder->control->disable(); | ||
658 | recorder->control->audio->mixer(this->mixer->control); | ||
659 | |||
660 | \#if (HD24DEBUG==1) | ||
661 | cout << "init_gui" << endl; | ||
662 | \#endif | ||
663 | Fl::remove_timeout(poll_callback); | ||
664 | ui_refresh("init gui"); | ||
665 | Fl::add_timeout(TIMEOUT,poll_callback,this); | ||
666 | |||
667 | populate_formats(); | ||
668 | \#if (HD24DEBUG==1) | ||
669 | cout << "formats populated" << endl; | ||
670 | \#endif | ||
671 | fromtime->value("START"); | ||
672 | totime->value("END"); | ||
673 | refresh(fromtime); | ||
674 | refresh(totime); | ||
675 | \#if (HD24DEBUG==1) | ||
676 | cout << "init gui complete" << endl; | ||
677 | \#endif | ||
678 | |||
679 | calcspace(); | ||
680 | showprogtitle(); | ||
681 | |||
682 | |||
683 | setstatus("Ready.");} {} | ||
684 | } | ||
685 | Function {drivename_cb(Fl_Widget* w, void* data)} {return_type {static void} | ||
686 | } { | ||
687 | code {\#if (HD24DEBUG==1) | ||
688 | cout << "drivename_cb" << endl; | ||
689 | \#endif | ||
690 | HD24UserInterface *o=(HD24UserInterface *)data; | ||
691 | o->drivename_callback(w,data);} {} | ||
692 | } | ||
693 | Function {drivename_callback(Fl_Widget* w, void* data)} {return_type void | ||
694 | } { | ||
695 | code {\#if (HD24DEBUG==1) | ||
696 | cout << "drivename_callback" << endl; | ||
697 | \#endif | ||
698 | int choicemade=((Fl_Choice*)(w))->value(); | ||
699 | \#if (HD24DEBUG==1) | ||
700 | cout << "chose drive " << choicemade+1 << endl; | ||
701 | \#endif | ||
702 | |||
703 | |||
704 | string* idir=hd24utils::getlastdir("driveimagedir"); | ||
705 | hd24fs* newcurrenthd=new hd24fs(idir->c_str(),defaulthd24->mode(),choicemade); | ||
706 | delete idir; | ||
707 | currenthd24=newcurrenthd; | ||
708 | |||
709 | init_gui(choicemade);} {} | ||
710 | } | ||
711 | Function {trackaction_callback(Fl_Widget* w, void* data)} {return_type void | ||
712 | } { | ||
713 | code {\#if (HD24DEBUG==1) | ||
714 | cout << "trackaction_callback" << endl; | ||
715 | \#endif | ||
716 | int choicemade=((Fl_Choice*)(w))->value(); | ||
717 | if (choicemade==0) { | ||
718 | ((Fl_Choice*)(w))->color(1); | ||
719 | } else { | ||
720 | ((Fl_Choice*)(w))->color(7); | ||
721 | } | ||
722 | \#if (HD24DEBUG==1) | ||
723 | cout << "chose item " << choicemade << endl; | ||
724 | \#endif} {} | ||
725 | } | ||
726 | Function {projectname_cb(Fl_Widget* w, void* data)} {return_type {static void} | ||
727 | } { | ||
728 | code {\#if (HD24DEBUG==1) | ||
729 | cout << "projectname_cb" << endl; | ||
730 | \#endif | ||
731 | HD24UserInterface *o=(HD24UserInterface *)data; | ||
732 | o->projectname_callback(w,data);} {} | ||
733 | } | ||
734 | Function {projectname_callback(Fl_Widget* w, void* data)} {return_type void | ||
735 | } { | ||
736 | code {\#if (HD24DEBUG==1) | ||
737 | cout << "projectname_callback" << endl; | ||
738 | \#endif | ||
739 | int choicemade=((Fl_Choice*)(w))->value(); | ||
740 | select_project(choicemade+1);} {} | ||
741 | } | ||
742 | Function {songname_cb(Fl_Widget* w, void* data)} {open return_type {static void} | ||
743 | } { | ||
744 | code {\#if (HD24DEBUG == 1 ) | ||
745 | cout << "songname_cb" << endl; | ||
746 | \#endif | ||
747 | HD24UserInterface *o=(HD24UserInterface *)data; | ||
748 | o->songname_callback(w,data);} {} | ||
749 | } | ||
750 | Function {songname_callback(Fl_Widget* w, void* data)} {open return_type void | ||
751 | } { | ||
752 | code {\#if (HD24DEBUG==1) | ||
753 | cout << "songname_callback" << endl; | ||
754 | \#endif | ||
755 | int choicemade=((Fl_Choice*)(w))->value(); | ||
756 | if (currproj!=NULL) delete currproj; | ||
757 | currproj=currenthd24->getproject(projectname->value()+1); | ||
758 | //songname->value(choicemade); // should not be needed | ||
759 | select_song(choicemade); // song id=choicemade} {} | ||
760 | } | ||
761 | Function {refresh(Fl_Widget * w)} {open return_type void | ||
762 | } { | ||
763 | code {w->deactivate(); | ||
764 | w->activate();} {} | ||
765 | } | ||
766 | decl {time_t starttime,endtime} {} | ||
767 | Function {calcspace()} {return_type void | ||
768 | } { | ||
769 | code {__uint32 rate; | ||
770 | __uint32 tracks; | ||
771 | |||
772 | switch (atrate->value()) { | ||
773 | case 0: rate=44100; break; | ||
774 | case 1: rate=48000; break; | ||
775 | case 2: rate=88200; break; | ||
776 | case 3: rate=96000; break; | ||
777 | default: return; | ||
778 | } | ||
779 | switch (attracks->value()) { | ||
780 | case 0: tracks=2; break; | ||
781 | case 1: tracks=6; break; | ||
782 | case 2: tracks=8; break; | ||
783 | case 3: tracks=12; break; | ||
784 | case 4: tracks=16; break; | ||
785 | case 5: tracks=24; break; | ||
786 | default: return; | ||
787 | } | ||
788 | string* strfree=currenthd24->freespace(rate,tracks); | ||
789 | freespace->value(strfree->c_str()); | ||
790 | delete (strfree);} {} | ||
791 | } | ||
792 | Function {transferstatus(void* ui,const char* message,double pct)} {open return_type {static void} | ||
793 | } { | ||
794 | code {if (ui==NULL) return; | ||
795 | ((HD24UserInterface*)ui)->statusmsg->value(message); | ||
796 | ((HD24UserInterface*)ui)->fl_check();} {} | ||
797 | } | ||
798 | Function {setstatus(string message)} {open return_type void | ||
799 | } { | ||
800 | code {statusmsg->value(message.c_str()); | ||
801 | fl_check();} {} | ||
802 | } | ||
803 | decl {/* ===File transfer stuff ===================================================== */} {} | ||
804 | decl {Fl_Widget* trackaction[24];} {public | ||
805 | } | ||
806 | decl {int transfer_cancel;} {public | ||
807 | } | ||
808 | decl {Fl_Output* filename[24];} {public | ||
809 | } | ||
810 | Function {savemessage_callback(void* user)} {open return_type {static void} | ||
811 | } { | ||
812 | code {HD24UserInterface* mythis=(HD24UserInterface*)user; | ||
813 | string* stat=new string(mythis->savemessage); | ||
814 | mythis->setstatus(*stat); | ||
815 | //mythis->uicanvas->redraw(); | ||
816 | mythis->statusbar->damage(); | ||
817 | mythis->statusbar->redraw(); | ||
818 | |||
819 | delete (stat); | ||
820 | if (mythis->mustdispsavemessage) { | ||
821 | Fl::repeat_timeout(.25,savemessage_callback,user); | ||
822 | }} {} | ||
823 | } | ||
824 | Function {countfiletracks(const char* filename)} {open return_type int | ||
825 | } { | ||
826 | code {SF_INFO sfinfo; | ||
827 | SNDFILE* infile=NULL; | ||
828 | if (strlen(filename)==0) | ||
829 | { | ||
830 | return 0; | ||
831 | } | ||
832 | infile=soundfile->sf_open(filename,SFM_READ,&sfinfo); | ||
833 | if (!infile) | ||
834 | { | ||
835 | return 0; | ||
836 | } | ||
837 | int numchans=sfinfo.channels; | ||
838 | soundfile->sf_close(infile); | ||
839 | return numchans;} {} | ||
840 | } | ||
841 | decl {char savemessage[300];} {public | ||
842 | } | ||
843 | Function {populate_trackaction(HD24UserInterface* ui,Fl_Widget* o,int tracknum)} {open return_type void | ||
844 | } { | ||
845 | code {if (tracknum<1) { | ||
846 | return; | ||
847 | } | ||
848 | if (tracknum>24) { | ||
849 | return; | ||
850 | } | ||
851 | |||
852 | trackaction[tracknum-1]=o; | ||
853 | |||
854 | ((Fl_Choice*)o)->clear(); | ||
855 | ((Fl_Choice*)o)->add("Erase",0,(void (*)(Fl_Widget*,void*))(&(trackaction_cb)),(void*)this); | ||
856 | ((Fl_Choice*)o)->add("SMPTE",0,(void (*)(Fl_Widget*,void*))(&(trackaction_cb)),(void*)this); | ||
857 | ((Fl_Choice*)o)->add("Mono",0,(void (*)(Fl_Widget*,void*))(&(trackaction_cb)),(void*)this); | ||
858 | // count number of tracks in file given by filename | ||
859 | // when >1, for each track add a line. | ||
860 | int numtracks=countfiletracks(filename[tracknum-1]->value()); | ||
861 | if (numtracks>1) { | ||
862 | for (int i=1; i<=numtracks; i++) { | ||
863 | string strtrack="Tr."; | ||
864 | string* strnum=Convert::int2str(i); | ||
865 | strtrack+=*strnum; | ||
866 | ((Fl_Choice*)o)->add(strtrack.c_str(),0,(void (*)(Fl_Widget*,void*))(&(trackaction_cb)),(void*)this); | ||
867 | delete strnum; | ||
868 | } | ||
869 | } | ||
870 | ((Fl_Choice*)o)->value(2); // default 0=erase, 1=SMPTE, 2=mono | ||
871 | ((Fl_Choice*)o)->redraw(); | ||
872 | fl_check();} {} | ||
873 | } | ||
874 | Function {populate_trackactionbyfile(__uint32 slotnum,int trackchoice)} {open return_type void | ||
875 | } { | ||
876 | code {if (slotnum<0) return; | ||
877 | if (slotnum>23) return; | ||
878 | |||
879 | Fl_Choice* o=(Fl_Choice*)trackaction[slotnum]; | ||
880 | if (o==NULL) return; | ||
881 | for (unsigned int i=0;i<128;i++) { o->remove(0); } | ||
882 | o->add("Erase",0,(void (*)(Fl_Widget*,void*))(&(trackaction_cb)),(void*)this); | ||
883 | o->add("SMPTE",0,(void (*)(Fl_Widget*,void*))(&(trackaction_cb)),(void*)this); | ||
884 | o->add("Mono",0,(void (*)(Fl_Widget*,void*))(&(trackaction_cb)),(void*)this); | ||
885 | // count number of tracks in file given by filename | ||
886 | // when >1, for each track add a line. | ||
887 | int numtracks=countfiletracks(filename[slotnum]->value()); | ||
888 | if (numtracks>1) { | ||
889 | for (int i=1; i<=numtracks; i++) { | ||
890 | string strtrack="Tr."; | ||
891 | string* strnum=Convert::int2str(i); | ||
892 | strtrack+=*strnum; | ||
893 | o->add(strtrack.c_str(),0,(void (*)(Fl_Widget*,void*))(&(trackaction_cb)),(void*)this); | ||
894 | delete strnum; | ||
895 | } | ||
896 | } | ||
897 | o->value(trackchoice); | ||
898 | trackaction_callback(o,NULL); | ||
899 | o->redraw(); | ||
900 | |||
901 | fl_check();} {} | ||
902 | } | ||
903 | Function {moveselected(__sint32 direction)} {open return_type void | ||
904 | } { | ||
905 | code {__uint32 firsttrack=0; | ||
906 | __uint32 lasttrack=0; | ||
907 | if (currsong==NULL) | ||
908 | { | ||
909 | return; | ||
910 | } | ||
911 | if (direction==-1) | ||
912 | { | ||
913 | firsttrack=1; | ||
914 | lasttrack=currsong->logical_channels(); | ||
915 | if (trackselected[0]==1) | ||
916 | { | ||
917 | // move up, but first track is selected | ||
918 | // and already upper choice- cannot move up | ||
919 | return; | ||
920 | } | ||
921 | } | ||
922 | else | ||
923 | { | ||
924 | if (direction==1) | ||
925 | { | ||
926 | lasttrack=1; | ||
927 | firsttrack=currsong->logical_channels(); | ||
928 | |||
929 | if (trackselected[currsong->logical_channels()-1]==1) | ||
930 | { | ||
931 | return; | ||
932 | } | ||
933 | } | ||
934 | } | ||
935 | // we need to move stuff. | ||
936 | if (firsttrack==0) return; // direction==0, don't move. | ||
937 | |||
938 | __uint32 tracknum=firsttrack; | ||
939 | while (tracknum!=lasttrack) | ||
940 | { | ||
941 | if (trackselected[tracknum-1]!=trackselected[tracknum-1-direction]) | ||
942 | { | ||
943 | int dummy=trackselected[tracknum-1]; | ||
944 | string* trackval=new string(filename[tracknum-1]->value()); | ||
945 | |||
946 | trackselected[tracknum-1]=trackselected[tracknum-1-direction]; | ||
947 | trackselected[tracknum-1-direction]=dummy; | ||
948 | |||
949 | int a=((Fl_Choice*)(trackaction[tracknum-1]))->value(); | ||
950 | int b=((Fl_Choice*)(trackaction[tracknum-1-direction]))->value(); | ||
951 | |||
952 | filename[tracknum-1]->value(filename[tracknum-1-direction]->value()); | ||
953 | filename[tracknum-1-direction]->value(trackval->c_str()); | ||
954 | |||
955 | populate_trackactionbyfile(tracknum-1,b); | ||
956 | populate_trackactionbyfile(tracknum-1-direction,a); | ||
957 | |||
958 | delete trackval; | ||
959 | } | ||
960 | tracknum-=direction; | ||
961 | } | ||
962 | |||
963 | redrawtracks();} {} | ||
964 | } | ||
965 | Function {trackaction_cb(Fl_Widget* w, void* data)} {open return_type {static void} | ||
966 | } { | ||
967 | code {\#if (HD24DEBUG==1) | ||
968 | cout << "trackaction_cb" << endl; | ||
969 | \#endif | ||
970 | HD24UserInterface *o=(HD24UserInterface *)data; | ||
971 | o->trackaction_callback(w,data);} {} | ||
972 | } | ||
973 | Function {redrawtracks()} {open return_type void | ||
974 | } { | ||
975 | code {bool track_active; | ||
976 | if (currsong==NULL) { | ||
977 | return; | ||
978 | } | ||
979 | |||
980 | for (unsigned int tracknum=1;tracknum<=MAXCHANNELS;tracknum++) | ||
981 | { | ||
982 | if (currsong->logical_channels()>=tracknum) { | ||
983 | track_active=true; | ||
984 | filename[tracknum-1]->activate(); | ||
985 | } else { | ||
986 | track_active=false; | ||
987 | ((Fl_Output*)filename[tracknum-1])->color(7); | ||
988 | filename[tracknum-1]->deactivate(); | ||
989 | } | ||
990 | |||
991 | if (track_active) { | ||
992 | if (trackselected[tracknum-1]==1) { | ||
993 | ((Fl_Output*)filename[tracknum-1])->color(3); | ||
994 | } else { | ||
995 | ((Fl_Output*)filename[tracknum-1])->color(7); | ||
996 | } | ||
997 | } | ||
998 | |||
999 | ((Fl_Output*)filename[tracknum-1])->redraw(); | ||
1000 | }} {} | ||
1001 | } | ||
1002 | decl {/* ===UI stuff ===================================================== */} {} | ||
1003 | Function {populate_formats()} {open return_type void | ||
1004 | } { | ||
1005 | code {\#if (HD24DEBUG==1) | ||
1006 | cout << "populate_formats" << endl; | ||
1007 | \#endif | ||
1008 | |||
1009 | for (int i=0;i<transeng->supportedformatcount();i++) | ||
1010 | { | ||
1011 | fileformat->add(transeng->getformatdesc(i),0,NULL,(void*)this); | ||
1012 | } | ||
1013 | fileformat->value(0);} {} | ||
1014 | } | ||
1015 | Function {selectfilename(int tracknum)} {return_type void | ||
1016 | } { | ||
1017 | code {this->trackselected[tracknum-1]=1-this->trackselected[tracknum-1]; | ||
1018 | if (this->trackselected[tracknum-1]==1) { | ||
1019 | this->filename[tracknum-1]->color(3); | ||
1020 | } else { | ||
1021 | this->filename[tracknum-1]->color(7); | ||
1022 | } | ||
1023 | this->filename[tracknum-1]->redraw();} {} | ||
1024 | } | ||
1025 | Function {select_project(int projectid)} {open return_type void | ||
1026 | } { | ||
1027 | code {if (currproj!=NULL) { | ||
1028 | if (currsong!=NULL) | ||
1029 | { | ||
1030 | hd24song* tmpsong=currsong; | ||
1031 | currsong=NULL; | ||
1032 | delete tmpsong; | ||
1033 | } | ||
1034 | hd24project* tmpproj=currproj; | ||
1035 | currproj=NULL; | ||
1036 | delete tmpproj; | ||
1037 | } | ||
1038 | currproj=currenthd24->getproject(projectid); | ||
1039 | \#if (HD24DEBUG==1) | ||
1040 | cout << "select_project \#" << projectid << endl; | ||
1041 | \#endif | ||
1042 | currenthd24->lastprojectid(projectid); | ||
1043 | projectname->value(projectid-1); /* project id is 1-based */ | ||
1044 | int currsongcount=0; | ||
1045 | if (currproj==NULL) | ||
1046 | { | ||
1047 | delete_project->deactivate(); | ||
1048 | } | ||
1049 | else | ||
1050 | { | ||
1051 | delete_project->activate(); | ||
1052 | currsongcount=currproj->songcount(); | ||
1053 | } | ||
1054 | |||
1055 | if (currsongcount==0) | ||
1056 | { | ||
1057 | number_of_songs->value("0"); | ||
1058 | populate_songlist(0); // shows -- EMPTY PROJECT -- | ||
1059 | select_song(0); | ||
1060 | return; | ||
1061 | } | ||
1062 | |||
1063 | // currproj is defined at this point. | ||
1064 | |||
1065 | string* nums=Convert::int2str(currproj->songcount()); | ||
1066 | number_of_songs->value(nums->c_str()); | ||
1067 | \#if (HD24DEBUG==1) | ||
1068 | cout << "number of songs=" << currproj->songcount() << endl; | ||
1069 | \#endif | ||
1070 | delete(nums); | ||
1071 | |||
1072 | int lastsongid=currproj->lastsongid(); | ||
1073 | \#if (HD24DEBUG==1) | ||
1074 | cout << "lastsongid=" << lastsongid << endl; | ||
1075 | \#endif | ||
1076 | populate_songlist(lastsongid);} {} | ||
1077 | } | ||
1078 | Function {select_song(int songid)} {open return_type void | ||
1079 | } { | ||
1080 | code {unsigned int i; | ||
1081 | button_setlocatepoint->deactivate(); | ||
1082 | \#if (HD24DEBUG==1) | ||
1083 | cout << "select_song \#" << songid << endl; | ||
1084 | \#endif | ||
1085 | |||
1086 | |||
1087 | |||
1088 | if (songid==0) { | ||
1089 | |||
1090 | // This represents the choice "all songs" | ||
1091 | if (currsong!=NULL) { | ||
1092 | hd24song* tmpsong=currsong; | ||
1093 | currsong=NULL; | ||
1094 | delete tmpsong; | ||
1095 | } | ||
1096 | transfersource->value("(All songs in the current project)"); | ||
1097 | if (number_of_tracks==NULL) | ||
1098 | { | ||
1099 | return; // ui not yet initialized? | ||
1100 | } | ||
1101 | tab_tohd24->deactivate(); | ||
1102 | rename_song->deactivate(); | ||
1103 | delete_song->deactivate(); | ||
1104 | number_of_tracks->value(""); | ||
1105 | number_of_tracks->deactivate(); | ||
1106 | sample_rate->value(""); | ||
1107 | sample_rate->deactivate(); | ||
1108 | bitdepth->value(""); | ||
1109 | bitdepth->deactivate(); | ||
1110 | duration->value(""); | ||
1111 | duration->deactivate(); | ||
1112 | //refresh (songname); | ||
1113 | for (i=0; i<MAXCHANNELS;i++) { | ||
1114 | track[i]->deactivate(); | ||
1115 | track[i]->value(1); | ||
1116 | track[i]->show(); | ||
1117 | } | ||
1118 | button_setlocatepoint->deactivate(); | ||
1119 | button_golocatepoint->deactivate(); | ||
1120 | button_invert_tracks->deactivate(); | ||
1121 | choice_startloc=0; // use default | ||
1122 | // disable locatepoint dropdown: | ||
1123 | choice_endloc=populate_locatepoints(currsong,locatepoints); | ||
1124 | choice_endloc=0; | ||
1125 | update_fromto(); | ||
1126 | fromto->deactivate(); | ||
1127 | refresh (tab_tohd24); | ||
1128 | return; | ||
1129 | |||
1130 | } else { | ||
1131 | \#if (HD24DEBUG==1) | ||
1132 | cout << "activate buttons" << endl; | ||
1133 | \#endif | ||
1134 | delete_song->activate(); | ||
1135 | rename_song->activate(); | ||
1136 | tab_tohd24->activate(); | ||
1137 | button_golocatepoint->activate(); | ||
1138 | button_setlocatepoint->activate(); | ||
1139 | button_invert_tracks->activate(); | ||
1140 | rename_song->activate(); | ||
1141 | sample_rate->activate(); | ||
1142 | bitdepth->activate(); | ||
1143 | duration->activate(); | ||
1144 | refresh (rename_song); | ||
1145 | refresh (number_of_tracks); | ||
1146 | refresh (sample_rate); | ||
1147 | refresh (bitdepth); | ||
1148 | refresh (duration); | ||
1149 | refresh (tab_tohd24); | ||
1150 | \#if (HD24DEBUG==1) | ||
1151 | cout << "deselect old song" << endl; | ||
1152 | \#endif | ||
1153 | if (currsong!=NULL) { | ||
1154 | recorder->control->song(NULL); /* tell recorder that the song is gone */ | ||
1155 | delete currsong; | ||
1156 | currsong=NULL; | ||
1157 | } | ||
1158 | \#if (HD24DEBUG==1) | ||
1159 | cout << "currprojgetsong" << endl; | ||
1160 | \#endif | ||
1161 | currsong=currproj->getsong(songid); | ||
1162 | currproj->lastsongid(songid); | ||
1163 | if (currsong->has_unexpected_end()) { | ||
1164 | if (currsong->is_fixable_unexpected_end()) { | ||
1165 | song_messages->value("Unexpected end of song.\\nTrying to find the rest of the audio..."); | ||
1166 | // currenthd24->dumpclusterusage2(currenthd24->findorphanclusters()); | ||
1167 | unsigned char* orphans=currenthd24->findorphanclusters(); | ||
1168 | if (orphans != NULL) { | ||
1169 | currsong->appendorphanclusters(orphans,true /*allowsongresize*/); | ||
1170 | song_messages->value( | ||
1171 | "Unexpected end of song. I think I found back the rest of it.\\n" | ||
1172 | "However, you really should backup all audio and reformat this drive."); | ||
1173 | if (currenthd24->getmaintenancemode()==1) { | ||
1174 | if (confirm("Song was recovered. Do you wish to save the changes?\\nAnswer Yes only if you have verified that the audio is OK)")) { | ||
1175 | currsong->save(); | ||
1176 | } | ||
1177 | } | ||
1178 | } | ||
1179 | } | ||
1180 | else | ||
1181 | { | ||
1182 | ui_refresh("selectsong"); | ||
1183 | song_messages->value("Unexpected end of song.\\nHD24tools can not automatically fix this specific occurence."); | ||
1184 | } | ||
1185 | } else { | ||
1186 | song_messages->value("No messages."); | ||
1187 | } | ||
1188 | } | ||
1189 | |||
1190 | |||
1191 | \#if (HD24DEBUG==1) | ||
1192 | cout << "songname->value" << endl; | ||
1193 | \#endif | ||
1194 | |||
1195 | songname->value(songid); // entry 0=all songs, 1=song id 1 | ||
1196 | string* dummy=currsong->songname(); | ||
1197 | transfersource->value(dummy->c_str()); | ||
1198 | |||
1199 | /* This should al be done by the recorder.... | ||
1200 | string disp="S"; | ||
1201 | string* idstr=Convert::int2str(songid,2,"0"); | ||
1202 | disp+=*idstr; | ||
1203 | delete idstr; | ||
1204 | disp+=":\\""; | ||
1205 | string* dummy=currsong->songname(); | ||
1206 | transfersource->value(dummy->c_str()); | ||
1207 | string* dummy2=Convert::readstring((unsigned char*)dummy->c_str(),0,10); | ||
1208 | string* dummy3=Convert::readstring((unsigned char*)dummy->c_str(),0,11); | ||
1209 | |||
1210 | disp+=*dummy2; | ||
1211 | delete dummy; | ||
1212 | delete dummy2; | ||
1213 | if (dummy3->length()>10) | ||
1214 | { | ||
1215 | disp+="\\4"; // arrow right | ||
1216 | } else { | ||
1217 | disp+="\\""; | ||
1218 | } | ||
1219 | delete dummy3; | ||
1220 | string* disp2=Convert::padright(disp,16," "); | ||
1221 | |||
1222 | string* dur=currsong->display_duration(); | ||
1223 | |||
1224 | *disp2+=dur->substr(0,8); | ||
1225 | *disp2+=":"; | ||
1226 | *disp2+=dur->substr(9,2); | ||
1227 | *disp2+=" "; | ||
1228 | if (currsong->iswriteprotected()) | ||
1229 | { | ||
1230 | *disp2+="\\1"; | ||
1231 | } else { | ||
1232 | *disp2+="\\2"; | ||
1233 | } | ||
1234 | string* strtracksb=Convert::int2str(currsong->logical_channels(),2,"0"); | ||
1235 | *disp2+=*strtracksb; | ||
1236 | delete strtracksb; | ||
1237 | *disp2+="t"; | ||
1238 | |||
1239 | recorder->control->dispwrite(0,disp2->c_str()); | ||
1240 | delete disp2; | ||
1241 | ............. until this point */ | ||
1242 | recorder->control->song(currsong); /* load song into recorder */ | ||
1243 | |||
1244 | redrawtracks(); // enable/disable tracks for export to HD24 | ||
1245 | string* strtracks=Convert::int2str(currsong->logical_channels()); | ||
1246 | number_of_tracks->value(strtracks->c_str()); | ||
1247 | number_of_tracks->activate(); | ||
1248 | delete (strtracks); | ||
1249 | string* samrat=Convert::int2str(currsong->samplerate()); | ||
1250 | sample_rate->value(samrat->c_str()); | ||
1251 | sample_rate->activate(); | ||
1252 | delete samrat; | ||
1253 | if (mixer!=NULL) { | ||
1254 | mixer->control->samplerate(this->samplerate()); | ||
1255 | } | ||
1256 | |||
1257 | string* bitd=Convert::int2str(currsong->bitdepth()); | ||
1258 | bitdepth->value(bitd->c_str()); | ||
1259 | bitdepth->activate(); | ||
1260 | delete(bitd); | ||
1261 | |||
1262 | string* dur=currsong->display_duration(); | ||
1263 | duration->value(dur->c_str()); | ||
1264 | duration->activate(); | ||
1265 | delete(dur); | ||
1266 | |||
1267 | if (currsong->iswriteprotected()) { | ||
1268 | writeprotected->value(1); | ||
1269 | } else { | ||
1270 | writeprotected->value(0); | ||
1271 | } | ||
1272 | |||
1273 | refresh (songname); | ||
1274 | refresh (number_of_tracks); | ||
1275 | refresh (sample_rate); | ||
1276 | refresh (bitdepth); | ||
1277 | refresh (duration); | ||
1278 | refresh (writeprotected);// writeprotected->deactivate(); | ||
1279 | |||
1280 | for (i=0; i<currsong->logical_channels();i++) { | ||
1281 | track[i]->activate(); | ||
1282 | track[i]->show(); | ||
1283 | trackled[i]->show(); | ||
1284 | } | ||
1285 | for (i=currsong->logical_channels();i<MAXCHANNELS;i++) { | ||
1286 | track[i]->deactivate(); | ||
1287 | track[i]->hide(); | ||
1288 | trackled[i]->hide(); | ||
1289 | } | ||
1290 | |||
1291 | choice_startloc=0; // use default | ||
1292 | choice_endloc=populate_locatepoints(currsong,locatepoints); | ||
1293 | button_golocatepoint->activate(); | ||
1294 | if (choice_endloc>0) { | ||
1295 | fromto->activate(); | ||
1296 | } | ||
1297 | update_fromto();} {} | ||
1298 | } | ||
1299 | decl {int choice_startloc;} {} | ||
1300 | decl {int choice_endloc;} {} | ||
1301 | decl {bool mustdispsavemessage;} {public | ||
1302 | } | ||
1303 | decl {int loopmode;} {public | ||
1304 | } | ||
1305 | decl {int uiredrawcount; /* to limit refreshing UI */} {public | ||
1306 | } | ||
1307 | Function {update_fromto()} {return_type void | ||
1308 | } { | ||
1309 | code {if (currsong==NULL) | ||
1310 | { | ||
1311 | fromtime->value("START"); | ||
1312 | totime->value("END"); | ||
1313 | return; | ||
1314 | } | ||
1315 | string* dummy1=currsong->getlocatename(choice_startloc); | ||
1316 | string* dummy2=currsong->getlocatename(choice_endloc); | ||
1317 | string* strfrom=Convert::trim(dummy1); | ||
1318 | string* strto=Convert::trim(dummy2); | ||
1319 | |||
1320 | |||
1321 | fromtime->value(strfrom->c_str()); | ||
1322 | totime->value(strto->c_str()); | ||
1323 | delete(dummy1); | ||
1324 | delete(dummy2); | ||
1325 | delete (strfrom); | ||
1326 | delete (strto);} {} | ||
1327 | } | ||
1328 | Function {make_window(hd24fs* p_fsys) /* <------------------------------------------- */} {open | ||
1329 | } { | ||
1330 | Fl_Window {} { | ||
1331 | label HD24connect open | ||
1332 | xywh {485 44 605 530} type Double color 52 align 5 | ||
1333 | code0 {defaulthd24=p_fsys;} | ||
1334 | code1 {currenthd24=p_fsys; // current and default to allow multi drive support} | ||
1335 | code2 {init_vars();} visible | ||
1336 | } { | ||
1337 | Fl_Group {} {open | ||
1338 | xywh {-5 0 1720 540} | ||
1339 | } { | ||
1340 | Fl_Group menucanvas {open | ||
1341 | xywh {0 0 640 24} | ||
1342 | } { | ||
1343 | Fl_Menu_Bar {} {open | ||
1344 | xywh {0 0 640 24} color 52 | ||
1345 | } { | ||
1346 | Submenu menufile { | ||
1347 | label {&File} open | ||
1348 | xywh {0 0 100 20} labelsize 12 | ||
1349 | } { | ||
1350 | MenuItem {} { | ||
1351 | label {&Detect HD24 drives} | ||
1352 | callback {if (currenthd24!=NULL) { | ||
1353 | delete currenthd24; | ||
1354 | currenthd24=NULL; | ||
1355 | } | ||
1356 | |||
1357 | string* idir=hd24utils::getlastdir("driveimagedir"); | ||
1358 | currenthd24=new hd24fs(idir->c_str(),hd24fs::MODE_RDWR); | ||
1359 | delete idir; | ||
1360 | defaulthd24=currenthd24; | ||
1361 | if (!(currenthd24->isOpen())) | ||
1362 | { | ||
1363 | fl_message("Sorry, during detection no valid HD24 drive was found connected to the system.\\nPlease switch on and connect the drive, or try another File menu option."); | ||
1364 | } | ||
1365 | ui_restart();} | ||
1366 | xywh {0 0 34 21} labelsize 12 divider | ||
1367 | } | ||
1368 | MenuItem {} { | ||
1369 | label {&Open drive image...} | ||
1370 | callback {string* driveimgdir=hd24utils::getlastdir("driveimagedir"); | ||
1371 | |||
1372 | Fl_Native_File_Chooser chooser; | ||
1373 | chooser.directory(driveimgdir->c_str()); | ||
1374 | delete driveimgdir; | ||
1375 | chooser.title("Select HD24 drive image\\0"); | ||
1376 | chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); | ||
1377 | chooser.filter("Drive Images\\t*.{img,bin,h24,hd24}\\0"); | ||
1378 | //chooser.preview(0); | ||
1379 | switch (chooser.show()) { | ||
1380 | case -1: break; //error | ||
1381 | case 1: break; //cancel | ||
1382 | default: | ||
1383 | if (chooser.filename()) { | ||
1384 | string* cfilename=new string(chooser.filename()); | ||
1385 | |||
1386 | //cout << "filename = " << *strfile << endl; | ||
1387 | string* fpath=new string(""); | ||
1388 | *fpath+=cfilename->substr(0,strlen(cfilename->c_str())-strlen(fl_filename_name(cfilename->c_str()))); | ||
1389 | hd24utils::setlastdir("driveimagedir",fpath->c_str()); | ||
1390 | |||
1391 | hd24fs* sysob=new hd24fs(fpath->c_str(),hd24fs::MODE_RDWR,cfilename,false); | ||
1392 | delete cfilename; | ||
1393 | if (currenthd24!=NULL) | ||
1394 | { | ||
1395 | currenthd24->~hd24fs(); | ||
1396 | } | ||
1397 | if (defaulthd24!=NULL) | ||
1398 | { | ||
1399 | if (defaulthd24!=currenthd24) | ||
1400 | { | ||
1401 | defaulthd24->~hd24fs(); | ||
1402 | } | ||
1403 | } | ||
1404 | currenthd24=sysob; | ||
1405 | defaulthd24=sysob; | ||
1406 | |||
1407 | if (!(currenthd24->isOpen())) | ||
1408 | { | ||
1409 | bool choice=confirm( | ||
1410 | "File does not appear to be a valid HD24 device image.\\nDo you want to try using it anyway?\\nWarning: Choosing 'Yes' may result in\\ncrashes and other unpredictable behavior." | ||
1411 | ); | ||
1412 | |||
1413 | if (choice) { | ||
1414 | if (sysob!=NULL) { | ||
1415 | delete (sysob); | ||
1416 | } | ||
1417 | bool wantheader=confirm("Do you want to load a header file?"); | ||
1418 | |||
1419 | cfilename=new string(chooser.filename()); | ||
1420 | string* idir=hd24utils::getlastdir("driveimagedir"); | ||
1421 | sysob=new hd24fs(idir->c_str(),hd24fs::MODE_RDWR,cfilename,true); //force | ||
1422 | delete idir; | ||
1423 | delete cfilename; | ||
1424 | if (currenthd24!=NULL) | ||
1425 | { | ||
1426 | currenthd24->~hd24fs(); | ||
1427 | } | ||
1428 | if (defaulthd24!=NULL) | ||
1429 | { | ||
1430 | if (defaulthd24!=currenthd24) | ||
1431 | { | ||
1432 | defaulthd24->~hd24fs(); | ||
1433 | } | ||
1434 | |||
1435 | } | ||
1436 | |||
1437 | currenthd24=sysob; | ||
1438 | defaulthd24=sysob; | ||
1439 | if (currenthd24->isOpen()) { | ||
1440 | if (wantheader) { | ||
1441 | loadheaderfile(); | ||
1442 | } | ||
1443 | ui_restart(); | ||
1444 | return; | ||
1445 | } | ||
1446 | fl_message("Cannot open HD24 device image."); | ||
1447 | } | ||
1448 | |||
1449 | return; | ||
1450 | } | ||
1451 | ui_restart(); | ||
1452 | } | ||
1453 | break; | ||
1454 | }} | ||
1455 | xywh {0 0 34 21} labelsize 12 | ||
1456 | } | ||
1457 | MenuItem {} { | ||
1458 | label {&Save drive image...} | ||
1459 | callback {string* driveimgdir=new string(""); | ||
1460 | *driveimgdir+=*hd24utils::getlastdir("driveimagedir"); | ||
1461 | |||
1462 | Fl_Native_File_Chooser chooser; | ||
1463 | chooser.filter("Drive Images\\t*.{img,bin,h24,hd24}\\0"); | ||
1464 | chooser.title("Export full drive image file"); | ||
1465 | chooser.directory(driveimgdir->c_str()); | ||
1466 | chooser.options(Fl_Native_File_Chooser::NEW_FOLDER); | ||
1467 | chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); | ||
1468 | |||
1469 | switch (chooser.show()) { | ||
1470 | case -1: break; //error | ||
1471 | case 1: break; //cancel | ||
1472 | default: | ||
1473 | // save header to chooser.filename() | ||
1474 | |||
1475 | bool bFileexists=hd24utils::fileExists(chooser.filename()); | ||
1476 | if (bFileexists) { | ||
1477 | bool choice=confirm( | ||
1478 | "A file with this name already exists. Do you wish to overwrite it?" | ||
1479 | ); | ||
1480 | if (!(choice)) return; | ||
1481 | } | ||
1482 | string* strfile=new string(chooser.filename()); | ||
1483 | //cout << "filename = " << *strfile << endl; | ||
1484 | string* fpath=new string(""); | ||
1485 | *fpath+=strfile->substr(0,strlen(strfile->c_str())-strlen(fl_filename_name(strfile->c_str()))); | ||
1486 | hd24utils::setlastdir("driveimagedir",fpath->c_str()); | ||
1487 | this->transfer_cancel=0; | ||
1488 | this->mustdispsavemessage=true; | ||
1489 | Fl::add_timeout(.25,savemessage_callback,this); | ||
1490 | int result=hd24utils::savedriveimage(currenthd24,strfile,&this->savemessage[0],&this->transfer_cancel); | ||
1491 | delete strfile; | ||
1492 | if (result==0) { | ||
1493 | fl_message("Drive image created successfully."); | ||
1494 | setstatus("Done."); | ||
1495 | } else { | ||
1496 | fl_message("Could not write drive image to file. Access denied? Disk full?"); | ||
1497 | } | ||
1498 | this->mustdispsavemessage=false; | ||
1499 | break; | ||
1500 | } | ||
1501 | delete driveimgdir;} | ||
1502 | xywh {10 10 34 21} labelsize 12 | ||
1503 | } | ||
1504 | Submenu {} { | ||
1505 | label {&Catalog} open | ||
1506 | xywh {0 0 70 21} labelsize 12 | ||
1507 | } { | ||
1508 | MenuItem {} { | ||
1509 | label {&Export catalog...} | ||
1510 | callback {string* catdir=new string(""); | ||
1511 | *catdir+=*hd24utils::getlastdir("catalogdir"); | ||
1512 | |||
1513 | Fl_Native_File_Chooser chooser; | ||
1514 | chooser.filter("Text files\\t*.txt"); | ||
1515 | chooser.title("Export disk catalog to file"); | ||
1516 | chooser.directory(catdir->c_str()); | ||
1517 | chooser.options(Fl_Native_File_Chooser::NEW_FOLDER); | ||
1518 | chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); | ||
1519 | |||
1520 | switch (chooser.show()) { | ||
1521 | case -1: break; //error | ||
1522 | case 1: break; //cancel | ||
1523 | default: | ||
1524 | // save header to chooser.filename() | ||
1525 | |||
1526 | bool bFileexists=hd24utils::fileExists(chooser.filename()); | ||
1527 | if (bFileexists) { | ||
1528 | bool choice=confirm( | ||
1529 | "A file with this name already exists. Do you wish to overwrite it?" | ||
1530 | ); | ||
1531 | if (!(choice)) return; | ||
1532 | } | ||
1533 | string* strfile=new string(chooser.filename()); | ||
1534 | //cout << "filename = " << *strfile << endl; | ||
1535 | string* fpath=new string(""); | ||
1536 | *fpath+=strfile->substr(0,strlen(strfile->c_str())-strlen(fl_filename_name(strfile->c_str()))); | ||
1537 | hd24utils::setlastdir("catalogdir",fpath->c_str()); | ||
1538 | string* anyerrors=hd24utils::savecatalog(currenthd24,strfile); | ||
1539 | delete strfile; | ||
1540 | if (anyerrors==NULL) { | ||
1541 | fl_message("Catalog file created successfully."); | ||
1542 | } else { | ||
1543 | delete anyerrors; | ||
1544 | fl_message("Could not write catalog file. Access denied? Disk full?"); | ||
1545 | } | ||
1546 | break; | ||
1547 | } | ||
1548 | delete catdir;} | ||
1549 | tooltip {Save the disk directory to a printable text file} xywh {40 40 34 21} labelsize 12 | ||
1550 | } | ||
1551 | MenuItem {} { | ||
1552 | label {&Print catalog} | ||
1553 | callback {string* result=hd24utils::printcatalog(currenthd24); | ||
1554 | if (result!=NULL) | ||
1555 | { | ||
1556 | if (strlen(result->c_str())!=0) | ||
1557 | { | ||
1558 | fl_message("%s",result->c_str()); | ||
1559 | } | ||
1560 | } | ||
1561 | delete result;} | ||
1562 | tooltip {Save the disk directory to a printable text file} xywh {30 30 34 21} labelsize 12 divider | ||
1563 | } | ||
1564 | } | ||
1565 | Submenu {} { | ||
1566 | label {&Mixer} open | ||
1567 | xywh {10 10 70 21} labelsize 12 | ||
1568 | } { | ||
1569 | MenuItem {} { | ||
1570 | label {&Save mixer settings to file,,,} | ||
1571 | callback {mixer->savetofile();} | ||
1572 | tooltip {Save the current mixer settings to a file} xywh {50 50 34 21} labelsize 12 | ||
1573 | } | ||
1574 | MenuItem {} { | ||
1575 | label {&Load mixer settings from file...} | ||
1576 | callback {mixer->loadfromfile();} | ||
1577 | tooltip {Recall mixer settings from a previously saved mix} xywh {60 60 34 21} labelsize 12 divider | ||
1578 | } | ||
1579 | MenuItem {} { | ||
1580 | label {&Save mixer settings to HD24 drive,,,} | ||
1581 | tooltip {Save the current mix onto the HD24 drive} xywh {60 60 34 21} labelsize 12 deactivate | ||
1582 | } | ||
1583 | MenuItem {} { | ||
1584 | label {&Load mixer settings from HD24 drive...} | ||
1585 | tooltip {Recall mixer settings from a mix previously saved to the current HD24 drive} xywh {70 70 34 21} labelsize 12 deactivate | ||
1586 | } | ||
1587 | } | ||
1588 | Submenu {} { | ||
1589 | label {&Recovery} open | ||
1590 | xywh {0 0 70 21} labelsize 12 divider | ||
1591 | } { | ||
1592 | MenuItem {} { | ||
1593 | label {&Select device...} | ||
1594 | callback {dialog_choosedevice* chooser=new dialog_choosedevice(); | ||
1595 | Fl_Double_Window* w=chooser->make_window(currenthd24); | ||
1596 | w->end(); | ||
1597 | w->show(); | ||
1598 | while (w->visible()) { | ||
1599 | Fl::wait(); | ||
1600 | } | ||
1601 | string* cfilename; | ||
1602 | hd24fs* sysob; | ||
1603 | string* idir=NULL; | ||
1604 | switch (chooser->buttonclicked) { | ||
1605 | case 1: | ||
1606 | // OK | ||
1607 | cfilename=new string(chooser->devicename->c_str()); | ||
1608 | idir=hd24utils::getlastdir("driveimagedir"); | ||
1609 | sysob=new hd24fs(idir->c_str(),hd24fs::MODE_RDWR,cfilename,false); | ||
1610 | delete idir; idir=NULL; | ||
1611 | |||
1612 | currenthd24=sysob; | ||
1613 | defaulthd24=sysob; | ||
1614 | |||
1615 | if (!(currenthd24->isOpen())) | ||
1616 | { | ||
1617 | bool choice=confirm( | ||
1618 | "Device does not appear to be a valid HD24 device.\\nDo you want to try using it anyway?\\nWarning: Choosing 'Yes' may result in\\ncrashes and other unpredictable behavior." | ||
1619 | ); | ||
1620 | |||
1621 | if (choice) { | ||
1622 | if (sysob!=NULL) { | ||
1623 | delete (sysob); | ||
1624 | } | ||
1625 | string* idir=hd24utils::getlastdir("driveimagedir"); | ||
1626 | sysob=new hd24fs(idir->c_str(),hd24fs::MODE_RDWR,cfilename,true); //force | ||
1627 | delete idir; | ||
1628 | currenthd24=sysob; | ||
1629 | defaulthd24=sysob; | ||
1630 | int tryheader=0; | ||
1631 | if (currenthd24->isOpen()) { | ||
1632 | tryheader=1; | ||
1633 | bool wantheader=confirm("Do you want to load a header file?"); | ||
1634 | if (wantheader) { | ||
1635 | loadheaderfile(); | ||
1636 | } | ||
1637 | |||
1638 | ui_restart(); | ||
1639 | delete cfilename; | ||
1640 | return; | ||
1641 | } | ||
1642 | if (tryheader==1) { | ||
1643 | fl_message("Cannot open HD24 device."); | ||
1644 | } else { | ||
1645 | fl_message("Cannot open HD24 device. Access denied?"); | ||
1646 | } | ||
1647 | } | ||
1648 | delete cfilename; | ||
1649 | break; | ||
1650 | } | ||
1651 | ui_restart(); | ||
1652 | delete cfilename; | ||
1653 | break; | ||
1654 | case 2: | ||
1655 | // cancel | ||
1656 | break; | ||
1657 | default: | ||
1658 | // unknown | ||
1659 | break; | ||
1660 | } | ||
1661 | delete chooser;} | ||
1662 | xywh {5 5 34 21} labelsize 12 | ||
1663 | } | ||
1664 | MenuItem {} { | ||
1665 | label {Load &header file...} | ||
1666 | callback {loadheaderfile();} | ||
1667 | xywh {5 5 34 21} labelsize 12 | ||
1668 | } | ||
1669 | MenuItem {} { | ||
1670 | label {&Create header file...} | ||
1671 | callback {string* headerdir=new string(""); | ||
1672 | *headerdir+=*hd24utils::getlastdir("headerdir"); | ||
1673 | |||
1674 | Fl_Native_File_Chooser chooser; | ||
1675 | chooser.filter("Header files (*.h24)\\t"); | ||
1676 | chooser.title("Create header file"); | ||
1677 | chooser.options(Fl_Native_File_Chooser::NEW_FOLDER); | ||
1678 | chooser.directory(headerdir->c_str()); | ||
1679 | chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); | ||
1680 | |||
1681 | switch (chooser.show()) { | ||
1682 | case -1: break; //error | ||
1683 | case 1: break; //cancel | ||
1684 | default: | ||
1685 | // save header to chooser.filename() | ||
1686 | bool bFileexists=hd24utils::fileExists(chooser.filename()); | ||
1687 | if (bFileexists) { | ||
1688 | bool choice=confirm( | ||
1689 | "A file with this name already exists. Do you wish to overwrite it?" | ||
1690 | ); | ||
1691 | if (!(choice)) return; | ||
1692 | } | ||
1693 | string* strfile=new string(chooser.filename()); | ||
1694 | string* fpath=new string(""); | ||
1695 | *fpath+=strfile->substr(0,strlen(strfile->c_str())-strlen(fl_filename_name(strfile->c_str()))); | ||
1696 | hd24utils::setlastdir("headerdir",fpath->c_str()); | ||
1697 | |||
1698 | int result=hd24utils::saveheader(currenthd24,strfile); | ||
1699 | delete strfile; | ||
1700 | if (result==0) { | ||
1701 | fl_message("Header file created successfully."); | ||
1702 | } else { | ||
1703 | fl_message("Could not write header file. Access denied? Disk full?"); | ||
1704 | } | ||
1705 | break; | ||
1706 | }} | ||
1707 | xywh {15 15 34 21} labelsize 12 | ||
1708 | } | ||
1709 | MenuItem {} { | ||
1710 | label {Recover song from &power failure} | ||
1711 | callback {if (currsong==NULL) { | ||
1712 | fl_message("First select the song to recover."); | ||
1713 | return; | ||
1714 | } | ||
1715 | |||
1716 | dialog_setlength* ui_setlength; | ||
1717 | ui_setlength=new dialog_setlength; | ||
1718 | int currlocchoice=locatepoints->value(); | ||
1719 | Fl_Window *win=ui_setlength->make_window(currsong,currlocchoice); | ||
1720 | win->end(); | ||
1721 | win->show(); | ||
1722 | |||
1723 | while (win->visible()) { Fl::wait(); } | ||
1724 | |||
1725 | if (ui_setlength->buttonclicked==1) { | ||
1726 | // TODO: | ||
1727 | // - create header file | ||
1728 | // getuserdatapath. | ||
1729 | // | ||
1730 | |||
1731 | char userdatapath[FL_PATH_MAX]; | ||
1732 | Fl_Preferences* prefs=new Fl_Preferences(Fl_Preferences::USER,"HD24","HD24connect"); | ||
1733 | prefs->getUserdataPath(userdatapath,FL_PATH_MAX); | ||
1734 | delete prefs; | ||
1735 | string* headerfilename=new string(userdatapath); | ||
1736 | |||
1737 | // add OS directory slash if forgotten | ||
1738 | \#ifdef WINDOWS | ||
1739 | \#define OSSLASH '\\\\' | ||
1740 | \#else | ||
1741 | \#define OSSLASH '/' | ||
1742 | \#endif | ||
1743 | const char* x=headerfilename->c_str(); | ||
1744 | int q=strlen(x); | ||
1745 | if (q>0) | ||
1746 | { | ||
1747 | if (x[q-1]!=OSSLASH) | ||
1748 | { | ||
1749 | *headerfilename+=OSSLASH; | ||
1750 | } | ||
1751 | } | ||
1752 | *headerfilename+="livefix.h24"; | ||
1753 | |||
1754 | int createtempheaderresult=hd24utils::savedrivesectors(currenthd24,headerfilename,0,0x10c76,NULL,NULL); | ||
1755 | |||
1756 | if (createtempheaderresult!=0) | ||
1757 | { | ||
1758 | delete headerfilename; | ||
1759 | fl_message("Couldn't create a temporary header file, cannot continue. Sorry."); | ||
1760 | return; | ||
1761 | } | ||
1762 | // header was created successfully. | ||
1763 | currenthd24->useheaderfile(*headerfilename); | ||
1764 | //cout << "Userdatapath="<<userdatapath << endl; | ||
1765 | |||
1766 | // - use header file | ||
1767 | // - this makes sure any writes go to header file | ||
1768 | |||
1769 | bool clearnew=false; | ||
1770 | currsong->songlength_in_samples(ui_setlength->locpoint,clearnew); | ||
1771 | currsong->save(); | ||
1772 | ui_refresh("liverec"); | ||
1773 | } | ||
1774 | delete ui_setlength;} | ||
1775 | xywh {10 10 36 21} labelsize 12 | ||
1776 | } | ||
1777 | } | ||
1778 | MenuItem {} { | ||
1779 | label {E&xit} | ||
1780 | callback {/* Find current window */ | ||
1781 | this->finish(); | ||
1782 | |||
1783 | Fl_Window * x=Fl::first_window(); | ||
1784 | x->~Fl_Window(); | ||
1785 | delete x; | ||
1786 | x=NULL;} | ||
1787 | xywh {0 0 100 20} labelsize 12 | ||
1788 | } | ||
1789 | } | ||
1790 | Submenu menutools { | ||
1791 | label {&Tools} open | ||
1792 | xywh {10 10 100 20} labelsize 12 | ||
1793 | } { | ||
1794 | Submenu {} { | ||
1795 | label {Alter &order of songs in project} open | ||
1796 | xywh {20 20 100 20} labelsize 12 divider | ||
1797 | } { | ||
1798 | MenuItem {} { | ||
1799 | label {Sort &Alphabetically} | ||
1800 | callback {if (this->currproj==NULL) | ||
1801 | { | ||
1802 | fl_message("Cannot sort project- no project selected."); | ||
1803 | return; | ||
1804 | } | ||
1805 | this->currproj->sort(); | ||
1806 | this->currproj->save(); | ||
1807 | this->ui_refresh("sort");} | ||
1808 | xywh {30 30 34 21} labelsize 12 | ||
1809 | } | ||
1810 | } | ||
1811 | MenuItem {} { | ||
1812 | label {&Options...} | ||
1813 | callback {dialog_options* ui_options; | ||
1814 | ui_options=new dialog_options; | ||
1815 | Fl_Window *win=ui_options->make_window(); | ||
1816 | win->end(); | ||
1817 | win->show(); | ||
1818 | |||
1819 | while (win->visible()) { Fl::wait(); } | ||
1820 | |||
1821 | delete ui_options;} | ||
1822 | xywh {30 30 34 21} labelsize 12 | ||
1823 | } | ||
1824 | } | ||
1825 | Submenu menuhelp { | ||
1826 | label {&Help} open | ||
1827 | xywh {0 0 100 20} labelsize 12 | ||
1828 | } { | ||
1829 | MenuItem {} { | ||
1830 | label {&About} | ||
1831 | callback {UserInterface_HelpAbout* ui_help_about; | ||
1832 | ui_help_about=new UserInterface_HelpAbout; | ||
1833 | |||
1834 | Fl_Window *helpaboutdialog=ui_help_about->make_window(); | ||
1835 | helpaboutdialog->end(); | ||
1836 | helpaboutdialog->show(); | ||
1837 | |||
1838 | while (helpaboutdialog->visible()) { Fl::wait(); }} | ||
1839 | xywh {0 0 100 20} labelsize 12 | ||
1840 | } | ||
1841 | MenuItem {} { | ||
1842 | label {System &Info} | ||
1843 | callback {string info="HD24connect system info\\n"; | ||
1844 | info+="JACK: "; | ||
1845 | if (libjack->libloaded) { | ||
1846 | info+="Loaded"; | ||
1847 | } else { | ||
1848 | info+="Not present"; | ||
1849 | } | ||
1850 | info+="\\n"; | ||
1851 | |||
1852 | info+="LIBSNDFILE: "; | ||
1853 | if (soundfile->libloaded) { | ||
1854 | info+="Loaded"; | ||
1855 | } else { | ||
1856 | info+="Not present"; | ||
1857 | } | ||
1858 | info+="\\n"; | ||
1859 | |||
1860 | |||
1861 | info+="PORTAUDIO: "; | ||
1862 | if (portaudio->libloaded) { | ||
1863 | info+="Loaded"; | ||
1864 | } else { | ||
1865 | info+="Not present"; | ||
1866 | } | ||
1867 | info+="\\n"; | ||
1868 | |||
1869 | |||
1870 | fl_message("%s",info.c_str());} | ||
1871 | xywh {20 20 100 20} labelsize 12 | ||
1872 | } | ||
1873 | MenuItem {} { | ||
1874 | label {Report a &Bug} | ||
1875 | callback {string bug="No warranty of any kind is given on this program.\\n\\n"; | ||
1876 | bug+="However, if you find any defects or faults in it, they\\n"; | ||
1877 | bug+="will most likely be fixed with high priority in the next\\n"; | ||
1878 | bug+="release, as long as the author is aware of them.\\n\\n"; | ||
1879 | bug+="Should you find any defects, please email the author at\\n"; | ||
1880 | bug+="the following e-mail address:\\n\\n"; | ||
1881 | bug+="mrjb@@dnd.utwente.nl.\\n\\n"; | ||
1882 | bug+="Make sure to include 'hd24' in the subject line."; | ||
1883 | fl_message("%s",bug.c_str());} | ||
1884 | xywh {0 0 100 20} labelsize 12 | ||
1885 | } | ||
1886 | MenuItem {} { | ||
1887 | label {Request a &Feature} | ||
1888 | callback {string bug="If you would like a specific feature to be added, please\\n"; | ||
1889 | bug+="please email your request to the author at the following \\n"; | ||
1890 | bug+="e-mail address:\\n\\n"; | ||
1891 | bug+="mrjb@@dnd.utwente.nl.\\n\\n"; | ||
1892 | bug+="Make sure to include 'hd24 feature request' in the subject line.\\n"; | ||
1893 | bug+="You can increase the priority of the request by donating."; | ||
1894 | fl_message("%s",bug.c_str());} | ||
1895 | xywh {10 10 100 20} labelsize 12 | ||
1896 | } | ||
1897 | MenuItem {} { | ||
1898 | label {&Credits} | ||
1899 | callback {string thanks="Extra Special thanks go out to: \\n\\n"; | ||
1900 | thanks+="Randy Bryant for trusting me to use his Mac\\n"; | ||
1901 | thanks+="Mike Crute for hosting and builder support\\n"; | ||
1902 | thanks+="Cabbage for building various Mac package installers\\n"; | ||
1903 | thanks+="Edward van Westerlaak for Windows and Mac/OSX beta testing, hardware support and suggestions\\n"; | ||
1904 | thanks+="Erik de Castro Lopo and other contributors for libsndfile\\n"; | ||
1905 | thanks+="Ross Bencina, Phil Burk, Bjorn Roche and other contributors for the portaudio library\\n"; | ||
1906 | thanks+="Bill Spitzak and others for the Fast Light Toolkit\\n"; | ||
1907 | thanks+="Sveinn Kjartansson for providing the means for high sample rate support\\n\\n"; | ||
1908 | thanks+="Special thanks go out to the Yahoo Groups HD24 community\\n"; | ||
1909 | thanks+="for additional beta testing, suggestions and general encouragement.\\n\\n"; | ||
1910 | fl_message("%s",thanks.c_str());} | ||
1911 | xywh {10 10 100 20} labelsize 12 | ||
1912 | } | ||
1913 | } | ||
1914 | } | ||
1915 | } | ||
1916 | Fl_Group uicanvas {open | ||
1917 | xywh {-5 0 1720 540} resizable | ||
1918 | } { | ||
1919 | Fl_Group transfercanvas { | ||
1920 | label Transfer | ||
1921 | xywh {10 360 590 150} box UP_BOX color 52 labelfont 1 labelsize 12 align 5 | ||
1922 | } {} | ||
1923 | Fl_Group statusbar { | ||
1924 | xywh {-5 510 725 20} box DOWN_BOX color 23 | ||
1925 | } { | ||
1926 | Fl_Output backgroundbox { | ||
1927 | xywh {0 510 605 20} color 52 labelsize 12 textsize 12 | ||
1928 | } | ||
1929 | Fl_Button stop_transfer { | ||
1930 | label Cancel | ||
1931 | callback {transfer_cancel=1; | ||
1932 | stop_transfer->hide();} | ||
1933 | xywh {525 510 80 20} labelsize 12 align 16 | ||
1934 | code0 {o->hide();} | ||
1935 | } | ||
1936 | Fl_Output statusmsg { | ||
1937 | xywh {0 510 525 20} color 52 labelsize 12 textsize 12 | ||
1938 | } | ||
1939 | } | ||
1940 | Fl_Tabs Tabs { | ||
1941 | callback {this->readmixer(); | ||
1942 | this->mixer->damage(); | ||
1943 | if (o->value()==tabRecorder) | ||
1944 | { | ||
1945 | if (recorder->button_play->value()==0) | ||
1946 | { | ||
1947 | showprogtitle(); | ||
1948 | } | ||
1949 | }} open | ||
1950 | xywh {-5 25 1600 485} | ||
1951 | code0 {o->value(tabDrive);} | ||
1952 | } { | ||
1953 | Fl_Group tabDrive { | ||
1954 | label Drive open | ||
1955 | xywh {0 45 605 465} box UP_BOX color 52 labelfont 1 labelsize 12 align 5 hide | ||
1956 | } { | ||
1957 | Fl_Choice drivename { | ||
1958 | label {Drive name:} | ||
1959 | xywh {155 80 440 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
1960 | } {} | ||
1961 | Fl_Output fsversion { | ||
1962 | label {FS version:} | ||
1963 | xywh {305 105 50 20} labelsize 12 textsize 12 | ||
1964 | code0 {o->clear_visible_focus();} | ||
1965 | } | ||
1966 | Fl_Output number_of_projects { | ||
1967 | label {Number of projects:} | ||
1968 | xywh {155 105 70 20} labelsize 12 textsize 12 | ||
1969 | code0 {o->clear_visible_focus();} | ||
1970 | } | ||
1971 | Fl_Button rename_drive { | ||
1972 | label {Rename...} | ||
1973 | callback {if (currenthd24==NULL) return; | ||
1974 | dialog_rename* ui_rename; | ||
1975 | ui_rename=new dialog_rename(); | ||
1976 | string* currname=currenthd24->volumename(); | ||
1977 | string* strname=new string("Rename project"); | ||
1978 | Fl_Window* win=ui_rename->make_window(currname,strname); | ||
1979 | if (strname!=NULL) | ||
1980 | { | ||
1981 | delete strname; | ||
1982 | } | ||
1983 | if (currname!=NULL) | ||
1984 | { | ||
1985 | delete currname; | ||
1986 | } | ||
1987 | win->end(); | ||
1988 | win->show(); | ||
1989 | |||
1990 | while (win->visible()) { Fl::wait(); } | ||
1991 | if (ui_rename->buttonclicked==1) | ||
1992 | { | ||
1993 | // OK clicked | ||
1994 | if (confirm("Do you wish to write the changes to disk?")) { | ||
1995 | currenthd24->setvolumename(*(ui_rename->itemname)); | ||
1996 | currenthd24->savedriveinfo(); | ||
1997 | populate_drivelist(1+drivename->value()); | ||
1998 | drivename->redraw(); | ||
1999 | } | ||
2000 | } | ||
2001 | delete ui_rename; | ||
2002 | ui_refresh("ren proj");} | ||
2003 | xywh {510 105 85 20} labelsize 12 align 16 | ||
2004 | } | ||
2005 | Fl_Output freespace { | ||
2006 | label {Free space preview:} | ||
2007 | xywh {155 130 140 20} labelsize 12 textsize 12 | ||
2008 | code0 {o->clear_visible_focus();} | ||
2009 | } | ||
2010 | Fl_Choice atrate { | ||
2011 | label {at } | ||
2012 | callback {calcspace();} open | ||
2013 | xywh {320 130 85 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
2014 | code0 {o->value(0);} | ||
2015 | } { | ||
2016 | MenuItem {} { | ||
2017 | label 44100 | ||
2018 | xywh {5 5 100 20} value 1 labelsize 12 | ||
2019 | } | ||
2020 | MenuItem {} { | ||
2021 | label 48000 | ||
2022 | xywh {15 15 100 20} value 1 labelsize 12 | ||
2023 | } | ||
2024 | MenuItem {} { | ||
2025 | label 88200 | ||
2026 | xywh {25 25 100 20} value 1 labelsize 12 | ||
2027 | } | ||
2028 | MenuItem {} { | ||
2029 | label 96000 | ||
2030 | xywh {35 35 100 20} value 1 labelsize 12 | ||
2031 | } | ||
2032 | } | ||
2033 | Fl_Choice attracks { | ||
2034 | label {Hz, } | ||
2035 | callback {calcspace();} open | ||
2036 | xywh {435 130 75 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
2037 | code0 {o->value(5);} | ||
2038 | } { | ||
2039 | MenuItem {} { | ||
2040 | label 2 | ||
2041 | xywh {15 15 100 20} value 1 labelsize 12 | ||
2042 | } | ||
2043 | MenuItem {} { | ||
2044 | label 6 | ||
2045 | xywh {25 25 100 20} value 1 labelsize 12 | ||
2046 | } | ||
2047 | MenuItem {} { | ||
2048 | label 8 | ||
2049 | xywh {35 35 100 20} value 1 labelsize 12 | ||
2050 | } | ||
2051 | MenuItem {} { | ||
2052 | label 12 | ||
2053 | xywh {45 45 100 20} value 1 labelsize 12 | ||
2054 | } | ||
2055 | MenuItem {} { | ||
2056 | label 16 | ||
2057 | xywh {55 55 100 20} value 1 labelsize 12 | ||
2058 | } | ||
2059 | MenuItem {} { | ||
2060 | label 24 | ||
2061 | xywh {65 65 100 20} value 1 labelsize 12 | ||
2062 | } | ||
2063 | } | ||
2064 | Fl_Box {} { | ||
2065 | label tracks | ||
2066 | xywh {510 130 55 20} labelsize 12 align 20 | ||
2067 | } | ||
2068 | Fl_Group {} {open | ||
2069 | xywh {25 70 15 15} | ||
2070 | } {} | ||
2071 | Fl_Box {} { | ||
2072 | label {Drive information} | ||
2073 | xywh {0 58 5 17} labelfont 1 labelsize 12 align 8 | ||
2074 | } | ||
2075 | Fl_Text_Display catalog { | ||
2076 | label {Drive contents} | ||
2077 | xywh {5 190 595 310} box DOWN_BOX labelfont 1 labelsize 12 align 5 textfont 4 textsize 12 | ||
2078 | code0 {if (catalogbuffer==NULL) catalogbuffer=new Fl_Text_Buffer(); string* cat=new string("\\n"); catalogbuffer->append(cat->c_str()); delete cat;} | ||
2079 | code1 {o->buffer(catalogbuffer); o->scrollbar_align(FL_ALIGN_RIGHT);} | ||
2080 | } | ||
2081 | Fl_Button format_driveimage { | ||
2082 | label Format | ||
2083 | callback {bool wantformat=confirm("This will COMPLETELY ERASE\\nALL projects and songs on this drive.\\nAre you SURE you want to format the current drive?\\n"); | ||
2084 | if (!wantformat) return; | ||
2085 | // Okay, user is absolutely sure. | ||
2086 | currenthd24->write_enable(); | ||
2087 | currenthd24->quickformat(NULL); | ||
2088 | // there's no point in re-enabling write | ||
2089 | // protection again now, is there? | ||
2090 | ui_refresh("format"); | ||
2091 | setstatus("Format complete."); | ||
2092 | return;} | ||
2093 | xywh {455 105 55 20} labelsize 12 align 16 | ||
2094 | } | ||
2095 | Fl_Button create_driveimage { | ||
2096 | label {New Image...} | ||
2097 | callback {dialog_filesize* ui_filesize; | ||
2098 | ui_filesize=new dialog_filesize(); | ||
2099 | Fl_Window *win=ui_filesize->make_window(); | ||
2100 | win->end(); | ||
2101 | win->show(); | ||
2102 | |||
2103 | while (win->visible()) { Fl::wait(); } | ||
2104 | __uint32 lastsector=0; | ||
2105 | |||
2106 | if (ui_filesize->buttonclicked!=1) | ||
2107 | { | ||
2108 | delete ui_filesize; | ||
2109 | return; | ||
2110 | } | ||
2111 | |||
2112 | lastsector=ui_filesize->lastsector; | ||
2113 | delete ui_filesize; | ||
2114 | |||
2115 | string* driveimgdir=new string(""); | ||
2116 | *driveimgdir+=*hd24utils::getlastdir("driveimagedir"); | ||
2117 | |||
2118 | Fl_Native_File_Chooser chooser; | ||
2119 | chooser.filter("Drive Images\\t*.{img,bin,h24,hd24}\\0"); | ||
2120 | chooser.title("Create empty drive image in file"); | ||
2121 | chooser.directory(driveimgdir->c_str()); | ||
2122 | chooser.options(Fl_Native_File_Chooser::NEW_FOLDER); | ||
2123 | chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); | ||
2124 | |||
2125 | switch (chooser.show()) { | ||
2126 | case -1: break; //error | ||
2127 | case 1: break; //cancel | ||
2128 | default: | ||
2129 | // save header to chooser.filename() | ||
2130 | |||
2131 | bool bFileexists=hd24utils::fileExists(chooser.filename()); | ||
2132 | if (bFileexists) { | ||
2133 | bool choice=confirm( | ||
2134 | "A file with this name already exists. Do you wish to overwrite it?" | ||
2135 | ); | ||
2136 | if (!(choice)) return; | ||
2137 | } | ||
2138 | string* strfile=new string(chooser.filename()); | ||
2139 | //cout << "filename = " << *strfile << endl; | ||
2140 | string* fpath=new string(""); | ||
2141 | *fpath+=strfile->substr(0,strlen(strfile->c_str())-strlen(fl_filename_name(strfile->c_str()))); | ||
2142 | hd24utils::setlastdir("driveimagedir",fpath->c_str()); | ||
2143 | this->transfer_cancel=0; | ||
2144 | this->mustdispsavemessage=true; | ||
2145 | Fl::add_timeout(.25,savemessage_callback,this); | ||
2146 | // __uint32 lastsector=2097151; // 1 GiB | ||
2147 | int result=hd24utils::newdriveimage(strfile,lastsector,&this->savemessage[0],&this->transfer_cancel); | ||
2148 | |||
2149 | this->mustdispsavemessage=false; | ||
2150 | setstatus("Done."); | ||
2151 | if (result==0) { | ||
2152 | setstatus("Done."); | ||
2153 | int wantopen=confirm("Drive image created successfully.\\nDo you want to open it now?"); | ||
2154 | if (wantopen==1) | ||
2155 | { | ||
2156 | string* idir=hd24utils::getlastdir("driveimagedir"); | ||
2157 | hd24fs* sysob=new hd24fs(idir->c_str(),hd24fs::MODE_RDWR,strfile,false); | ||
2158 | delete idir; | ||
2159 | if (currenthd24!=NULL) | ||
2160 | { | ||
2161 | currenthd24->~hd24fs(); | ||
2162 | } | ||
2163 | if (defaulthd24!=NULL) | ||
2164 | { | ||
2165 | if (defaulthd24!=currenthd24) | ||
2166 | { | ||
2167 | defaulthd24->~hd24fs(); | ||
2168 | } | ||
2169 | |||
2170 | } | ||
2171 | currenthd24=sysob; | ||
2172 | defaulthd24=sysob; | ||
2173 | } | ||
2174 | |||
2175 | } else { | ||
2176 | fl_message("Could not write drive image to file. Access denied? Disk full?"); | ||
2177 | } | ||
2178 | delete strfile; | ||
2179 | break; | ||
2180 | } | ||
2181 | setstatus("Done."); | ||
2182 | ui_refresh("newdriveimage"); | ||
2183 | delete driveimgdir;} | ||
2184 | xywh {360 105 95 20} labelsize 12 align 16 | ||
2185 | } | ||
2186 | Fl_Box {} { | ||
2187 | label {Songs marked * are write-protected.} | ||
2188 | xywh {235 175 365 15} labelfont 2 labelsize 12 align 24 | ||
2189 | } | ||
2190 | } | ||
2191 | Fl_Group songinfogroup { | ||
2192 | label {Project/Song} | ||
2193 | xywh {0 50 605 460} box UP_BOX color 52 labelfont 1 labelsize 12 align 5 hide | ||
2194 | } { | ||
2195 | Fl_Choice songname { | ||
2196 | label {Song name:} open | ||
2197 | xywh {155 155 440 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
2198 | } {} | ||
2199 | Fl_Output number_of_tracks { | ||
2200 | label {Number of tracks:} | ||
2201 | xywh {155 180 90 20} labelsize 12 textsize 12 | ||
2202 | code0 {o->clear_visible_focus();} | ||
2203 | } | ||
2204 | Fl_Output sample_rate { | ||
2205 | label {Sample rate:} | ||
2206 | callback {if (currsong==NULL) return; | ||
2207 | bool confirmrate=false; | ||
2208 | if (strcmp(o->value(),"44100")==0) { | ||
2209 | o->value("48000"); | ||
2210 | currsong->samplerate(48000); | ||
2211 | if (mixer!=NULL) mixer->control->samplerate(48000); | ||
2212 | confirmrate=confirm("Re-stamp song as 48000Hz on disk?"); | ||
2213 | } else { | ||
2214 | if (strcmp(o->value(),"48000")==0) { | ||
2215 | o->value("44100"); | ||
2216 | currsong->samplerate(44100); | ||
2217 | if (mixer!=NULL) mixer->control->samplerate(44100); | ||
2218 | confirmrate=confirm("Re-stamp song as 44100Hz on disk?"); | ||
2219 | } | ||
2220 | } | ||
2221 | if (strcmp(o->value(),"88200")==0) { | ||
2222 | o->value("96000"); | ||
2223 | currsong->samplerate(96000); | ||
2224 | if (mixer!=NULL) mixer->control->samplerate(48000); | ||
2225 | confirmrate=confirm("Re-stamp song as 96000Hz on disk?"); | ||
2226 | } else { | ||
2227 | if (strcmp(o->value(),"96000")==0) { | ||
2228 | o->value("88200"); | ||
2229 | if (mixer!=NULL) mixer->control->samplerate(44100); | ||
2230 | confirmrate=confirm("Re-stamp song as 88200Hz on disk?"); | ||
2231 | } | ||
2232 | } | ||
2233 | |||
2234 | if (confirmrate) { | ||
2235 | // currsong->songname(*(ui_rename->itemname)); | ||
2236 | currsong->save(); | ||
2237 | populate_songlist(songname->value()); | ||
2238 | } else { | ||
2239 | |||
2240 | |||
2241 | |||
2242 | if (strcmp(o->value(),"44100")==0) { | ||
2243 | o->value("48000"); | ||
2244 | currsong->samplerate(48000); | ||
2245 | if (mixer!=NULL) mixer->control->samplerate(48000); | ||
2246 | } else { | ||
2247 | if (strcmp(o->value(),"48000")==0) { | ||
2248 | o->value("44100"); | ||
2249 | currsong->samplerate(44100); | ||
2250 | if (mixer!=NULL) mixer->control->samplerate(44100); | ||
2251 | } | ||
2252 | } | ||
2253 | if (strcmp(o->value(),"88200")==0) { | ||
2254 | o->value("96000"); | ||
2255 | currsong->samplerate(96000); | ||
2256 | if (mixer!=NULL) mixer->control->samplerate(48000); | ||
2257 | } else { | ||
2258 | if (strcmp(o->value(),"96000")==0) { | ||
2259 | o->value("88200"); | ||
2260 | currsong->samplerate(88200); | ||
2261 | if (mixer!=NULL) mixer->control->samplerate(44100); | ||
2262 | } | ||
2263 | } | ||
2264 | |||
2265 | |||
2266 | } | ||
2267 | ui_refresh("stamprate");} | ||
2268 | xywh {155 230 90 20} labelsize 12 textsize 12 | ||
2269 | code0 {o->clear_visible_focus();} | ||
2270 | } | ||
2271 | Fl_Output bitdepth { | ||
2272 | label {Bit depth:} | ||
2273 | xywh {155 255 90 20} labelsize 12 textsize 12 | ||
2274 | code0 {o->clear_visible_focus();} | ||
2275 | } | ||
2276 | Fl_Output duration { | ||
2277 | label {Duration:} | ||
2278 | xywh {155 205 90 20} labelsize 12 textsize 12 | ||
2279 | code0 {o->clear_visible_focus();} | ||
2280 | } | ||
2281 | Fl_Button rename_song { | ||
2282 | label {Rename...} | ||
2283 | callback {if (currsong==NULL) return; | ||
2284 | dialog_rename* ui_rename; | ||
2285 | ui_rename=new dialog_rename(); | ||
2286 | string* currname=currsong->songname(); | ||
2287 | string* strsong=new string("Rename song"); | ||
2288 | Fl_Window* win=ui_rename->make_window(currname,strsong); | ||
2289 | delete strsong; | ||
2290 | win->end(); | ||
2291 | win->show(); | ||
2292 | |||
2293 | while (win->visible()) { Fl::wait(); } | ||
2294 | if (ui_rename->buttonclicked==1) | ||
2295 | { | ||
2296 | // OK clicked | ||
2297 | if (confirm("Do you wish to write the changes to disk?")) { | ||
2298 | currsong->songname(*(ui_rename->itemname)); | ||
2299 | currsong->save(); | ||
2300 | populate_songlist(songname->value()); | ||
2301 | } | ||
2302 | } | ||
2303 | |||
2304 | delete ui_rename; | ||
2305 | ui_refresh("rename song");} | ||
2306 | xywh {510 180 85 20} labelsize 12 align 16 | ||
2307 | } | ||
2308 | Fl_Choice locatepoints { | ||
2309 | label {Locate points:} | ||
2310 | callback {setlocbuttonlabel(locatepoints->value()); | ||
2311 | if ((locatepoints->value())==25) { | ||
2312 | button_setlocatepoint->deactivate(); | ||
2313 | } else { | ||
2314 | button_setlocatepoint->activate(); | ||
2315 | }} open | ||
2316 | xywh {155 280 215 20} down_box BORDER_BOX labelsize 12 textsize 12 deactivate | ||
2317 | } {} | ||
2318 | Fl_Button button_setlocatepoint { | ||
2319 | label {Edit...} | ||
2320 | callback {if (currsong==NULL) return; | ||
2321 | dialog_setlocate* ui_setlocate; | ||
2322 | ui_setlocate=new dialog_setlocate; | ||
2323 | int currlocchoice=locatepoints->value(); | ||
2324 | Fl_Window *win=ui_setlocate->make_window(currsong,locatepoints->value()); | ||
2325 | win->end(); | ||
2326 | win->show(); | ||
2327 | |||
2328 | while (win->visible()) { Fl::wait(); } | ||
2329 | |||
2330 | /* Dialog has closed, read the results */ | ||
2331 | |||
2332 | populate_locatepoints(currsong,locatepoints); | ||
2333 | locatepoints->value(currlocchoice); | ||
2334 | |||
2335 | if (ui_setlocate->useasrange==1) { | ||
2336 | if (currlocchoice==1) | ||
2337 | { | ||
2338 | choice_startloc=1; | ||
2339 | } | ||
2340 | if (currlocchoice==2) | ||
2341 | { | ||
2342 | choice_endloc=2; | ||
2343 | } | ||
2344 | } | ||
2345 | currsong->save(); | ||
2346 | |||
2347 | update_fromto(); | ||
2348 | delete ui_setlocate;} | ||
2349 | xywh {370 280 60 20} labelsize 12 align 16 deactivate | ||
2350 | } | ||
2351 | Fl_Check_Button writeprotected { | ||
2352 | label {Write protected} | ||
2353 | callback {if (currsong==NULL) return; | ||
2354 | bool confirmprot=false; | ||
2355 | if (o->value()==0) { | ||
2356 | currsong->setwriteprotected(false); | ||
2357 | confirmprot=confirm("Write-enable song on disk?"); | ||
2358 | } else { | ||
2359 | if (o->value()==1) { | ||
2360 | currsong->setwriteprotected(true); | ||
2361 | confirmprot=confirm("Write-protect song on disk?"); | ||
2362 | } | ||
2363 | } | ||
2364 | |||
2365 | if (confirmprot) { | ||
2366 | currsong->save(); | ||
2367 | populate_songlist(songname->value()); | ||
2368 | } else { | ||
2369 | if (o->value()==0) { | ||
2370 | o->value(1); | ||
2371 | } else { | ||
2372 | o->value(0); | ||
2373 | } | ||
2374 | } | ||
2375 | ui_refresh("writeprot");} | ||
2376 | xywh {155 300 20 25} down_box DOWN_BOX labelsize 12 align 8 | ||
2377 | } | ||
2378 | Fl_Button button_golocatepoint { | ||
2379 | label Go | ||
2380 | callback {if (currsong==NULL) return; | ||
2381 | if (recorder==NULL) return; | ||
2382 | recorder->control->hd24_transport_goloc(currsong->getlocatepos(locatepoints->value()));} | ||
2383 | xywh {435 280 155 20} labelsize 12 align 16 | ||
2384 | } | ||
2385 | Fl_Output number_of_songs { | ||
2386 | label {Number of songs:} | ||
2387 | xywh {155 105 85 20} labelsize 12 textsize 12 | ||
2388 | code0 {o->clear_visible_focus();} | ||
2389 | } | ||
2390 | Fl_Choice projectname { | ||
2391 | label {Project name:} open | ||
2392 | xywh {155 80 440 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
2393 | } {} | ||
2394 | Fl_Button rename_project { | ||
2395 | label {Rename...} | ||
2396 | callback {if (currproj==NULL) return; | ||
2397 | dialog_rename* ui_rename; | ||
2398 | ui_rename=new dialog_rename(); | ||
2399 | |||
2400 | string* currname=currproj->projectname(); | ||
2401 | string* strproject=new string("Rename project"); | ||
2402 | Fl_Window* win=ui_rename->make_window(currname,strproject); | ||
2403 | if (strproject!=NULL) | ||
2404 | { | ||
2405 | delete strproject; | ||
2406 | } | ||
2407 | win->end(); | ||
2408 | win->show(); | ||
2409 | |||
2410 | while (win->visible()) { Fl::wait(); } | ||
2411 | if (ui_rename->buttonclicked==1) | ||
2412 | { | ||
2413 | // OK clicked | ||
2414 | if (confirm("Do you wish to write the changes to disk?")) { | ||
2415 | currproj->projectname(*(ui_rename->itemname)); | ||
2416 | currproj->save(); | ||
2417 | populate_projectlist(1+projectname->value()); | ||
2418 | } | ||
2419 | |||
2420 | |||
2421 | |||
2422 | |||
2423 | } | ||
2424 | delete ui_rename; | ||
2425 | ui_refresh("ren proj 2");} | ||
2426 | xywh {510 105 85 20} labelsize 12 align 16 | ||
2427 | } | ||
2428 | Fl_Box {} { | ||
2429 | label {Project information} | ||
2430 | xywh {0 58 5 17} labelfont 1 labelsize 12 align 8 | ||
2431 | } | ||
2432 | Fl_Box {} { | ||
2433 | label {Song information} | ||
2434 | xywh {0 138 5 17} labelfont 1 labelsize 12 align 8 | ||
2435 | } | ||
2436 | Fl_Output song_messages_label { | ||
2437 | label {Recovery messages:} | ||
2438 | xywh {155 325 10 20} type Multiline labelsize 12 textsize 12 | ||
2439 | code0 {o->clear_visible_focus();} | ||
2440 | } | ||
2441 | Fl_Output song_messages { | ||
2442 | xywh {155 325 440 40} type Multiline labelsize 12 textsize 12 | ||
2443 | code0 {o->clear_visible_focus();} | ||
2444 | } | ||
2445 | Fl_Button delete_project { | ||
2446 | label Delete | ||
2447 | callback {bool wantdel=confirm("Are you sure you want to delete this project, all songs in it and their recorded audio?\\nThis operation cannot be undone!"); | ||
2448 | if (!wantdel) return; | ||
2449 | __sint32 projtodel=currproj->projectid(); | ||
2450 | __uint32 result=currenthd24->deleteproject(projtodel); | ||
2451 | result++; result--; // ignore for now | ||
2452 | ui_refresh("del proj");} | ||
2453 | xywh {455 105 55 20} labelsize 12 align 16 | ||
2454 | } | ||
2455 | Fl_Button delete_song { | ||
2456 | label Delete | ||
2457 | callback {if (currproj==NULL) return; | ||
2458 | if (currsong==NULL) return; | ||
2459 | |||
2460 | bool wantdel=confirm("Are you sure you want to delete this song and its recorded audio?\\nThis operation cannot be undone!"); | ||
2461 | if (!wantdel) return; | ||
2462 | __uint32 songtodel=currsong->songid(); | ||
2463 | __uint32 result=currproj->deletesong(songtodel); | ||
2464 | result++; result--; //ignore for now | ||
2465 | ui_refresh("del song");} | ||
2466 | xywh {455 180 55 20} labelsize 12 align 16 | ||
2467 | } | ||
2468 | Fl_Button create_project { | ||
2469 | label {New Project...} | ||
2470 | callback {if (currenthd24==NULL) { | ||
2471 | fl_message("No drive is currently selected."); | ||
2472 | return; | ||
2473 | } | ||
2474 | |||
2475 | if (currenthd24->projectcount() == currenthd24->maxprojects()) | ||
2476 | { | ||
2477 | fl_message("Cannot create project.\\nThe maximum number of projects is already in use!"); | ||
2478 | return; | ||
2479 | } | ||
2480 | // - check if current project is NULL | ||
2481 | // - check if there's song space left in it | ||
2482 | dialog_newproject* ui_newproject; | ||
2483 | ui_newproject=new dialog_newproject(); | ||
2484 | Fl_Window *win=ui_newproject->make_window(); | ||
2485 | win->end(); | ||
2486 | win->show(); | ||
2487 | |||
2488 | while (win->visible()) { Fl::wait(); } | ||
2489 | |||
2490 | if (ui_newproject->buttonclicked!=1) | ||
2491 | { | ||
2492 | delete ui_newproject; | ||
2493 | return; | ||
2494 | } | ||
2495 | char projname[65]; | ||
2496 | for (int i=0;i<65;i++) { | ||
2497 | projname[i]=0; | ||
2498 | } | ||
2499 | hd24project* newproj=currenthd24->createproject( | ||
2500 | (const char*)strncpy(projname,ui_newproject->projectname,64) | ||
2501 | ); | ||
2502 | if (newproj==NULL) | ||
2503 | { | ||
2504 | fl_message("Could not create the project. Access denied?"); | ||
2505 | delete ui_newproject; | ||
2506 | return; | ||
2507 | } | ||
2508 | |||
2509 | //if (ui_newsong->buttonclicked==1) { | ||
2510 | // lastsector=ui_filesize->lastsector; | ||
2511 | //} | ||
2512 | ui_refresh("createproj"); | ||
2513 | delete ui_newproject;} | ||
2514 | xywh {360 105 95 20} labelsize 12 align 16 | ||
2515 | } | ||
2516 | Fl_Button create_song { | ||
2517 | label {New Song...} | ||
2518 | callback {if (currenthd24==NULL) { | ||
2519 | fl_message("No drive is currently selected."); | ||
2520 | return; | ||
2521 | } | ||
2522 | |||
2523 | if (currproj==NULL) { | ||
2524 | fl_message("No project is currently selected."); | ||
2525 | return; | ||
2526 | } | ||
2527 | |||
2528 | if (currproj->songcount() == currproj->maxsongs()) | ||
2529 | { | ||
2530 | fl_message("Cannot create song.\\nThe maximum number of songs is already in use!"); | ||
2531 | return; | ||
2532 | } | ||
2533 | savemessage[0]='\\0'; | ||
2534 | transfer_cancel=0; | ||
2535 | |||
2536 | this->mustdispsavemessage=true; | ||
2537 | Fl::add_timeout(0,savemessage_callback,this); | ||
2538 | |||
2539 | dialog_newsong* ui_newsong; | ||
2540 | ui_newsong=new dialog_newsong(); | ||
2541 | Fl_Window *win=ui_newsong->make_window(); | ||
2542 | win->end(); | ||
2543 | win->show(); | ||
2544 | |||
2545 | |||
2546 | |||
2547 | while (win->visible()) { Fl::wait(); } | ||
2548 | |||
2549 | |||
2550 | |||
2551 | //__uint32 lastsector=0; | ||
2552 | |||
2553 | if (ui_newsong->buttonclicked!=1) | ||
2554 | { | ||
2555 | mustdispsavemessage=false; | ||
2556 | transfer_cancel=1; | ||
2557 | delete ui_newsong; | ||
2558 | return; | ||
2559 | } | ||
2560 | |||
2561 | char songname[65]; | ||
2562 | for (int i=0;i<65;i++) { | ||
2563 | songname[i]=0; | ||
2564 | } | ||
2565 | hd24song* newsong=currproj->createsong( | ||
2566 | (const char*)strncpy(songname,ui_newsong->songname,64),ui_newsong->trackcount,ui_newsong->samplerate | ||
2567 | ); | ||
2568 | |||
2569 | |||
2570 | if (newsong==NULL) | ||
2571 | { | ||
2572 | fl_message("Could not create the song. Access denied?"); | ||
2573 | mustdispsavemessage=false; | ||
2574 | transfer_cancel=1; | ||
2575 | delete ui_newsong; | ||
2576 | return; | ||
2577 | } | ||
2578 | __uint32 samlen=ui_newsong->songlength_in_samples; | ||
2579 | win->~Fl_Window(); | ||
2580 | delete ui_newsong; | ||
2581 | // optionally, lengthen song to specified size. | ||
2582 | if (samlen>0) { | ||
2583 | setstatus("Lengthening song... "); | ||
2584 | |||
2585 | |||
2586 | \#if (HD24DEBUG==1) | ||
2587 | cout << "about to start lengthening song to maxlen=" << samlen << endl; | ||
2588 | \#endif | ||
2589 | bool clearnew=true; // clear lengthened part | ||
2590 | |||
2591 | __uint32 translen=newsong->songlength_in_samples(samlen,clearnew,&this->savemessage[0],&this->transfer_cancel,Fl::check); | ||
2592 | |||
2593 | |||
2594 | \#if (HD24DEBUG==1) | ||
2595 | cout << "verifying actual song length " << endl; | ||
2596 | cout << "new len=" << translen << endl; | ||
2597 | \#endif | ||
2598 | if (translen!=samlen) | ||
2599 | { | ||
2600 | \#if (HD24DEBUG==1) | ||
2601 | |||
2602 | cout << "new len<> maxlen so not enough space." << endl; | ||
2603 | \#endif | ||
2604 | if (transfer_cancel==0) | ||
2605 | { | ||
2606 | fl_message("Not enough space on HD24 drive."); | ||
2607 | } else | ||
2608 | { | ||
2609 | fl_message("Song lengthening cancelled by user."); | ||
2610 | } | ||
2611 | return; | ||
2612 | } | ||
2613 | newsong->save(); | ||
2614 | |||
2615 | \#if (HD24DEBUG==1) | ||
2616 | cout << "translen is now " << translen << endl; | ||
2617 | \#endif | ||
2618 | } | ||
2619 | stop_transfer->hide(); | ||
2620 | this->mustdispsavemessage=false; | ||
2621 | delete newsong; // ui refresh will pick it up as currsong. | ||
2622 | ui_refresh("newsong"); | ||
2623 | setstatus("Ready."); | ||
2624 | return;} | ||
2625 | xywh {360 180 95 20} labelsize 12 align 16 | ||
2626 | } | ||
2627 | Fl_Box {} { | ||
2628 | label Hz | ||
2629 | xywh {245 230 19 20} labelsize 12 align 20 | ||
2630 | } | ||
2631 | Fl_Box {} { | ||
2632 | label {hours:minutes:seconds.frames} | ||
2633 | xywh {245 205 195 20} labelsize 12 align 20 | ||
2634 | } | ||
2635 | } | ||
2636 | Fl_Group tabRecorder { | ||
2637 | label Recorder open | ||
2638 | xywh {-5 46 620 464} color 52 labelfont 1 labelsize 12 hide | ||
2639 | } { | ||
2640 | Fl_Group recorder {open | ||
2641 | xywh {-5 49 610 457} color 53 selection_color 53 align 0 | ||
2642 | code0 {o->set_ui(this);} | ||
2643 | code1 {o->control->audiolib(AUDIOLIB_PORTAUDIO,(void*)(this->portaudio));} | ||
2644 | code2 {o->control->audiolib(AUDIOLIB_JACK,(void*)(this->libjack));} | ||
2645 | code3 {o->control->audiolib(AUDIOLIB_SNDFILE,(void*)(this->soundfile));} | ||
2646 | class RecorderUI | ||
2647 | } {} | ||
2648 | } | ||
2649 | Fl_Group tabMixer { | ||
2650 | label Mixer open | ||
2651 | xywh {0 45 605 463} color 52 labelfont 1 labelsize 12 hide | ||
2652 | } { | ||
2653 | Fl_Group mixer {open | ||
2654 | xywh {0 49 605 456} color 53 selection_color 53 align 0 | ||
2655 | code0 {o->set_ui(this);} | ||
2656 | class MixerUI | ||
2657 | } {} | ||
2658 | } | ||
2659 | Fl_Group tabCopyToPC { | ||
2660 | label {Copy to PC} open | ||
2661 | xywh {5 50 600 455} color 52 labelfont 1 labelsize 12 hide | ||
2662 | } { | ||
2663 | Fl_Check_Button {} { | ||
2664 | xywh {85 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2665 | code0 {track[0]=o;} | ||
2666 | } | ||
2667 | Fl_Check_Button {} { | ||
2668 | xywh {105 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2669 | code0 {track[1]=o;} | ||
2670 | } | ||
2671 | Fl_Check_Button {} { | ||
2672 | xywh {125 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2673 | code0 {track[2]=o;} | ||
2674 | } | ||
2675 | Fl_Check_Button {} { | ||
2676 | xywh {145 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2677 | code0 {track[3]=o;} | ||
2678 | } | ||
2679 | Fl_Check_Button {} { | ||
2680 | xywh {165 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2681 | code0 {track[4]=o;} | ||
2682 | } | ||
2683 | Fl_Check_Button {} { | ||
2684 | xywh {185 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2685 | code0 {track[5]=o;} | ||
2686 | } | ||
2687 | Fl_Check_Button {} { | ||
2688 | xywh {205 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2689 | code0 {track[6]=o;} | ||
2690 | } | ||
2691 | Fl_Check_Button {} { | ||
2692 | xywh {225 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2693 | code0 {track[7]=o;} | ||
2694 | } | ||
2695 | Fl_Check_Button {} { | ||
2696 | xywh {255 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2697 | code0 {track[8]=o;} | ||
2698 | } | ||
2699 | Fl_Check_Button {} { | ||
2700 | xywh {275 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2701 | code0 {track[9]=o;} | ||
2702 | } | ||
2703 | Fl_Check_Button {} { | ||
2704 | xywh {295 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2705 | code0 {track[10]=o;} | ||
2706 | } | ||
2707 | Fl_Check_Button {} { | ||
2708 | xywh {315 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2709 | code0 {track[11]=o;} | ||
2710 | } | ||
2711 | Fl_Check_Button {} { | ||
2712 | xywh {335 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2713 | code0 {track[12]=o;} | ||
2714 | } | ||
2715 | Fl_Check_Button {} { | ||
2716 | xywh {355 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2717 | code0 {track[13]=o;} | ||
2718 | } | ||
2719 | Fl_Check_Button {} { | ||
2720 | xywh {375 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2721 | code0 {track[14]=o;} | ||
2722 | } | ||
2723 | Fl_Check_Button {} { | ||
2724 | xywh {395 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2725 | code0 {track[15]=o;} | ||
2726 | } | ||
2727 | Fl_Check_Button {} { | ||
2728 | xywh {425 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2729 | code0 {track[16]=o;} | ||
2730 | } | ||
2731 | Fl_Check_Button {} { | ||
2732 | xywh {445 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2733 | code0 {track[17]=o;} | ||
2734 | } | ||
2735 | Fl_Check_Button {} { | ||
2736 | xywh {465 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2737 | code0 {track[18]=o;} | ||
2738 | } | ||
2739 | Fl_Check_Button {} { | ||
2740 | xywh {485 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2741 | code0 {track[19]=o;} | ||
2742 | } | ||
2743 | Fl_Check_Button {} { | ||
2744 | xywh {505 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2745 | code0 {track[20]=o;} | ||
2746 | } | ||
2747 | Fl_Check_Button {} { | ||
2748 | xywh {525 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2749 | code0 {track[21]=o;} | ||
2750 | } | ||
2751 | Fl_Check_Button {} { | ||
2752 | xywh {545 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2753 | code0 {track[22]=o;} | ||
2754 | } | ||
2755 | Fl_Check_Button {} { | ||
2756 | xywh {565 92 20 20} down_box DOWN_BOX value 1 labelsize 12 align 1 | ||
2757 | code0 {track[23]=o;} | ||
2758 | } | ||
2759 | Fl_Box {} { | ||
2760 | label {Tracks:} | ||
2761 | xywh {15 79 70 16} box FLAT_BOX color 52 labelsize 12 align 20 | ||
2762 | } | ||
2763 | Fl_Button button_invert_tracks { | ||
2764 | label Invert | ||
2765 | callback {int i; | ||
2766 | for (i=0; i<MAXCHANNELS; i++) { | ||
2767 | track[i]->value(1-track[i]->value()); | ||
2768 | }} | ||
2769 | xywh {15 92 65 20} labelsize 12 align 16 | ||
2770 | } | ||
2771 | Fl_Box led1 { | ||
2772 | label 01 | ||
2773 | xywh {85 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2774 | code0 {this->trackled[0]=o;} | ||
2775 | } | ||
2776 | Fl_Box led2 { | ||
2777 | label 02 | ||
2778 | xywh {105 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2779 | code0 {this->trackled[1]=o;} | ||
2780 | } | ||
2781 | Fl_Box led3 { | ||
2782 | label 03 | ||
2783 | xywh {125 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2784 | code0 {this->trackled[2]=o;} | ||
2785 | } | ||
2786 | Fl_Box led4 { | ||
2787 | label 04 | ||
2788 | xywh {145 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2789 | code0 {this->trackled[3]=o;} | ||
2790 | } | ||
2791 | Fl_Box led5 { | ||
2792 | label 05 | ||
2793 | xywh {165 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2794 | code0 {this->trackled[4]=o;} | ||
2795 | } | ||
2796 | Fl_Box led6 { | ||
2797 | label 06 | ||
2798 | xywh {185 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2799 | code0 {this->trackled[5]=o;} | ||
2800 | } | ||
2801 | Fl_Box led7 { | ||
2802 | label 07 | ||
2803 | xywh {205 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2804 | code0 {this->trackled[6]=o;} | ||
2805 | } | ||
2806 | Fl_Box led8 { | ||
2807 | label 08 | ||
2808 | xywh {225 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2809 | code0 {this->trackled[7]=o;} | ||
2810 | } | ||
2811 | Fl_Box led9 { | ||
2812 | label 09 | ||
2813 | xywh {255 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2814 | code0 {this->trackled[8]=o;} | ||
2815 | } | ||
2816 | Fl_Box led10 { | ||
2817 | label 10 | ||
2818 | xywh {275 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2819 | code0 {this->trackled[9]=o;} | ||
2820 | } | ||
2821 | Fl_Box led11 { | ||
2822 | label 11 | ||
2823 | xywh {295 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2824 | code0 {this->trackled[10]=o;} | ||
2825 | } | ||
2826 | Fl_Box led12 { | ||
2827 | label 12 | ||
2828 | xywh {315 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2829 | code0 {this->trackled[11]=o;} | ||
2830 | } | ||
2831 | Fl_Box led13 { | ||
2832 | label 13 | ||
2833 | xywh {335 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2834 | code0 {this->trackled[12]=o;} | ||
2835 | } | ||
2836 | Fl_Box led14 { | ||
2837 | label 14 | ||
2838 | xywh {355 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2839 | code0 {this->trackled[13]=o;} | ||
2840 | } | ||
2841 | Fl_Box led15 { | ||
2842 | label 15 | ||
2843 | xywh {375 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2844 | code0 {this->trackled[14]=o;} | ||
2845 | } | ||
2846 | Fl_Box led16 { | ||
2847 | label 16 | ||
2848 | xywh {395 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2849 | code0 {this->trackled[15]=o;} | ||
2850 | } | ||
2851 | Fl_Box led17 { | ||
2852 | label 17 | ||
2853 | xywh {424 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2854 | code0 {this->trackled[16]=o;} | ||
2855 | } | ||
2856 | Fl_Box led18 { | ||
2857 | label 18 | ||
2858 | xywh {444 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2859 | code0 {this->trackled[17]=o;} | ||
2860 | } | ||
2861 | Fl_Box led19 { | ||
2862 | label 19 | ||
2863 | xywh {464 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2864 | code0 {this->trackled[18]=o;} | ||
2865 | } | ||
2866 | Fl_Box led20 { | ||
2867 | label 20 | ||
2868 | xywh {484 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2869 | code0 {this->trackled[19]=o;} | ||
2870 | } | ||
2871 | Fl_Box led21 { | ||
2872 | label 21 | ||
2873 | xywh {504 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2874 | code0 {this->trackled[20]=o;} | ||
2875 | } | ||
2876 | Fl_Box led22 { | ||
2877 | label 22 | ||
2878 | xywh {524 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2879 | code0 {this->trackled[21]=o;} | ||
2880 | } | ||
2881 | Fl_Box led23 { | ||
2882 | label 23 | ||
2883 | xywh {544 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2884 | code0 {this->trackled[22]=o;} | ||
2885 | } | ||
2886 | Fl_Box led24 { | ||
2887 | label 24 | ||
2888 | xywh {564 80 20 14} box FLAT_BOX color 52 selection_color 0 labelsize 12 | ||
2889 | code0 {this->trackled[23]=o;} | ||
2890 | } | ||
2891 | Fl_Button button_transfertopc { | ||
2892 | label Transfer | ||
2893 | callback {recorder->control->button_stop_call(); | ||
2894 | mustdisplaytimer=false; | ||
2895 | __sint64 bytestransferred=0; | ||
2896 | transeng->sizelimit(strtoll(sizelimit->value(),0,10)); | ||
2897 | |||
2898 | int bytespersam; | ||
2899 | int wantsplit=0; | ||
2900 | __uint32 numsongs=1; | ||
2901 | double dif; | ||
2902 | __sint64 totbytestotransfer=0; | ||
2903 | |||
2904 | bool needoverwrite=false; | ||
2905 | bool isproblem=false; | ||
2906 | __uint32 channelstotransfer=0; | ||
2907 | |||
2908 | __uint32 i=0; | ||
2909 | |||
2910 | transfer_cancel=0; | ||
2911 | |||
2912 | if (currproj==NULL) | ||
2913 | { | ||
2914 | \#if (HD24DEBUG==1) | ||
2915 | cout << "No current project." << endl; | ||
2916 | \#endif | ||
2917 | return; | ||
2918 | } | ||
2919 | |||
2920 | /* TODO: DISABLE/ENABLE JACK BEFORE/AFTER TRANSFER */ | ||
2921 | //jack_client_t* saveclient=jackclient; | ||
2922 | //jackclient=NULL; | ||
2923 | /* TODO: DISABLE/ENABLE JACK BEFORE/AFTER TRANSFER */ | ||
2924 | |||
2925 | if (!(hd24utils::dirExists(projectdir->value()))) | ||
2926 | { | ||
2927 | fl_message("Project directory no longer exists.\\nPlease select another directory and try again."); | ||
2928 | //jackclient=saveclient; | ||
2929 | \#if (HD24DEBUG==1) | ||
2930 | cout << "project dir no longer exists, transfer cancelled." << endl; | ||
2931 | \#endif | ||
2932 | |||
2933 | return; | ||
2934 | } | ||
2935 | transeng->setstatusfunction=HD24UserInterface::transferstatus; | ||
2936 | transeng->projectdir(projectdir->value()); | ||
2937 | transeng->set_ui((void*)this); | ||
2938 | transeng->mixer(this->mixer->control); | ||
2939 | transeng->soundfile=soundfile; | ||
2940 | bool channelwarning=false; | ||
2941 | int currfileformat=0; | ||
2942 | bool multisong=false; | ||
2943 | if (currsong==NULL) | ||
2944 | { | ||
2945 | multisong=true; | ||
2946 | } | ||
2947 | else | ||
2948 | { | ||
2949 | // count channels to transfer | ||
2950 | __uint32 channels=currsong->logical_channels(); | ||
2951 | for (unsigned int handle=0;handle<channels;handle++) | ||
2952 | { | ||
2953 | if (track[handle]->value()!=0) | ||
2954 | { | ||
2955 | channelstotransfer++; | ||
2956 | transeng->trackselected(handle,true); | ||
2957 | } | ||
2958 | else | ||
2959 | { | ||
2960 | transeng->trackselected(handle,false); | ||
2961 | } | ||
2962 | } | ||
2963 | |||
2964 | transeng->mixleft( (transfersource_mixleft->value())==1); | ||
2965 | transeng->mixright( (transfersource_mixright->value()) ==1); | ||
2966 | |||
2967 | currfileformat=fileformat->value(); | ||
2968 | |||
2969 | transeng->selectedformat(currfileformat); | ||
2970 | |||
2971 | if (transeng->format_outputchannels(currfileformat)>1) | ||
2972 | { | ||
2973 | if ((channelstotransfer%(transeng->format_outputchannels(currfileformat)))!=0) | ||
2974 | { | ||
2975 | channelwarning=true; | ||
2976 | } | ||
2977 | } | ||
2978 | |||
2979 | } | ||
2980 | |||
2981 | if (multisong) | ||
2982 | { | ||
2983 | numsongs=currproj->songcount(); | ||
2984 | } | ||
2985 | if (channelwarning) | ||
2986 | { | ||
2987 | string multiple="Number of channels to export must be a multiple of "; | ||
2988 | string* mynum=Convert::int2str(transeng->format_outputchannels(currfileformat)); | ||
2989 | multiple+=*mynum; | ||
2990 | if (transeng->format_outputchannels(currfileformat)==2) | ||
2991 | { | ||
2992 | multiple+="\\nto export to stereo pairs."; | ||
2993 | } else { | ||
2994 | multiple+="\\nfor export to groups of "; | ||
2995 | multiple+=*mynum; | ||
2996 | multiple+=" channels."; | ||
2997 | } | ||
2998 | fl_message("%s",multiple.c_str()); | ||
2999 | delete mynum; | ||
3000 | /* TODO: DISABLE/ENABLE JACK BEFORE/AFTER TRANSFER */ | ||
3001 | // jackclient=saveclient; | ||
3002 | |||
3003 | |||
3004 | return; | ||
3005 | |||
3006 | } | ||
3007 | if (numsongs==0) | ||
3008 | { | ||
3009 | \#if (HD24DEBUG==1) | ||
3010 | cout << "multisong transfer: no songs in current project." << endl; | ||
3011 | \#endif | ||
3012 | fl_message("Nothing to do!"); | ||
3013 | /* TODO: DISABLE/ENABLE JACK BEFORE/AFTER TRANSFER */ | ||
3014 | // jackclient=saveclient; | ||
3015 | |||
3016 | return; | ||
3017 | } | ||
3018 | int havedoublesongname=0; | ||
3019 | if (multisong && (numsongs>1)) | ||
3020 | { | ||
3021 | // check if any song names are duplicated | ||
3022 | hd24song* s1=NULL; | ||
3023 | hd24song* s2=NULL; | ||
3024 | for (unsigned i=1; i<numsongs; i++) | ||
3025 | { | ||
3026 | if (s1!=NULL) { | ||
3027 | delete s1; | ||
3028 | s1=NULL; | ||
3029 | } | ||
3030 | s1=currproj->getsong(i); | ||
3031 | string* songname1=s1->songname(); | ||
3032 | for (unsigned int j=i+1; j<=numsongs; j++) { | ||
3033 | if (s2!=NULL) { | ||
3034 | delete s2; | ||
3035 | s2=NULL; | ||
3036 | } | ||
3037 | s2=currproj->getsong(j); | ||
3038 | string* songname2=s2->songname(); | ||
3039 | if (*songname1==*songname2) { | ||
3040 | havedoublesongname=1; | ||
3041 | } | ||
3042 | delete songname2; | ||
3043 | if (havedoublesongname==1) break; | ||
3044 | } | ||
3045 | delete songname1; | ||
3046 | if (havedoublesongname==1) break; | ||
3047 | } | ||
3048 | if (s1!=NULL) { | ||
3049 | delete s1; | ||
3050 | s1=NULL; | ||
3051 | } | ||
3052 | if (s2!=NULL) { | ||
3053 | delete s2; | ||
3054 | s2=NULL; | ||
3055 | } | ||
3056 | } | ||
3057 | if (havedoublesongname==1) | ||
3058 | { | ||
3059 | if (!confirm( | ||
3060 | "Duplicate song names were detected. If you continue, \\n" | ||
3061 | "exported songs will be prefixed with the song number. \\n\\n" | ||
3062 | "If you prefer to name the songs before export, you will\\n" | ||
3063 | "want to stop now.\\n\\n" | ||
3064 | "Do you wish to continue?" | ||
3065 | ) | ||
3066 | ) { | ||
3067 | /* TODO: DISABLE/ENABLE JACK BEFORE/AFTER TRANSFER */ | ||
3068 | // jackclient=saveclient; | ||
3069 | return; | ||
3070 | }; | ||
3071 | } | ||
3072 | // preparation for the transfers | ||
3073 | for (i=1; i<=numsongs; i++) | ||
3074 | { | ||
3075 | if (multisong) | ||
3076 | { | ||
3077 | if (currsong!=NULL) { | ||
3078 | delete currsong; | ||
3079 | currsong=NULL; | ||
3080 | } | ||
3081 | currsong=currproj->getsong(i); | ||
3082 | if (currsong!=NULL) | ||
3083 | { | ||
3084 | channelstotransfer=currsong->logical_channels(); | ||
3085 | choice_startloc=0; | ||
3086 | choice_endloc=currsong->locatepointcount(); | ||
3087 | } | ||
3088 | } | ||
3089 | \#if (HD24DEBUG==1) | ||
3090 | cout << "channels to transfer=" << channelstotransfer << endl; | ||
3091 | \#endif | ||
3092 | __uint64 bytestotransfer_perchannel=0; | ||
3093 | __uint64 bytestotransfer_thissong=0; | ||
3094 | transeng->sourcesong(currsong); | ||
3095 | if (currsong!=NULL) | ||
3096 | { | ||
3097 | bytespersam=(currsong->bitdepth())/8; | ||
3098 | // for kb/sec calculation | ||
3099 | // because of this, double at higher sample rates | ||
3100 | |||
3101 | __uint32 samstotrans_thissong; | ||
3102 | if (multisong) | ||
3103 | { | ||
3104 | samstotrans_thissong=currsong->songlength_in_samples(); | ||
3105 | transeng->startoffset(0); | ||
3106 | transeng->endoffset(currsong->songlength_in_samples()); | ||
3107 | } | ||
3108 | else | ||
3109 | { | ||
3110 | __uint32 startoffset=0; | ||
3111 | __uint32 endoffset=0; | ||
3112 | |||
3113 | if (choice_startloc!=0) { | ||
3114 | startoffset=currsong->getlocatepos(choice_startloc); | ||
3115 | } | ||
3116 | if (choice_endloc!=0) | ||
3117 | { | ||
3118 | endoffset=currsong->getlocatepos(choice_endloc); | ||
3119 | } | ||
3120 | transeng->startoffset(startoffset); | ||
3121 | transeng->endoffset(endoffset); | ||
3122 | if (endoffset>startoffset) | ||
3123 | { | ||
3124 | samstotrans_thissong=endoffset-startoffset; | ||
3125 | } | ||
3126 | else | ||
3127 | { | ||
3128 | samstotrans_thissong=startoffset-endoffset; | ||
3129 | } | ||
3130 | } | ||
3131 | \#if (HD24DEBUG==1) | ||
3132 | cout << "sams to transfer for this song=" << samstotrans_thissong << endl ; | ||
3133 | \#endif | ||
3134 | if (samstotrans_thissong==0xFFFFFFFF) | ||
3135 | { | ||
3136 | bool wanttransfer=confirm( | ||
3137 | "You are trying to transfer the maximum song size possible\\n" | ||
3138 | "(more than twenty hours or 300 Gigabytes of audio). \\n\\n" | ||
3139 | "HD24tools will gladly try to perform this transfer for you,\\n" | ||
3140 | "but it will take VERY LONG, and is probably not very helpful\\n" | ||
3141 | "to you.\\n\\n" | ||
3142 | "If you are currently trying to recover audio, you probably\\n" | ||
3143 | "forgot to set the export range (with the 'Range...' button\\n" | ||
3144 | "above). It is highly recommended to listen to your audio\\n" | ||
3145 | "and set two locate points before setting the export range.\\n\\n" | ||
3146 | "Do you want to perform this long and possibly useless\\n" | ||
3147 | "transfer anyway?"); | ||
3148 | if (!(wanttransfer)) return; | ||
3149 | } | ||
3150 | |||
3151 | bytestotransfer_perchannel=(__sint64)((__sint64)samstotrans_thissong*(__sint64)bytespersam); | ||
3152 | |||
3153 | // hi-samplerate correction: | ||
3154 | bytestotransfer_perchannel*=(currsong->physical_channels()/currsong->logical_channels()); | ||
3155 | bytestotransfer_thissong=(channelstotransfer*bytestotransfer_perchannel); | ||
3156 | |||
3157 | totbytestotransfer+=bytestotransfer_thissong; | ||
3158 | |||
3159 | if (!(needoverwrite)) | ||
3160 | { | ||
3161 | needoverwrite=anyfilesexist(currsong); | ||
3162 | } | ||
3163 | } | ||
3164 | |||
3165 | |||
3166 | /* The above number equals 2 giga/4, to bypass format limitations. | ||
3167 | For 24-bit samples 2 giga/3 would suffice but some space could | ||
3168 | be needed by headers etc. */ | ||
3169 | __uint64 MAXBYTES=transeng->sizelimit(); | ||
3170 | // max number of samples per giga is half for high samplerate files | ||
3171 | if (multisong) | ||
3172 | { | ||
3173 | delete currsong; | ||
3174 | currsong=NULL; | ||
3175 | } | ||
3176 | \#if (HD24DEBUG==1) | ||
3177 | cout << "Maxbytes per channel=" << MAXBYTES ; | ||
3178 | cout << "bytes per channel=" << bytestotransfer_perchannel << endl; | ||
3179 | \#endif | ||
3180 | if (bytestotransfer_perchannel>MAXBYTES) | ||
3181 | { | ||
3182 | if (wantsplit!=1) | ||
3183 | { | ||
3184 | /* | ||
3185 | int choice=fl_choice( | ||
3186 | "Exported audio files may be too large to play or edit. \\nDo you want to export the file as multiple smaller chunks?", | ||
3187 | "Yes","No","Cancel" | ||
3188 | ); | ||
3189 | if (choice==2) | ||
3190 | { | ||
3191 | \#if (HD24DEBUG==1) | ||
3192 | cout << "user cancelled too large file transfer" << endl; | ||
3193 | \#endif | ||
3194 | //jackclient=saveclient; | ||
3195 | return; // cancelled | ||
3196 | } | ||
3197 | if (choice==0) | ||
3198 | { | ||
3199 | wantsplit=1; | ||
3200 | } | ||
3201 | */ | ||
3202 | if (autosplit->value()==1) { | ||
3203 | wantsplit=1; | ||
3204 | } | ||
3205 | } | ||
3206 | } | ||
3207 | } | ||
3208 | if (multisong) | ||
3209 | { | ||
3210 | if (currsong!=NULL) { | ||
3211 | delete currsong; | ||
3212 | currsong=NULL; | ||
3213 | } | ||
3214 | } | ||
3215 | |||
3216 | // do we need to overwrite any files? Are we allowed to? | ||
3217 | if (needoverwrite) | ||
3218 | { | ||
3219 | isproblem=(!(confirm("One or more output files already exist. Do you want to overwrite them?"))); | ||
3220 | } | ||
3221 | |||
3222 | if (isproblem) | ||
3223 | { | ||
3224 | \#if (HD24DEBUG==1) | ||
3225 | cout << "user does not wish to perform needed overwrite." << endl; | ||
3226 | \#endif | ||
3227 | /* TODO: DISABLE/ENABLE JACK BEFORE/AFTER TRANSFER */ | ||
3228 | // jackclient=saveclient; | ||
3229 | return; | ||
3230 | } | ||
3231 | |||
3232 | // needed to check for dir to make sure about existence of output files | ||
3233 | // but the previous question may have given the user the time to mess up. | ||
3234 | // check the dir again :) | ||
3235 | |||
3236 | if (!(hd24utils::dirExists(projectdir->value()))) | ||
3237 | { | ||
3238 | fl_message("Project directory no longer exists.\\nPlease select another directory and try again."); | ||
3239 | /* TODO: DISABLE/ENABLE JACK BEFORE/AFTER TRANSFER */ | ||
3240 | // jackclient=saveclient; | ||
3241 | \#if (HD24DEBUG==1) | ||
3242 | cout << "project directory deleted" << endl; | ||
3243 | \#endif | ||
3244 | return; | ||
3245 | } | ||
3246 | \#if (HD24DEBUG==1) | ||
3247 | cout << "by calc, tot bytes to transfer=" << totbytestotransfer << endl; | ||
3248 | \#endif | ||
3249 | |||
3250 | deactivate_ui(); | ||
3251 | setstatus("Transferring audio to PC... 0%"); | ||
3252 | time (&starttime); | ||
3253 | int somethingwrong=0; | ||
3254 | for (i=1; i<=numsongs; i++) | ||
3255 | { | ||
3256 | \#if (HD24DEBUG==1) | ||
3257 | cout << "set song" << endl; | ||
3258 | \#endif | ||
3259 | if (transfer_cancel!=0) | ||
3260 | { | ||
3261 | \#if (HD24DEBUG==1) | ||
3262 | cout << "transfer cancelled by user." << endl; | ||
3263 | \#endif | ||
3264 | break; | ||
3265 | } | ||
3266 | |||
3267 | if (multisong) | ||
3268 | { | ||
3269 | if (currsong!=NULL) { | ||
3270 | delete currsong; | ||
3271 | currsong=NULL; | ||
3272 | } | ||
3273 | currsong=currproj->getsong(i); | ||
3274 | } | ||
3275 | transeng->sourcesong(currsong); | ||
3276 | if (currsong==NULL) | ||
3277 | { | ||
3278 | \#if (HD24DEBUG==1) | ||
3279 | cout << "currsong=null, nothing to transfer" << endl; | ||
3280 | \#endif | ||
3281 | continue; | ||
3282 | } | ||
3283 | \#if (HD24DEBUG==1) | ||
3284 | cout << "calling ftransfer with "; | ||
3285 | cout << "sonnum=" << i; | ||
3286 | cout << ", numsongs=" << numsongs; | ||
3287 | cout << ", totlen(bytes)=" << totbytestotransfer; | ||
3288 | cout << ", bytestransferred=" << bytestransferred; | ||
3289 | cout << ", wantsplit=" << wantsplit << endl; | ||
3290 | \#endif | ||
3291 | |||
3292 | transeng->prepare_transfer_to_pc(i,numsongs,totbytestotransfer,bytestransferred,wantsplit,(havedoublesongname==1)?(i):(0)); | ||
3293 | __sint64 currtransferred=transeng->transfer_to_pc(); | ||
3294 | if (currtransferred==0) | ||
3295 | { | ||
3296 | somethingwrong=1; | ||
3297 | break; | ||
3298 | } | ||
3299 | bytestransferred+=currtransferred; | ||
3300 | |||
3301 | if (multisong) | ||
3302 | { | ||
3303 | delete currsong; | ||
3304 | currsong=NULL; | ||
3305 | } | ||
3306 | |||
3307 | } | ||
3308 | |||
3309 | |||
3310 | if (multisong) | ||
3311 | { | ||
3312 | if (currsong!=NULL) | ||
3313 | { | ||
3314 | delete currsong; | ||
3315 | currsong=NULL; | ||
3316 | } | ||
3317 | } | ||
3318 | |||
3319 | /* TODO: DISABLE/ENABLE JACK BEFORE/AFTER TRANSFER */ | ||
3320 | //jackclient=saveclient; | ||
3321 | if (somethingwrong==1) | ||
3322 | { | ||
3323 | activate_ui(); | ||
3324 | if (transeng->lasterror()!=NULL) | ||
3325 | { | ||
3326 | |||
3327 | setstatus(transeng->lasterror()->c_str()); | ||
3328 | } | ||
3329 | else | ||
3330 | { | ||
3331 | setstatus((const char*)&"Unexpected error transferring files."); | ||
3332 | } | ||
3333 | stop_transfer->hide(); | ||
3334 | return; | ||
3335 | } | ||
3336 | |||
3337 | time (&endtime); | ||
3338 | dif=difftime(endtime,starttime); | ||
3339 | //__uint32 subsecs=(__uint32)(100*(dif-floor(dif))); | ||
3340 | dif=floor(dif); | ||
3341 | __uint32 minutes=((__uint32)dif-((__uint32)dif%60))/60; | ||
3342 | __uint32 seconds=((__uint32)dif%60); | ||
3343 | |||
3344 | string minsec="Ready. Transfer time: "; | ||
3345 | if (transfer_cancel==1) | ||
3346 | { | ||
3347 | minsec="Transfer cancelled. Elapsed transfer time: "; | ||
3348 | } | ||
3349 | transfer_cancel=0; | ||
3350 | string* strmins=Convert::int2str(minutes,2,"0"); | ||
3351 | minsec+=*strmins; | ||
3352 | delete (strmins); | ||
3353 | minsec+=":"; | ||
3354 | string* strsecs=Convert::int2str(seconds,2,"0"); | ||
3355 | minsec+=*strsecs; | ||
3356 | delete(strsecs); | ||
3357 | |||
3358 | if (dif>=1) | ||
3359 | { | ||
3360 | __uint32 kbps=(__uint32)(((bytestransferred)/1024)/dif); | ||
3361 | |||
3362 | minsec+=" ("; | ||
3363 | string* strkbps=Convert::int2str(kbps); | ||
3364 | minsec+=*strkbps; | ||
3365 | minsec+=" kB/sec)"; | ||
3366 | delete(strkbps); | ||
3367 | } | ||
3368 | activate_ui(); | ||
3369 | setstatus(minsec.c_str()); | ||
3370 | stop_transfer->hide();} | ||
3371 | xywh {530 480 70 20} labelsize 12 align 16 | ||
3372 | code0 {o->label("Transfer");} | ||
3373 | } | ||
3374 | Fl_Button {} { | ||
3375 | label {Browse...} | ||
3376 | callback {Fl_Native_File_Chooser chooser; | ||
3377 | chooser.title("Select project directory"); | ||
3378 | chooser.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY); | ||
3379 | chooser.options(Fl_Native_File_Chooser::NEW_FOLDER); | ||
3380 | chooser.filter(""); | ||
3381 | |||
3382 | string currdir=""; | ||
3383 | currdir+=projectdir->value(); | ||
3384 | |||
3385 | chooser.directory(currdir.c_str()); | ||
3386 | switch (chooser.show()) { | ||
3387 | case -1: break; //error | ||
3388 | case 1: break; //cancel | ||
3389 | default: | ||
3390 | if (chooser.filename()) { | ||
3391 | projectdir->value(chooser.filename()); | ||
3392 | hd24utils::setlastdir("projdir",chooser.filename()); | ||
3393 | } | ||
3394 | |||
3395 | break; | ||
3396 | }} | ||
3397 | xywh {505 175 85 20} labelsize 12 align 16 | ||
3398 | } | ||
3399 | Fl_Input projectdir { | ||
3400 | label {Project dir:} | ||
3401 | callback {/* callback when release: add a | ||
3402 | (back)slash to the end of the | ||
3403 | pathname if one is not present. */ | ||
3404 | |||
3405 | \#ifdef WINDOWS | ||
3406 | \#define MYSLASH '\\\\' | ||
3407 | \#else | ||
3408 | \#define MYSLASH '/' | ||
3409 | \#endif | ||
3410 | char* x=(char*)projectdir->value(); | ||
3411 | if (strlen(x)==0) { | ||
3412 | x[0]=MYSLASH; | ||
3413 | x[1]=0; | ||
3414 | } else { | ||
3415 | int q=strlen(x); | ||
3416 | if (x[q-1]!=MYSLASH) { | ||
3417 | x[q]=MYSLASH; | ||
3418 | x[q+1]=0; | ||
3419 | } | ||
3420 | } | ||
3421 | projectdir->value(x); | ||
3422 | hd24utils::setlastdir("projdir",projectdir->value());} | ||
3423 | xywh {85 175 415 20} labelsize 12 textsize 12 | ||
3424 | code0 {getlastprojdir(o);} | ||
3425 | code1 {/*o->clear_visible_focus();*/} | ||
3426 | } | ||
3427 | Fl_Output fromtime { | ||
3428 | label {From:} | ||
3429 | xywh {265 115 105 20} labelsize 12 textsize 12 | ||
3430 | code0 {o->clear_visible_focus();} | ||
3431 | } | ||
3432 | Fl_Output totime { | ||
3433 | label {To:} | ||
3434 | xywh {395 115 105 20} labelsize 12 textsize 12 | ||
3435 | code0 {o->clear_visible_focus();} | ||
3436 | } | ||
3437 | Fl_Button fromto { | ||
3438 | label {Range...} | ||
3439 | callback {if (currsong==NULL) return; | ||
3440 | dialog_fromto* ui_fromto; | ||
3441 | ui_fromto=new dialog_fromto; | ||
3442 | |||
3443 | Fl_Window *win=ui_fromto->make_window(currsong); | ||
3444 | populate_locatepoints(currsong,ui_fromto->fromloc); | ||
3445 | populate_locatepoints(currsong,ui_fromto->toloc); | ||
3446 | ui_fromto->fromloc->value(choice_startloc); | ||
3447 | ui_fromto->toloc->value(choice_endloc); | ||
3448 | win->end(); | ||
3449 | win->show(); | ||
3450 | |||
3451 | while (win->visible()) { Fl::wait(); } | ||
3452 | |||
3453 | /* Dialog has closed, read the results */ | ||
3454 | //if (ui_fromto->buttonclicked==0) | ||
3455 | //{ fl_message("No OK nor Cancel clicked"); } | ||
3456 | if (ui_fromto->buttonclicked==1) | ||
3457 | { | ||
3458 | // OK clicked | ||
3459 | choice_startloc=ui_fromto->choice_startloc; | ||
3460 | choice_endloc=ui_fromto->choice_endloc; | ||
3461 | update_fromto(); | ||
3462 | } | ||
3463 | //if (ui_fromto->buttonclicked==2) | ||
3464 | //{ fl_message("Cancel clicked"); } | ||
3465 | delete ui_fromto;} | ||
3466 | xywh {505 115 85 20} labelsize 12 align 16 | ||
3467 | } | ||
3468 | Fl_Choice fileformat { | ||
3469 | label {File format:} open | ||
3470 | xywh {85 200 160 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
3471 | } {} | ||
3472 | Fl_Check_Button autosplit { | ||
3473 | label {Automatically limit size of exported files} | ||
3474 | callback {if (autosplit->value()==1) { | ||
3475 | sizelimitdropdown->activate(); | ||
3476 | |||
3477 | if (sizelimitdropdown->value()==6) { | ||
3478 | sizelimit->activate(); | ||
3479 | } else { | ||
3480 | sizelimit->deactivate(); | ||
3481 | } | ||
3482 | } else { | ||
3483 | sizelimitdropdown->deactivate(); | ||
3484 | sizelimit->deactivate(); | ||
3485 | }} | ||
3486 | xywh {10 265 20 20} box FLAT_BOX down_box DOWN_BOX value 1 color 52 labelsize 12 align 8 | ||
3487 | } | ||
3488 | Fl_Input sizelimit { | ||
3489 | label bytes | ||
3490 | xywh {425 290 120 20} labelsize 12 align 8 textsize 12 | ||
3491 | code0 {long long x=1073741824LL; string* sval=Convert::int64tostr(x); o->value(sval->c_str()); delete sval; o->deactivate();} | ||
3492 | code1 {o->maximum_size(17);} | ||
3493 | } | ||
3494 | Fl_Box {} { | ||
3495 | label {Transfer target:} | ||
3496 | xywh {10 153 305 17} box FLAT_BOX color 52 labelfont 1 labelsize 12 align 20 | ||
3497 | } | ||
3498 | Fl_Box {} { | ||
3499 | label {Transfer options:} | ||
3500 | xywh {10 243 305 17} box FLAT_BOX color 52 labelfont 1 labelsize 12 align 20 | ||
3501 | } | ||
3502 | Fl_Box {} { | ||
3503 | label {Note: The actual file size will be a rough approximation of the requested split size.} | ||
3504 | xywh {30 318 550 17} box FLAT_BOX color 52 labelfont 2 labelsize 12 align 20 | ||
3505 | } | ||
3506 | Fl_Check_Button customrate { | ||
3507 | label {Stamp files with a custom sample rate} | ||
3508 | callback {if (customrate->value()==1) { | ||
3509 | ratechoice->activate(); | ||
3510 | if (ratechoice->value()==4) { | ||
3511 | stamprate->activate(); | ||
3512 | } else { | ||
3513 | stamprate->deactivate(); | ||
3514 | } | ||
3515 | } else { | ||
3516 | ratechoice->deactivate(); | ||
3517 | stamprate->deactivate(); | ||
3518 | }} | ||
3519 | xywh {10 345 20 20} box FLAT_BOX down_box DOWN_BOX color 52 labelsize 12 align 8 | ||
3520 | } | ||
3521 | Fl_Choice ratechoice { | ||
3522 | label {Sample rate:} open | ||
3523 | xywh {105 370 295 20} down_box BORDER_BOX labelsize 12 textsize 12 deactivate | ||
3524 | code0 {o->value(1);} | ||
3525 | } { | ||
3526 | MenuItem {} { | ||
3527 | label {44100 Hz} | ||
3528 | callback {long long x=44100LL; | ||
3529 | string* sval=Convert::int64tostr(x); | ||
3530 | stamprate->value(sval->c_str()); | ||
3531 | delete sval; | ||
3532 | stamprate->deactivate();} | ||
3533 | xywh {25 25 36 21} labelsize 12 | ||
3534 | } | ||
3535 | MenuItem {} { | ||
3536 | label {48000 Hz} | ||
3537 | callback {long long x=48000LL; | ||
3538 | string* sval=Convert::int64tostr(x); | ||
3539 | stamprate->value(sval->c_str()); | ||
3540 | delete sval; | ||
3541 | stamprate->deactivate();} | ||
3542 | xywh {35 35 36 21} labelsize 12 | ||
3543 | } | ||
3544 | MenuItem {} { | ||
3545 | label {88200 Hz} | ||
3546 | callback {long long x=88200LL; | ||
3547 | string* sval=Convert::int64tostr(x); | ||
3548 | stamprate->value(sval->c_str()); | ||
3549 | delete sval; | ||
3550 | stamprate->deactivate();} | ||
3551 | xywh {45 45 36 21} labelsize 12 | ||
3552 | } | ||
3553 | MenuItem {} { | ||
3554 | label {96000 Hz} | ||
3555 | callback {long long x=96000LL; | ||
3556 | string* sval=Convert::int64tostr(x); | ||
3557 | stamprate->value(sval->c_str()); | ||
3558 | delete sval; | ||
3559 | stamprate->deactivate();} | ||
3560 | xywh {55 55 36 21} labelsize 12 | ||
3561 | } | ||
3562 | MenuItem {} { | ||
3563 | label {User defined, specify -->} | ||
3564 | callback {stamprate->activate();} | ||
3565 | xywh {85 85 36 21} labelsize 12 | ||
3566 | } | ||
3567 | } | ||
3568 | Fl_Input stamprate { | ||
3569 | label Hz | ||
3570 | xywh {425 370 120 20} labelsize 12 align 8 textsize 12 deactivate | ||
3571 | code0 {long long x=48000; string* sval=Convert::int64tostr(x); o->value(sval->c_str()); delete sval; o->deactivate();} | ||
3572 | code1 {o->maximum_size(5);} | ||
3573 | } | ||
3574 | Fl_Choice sizelimitdropdown { | ||
3575 | label {Split every:} open | ||
3576 | tooltip 1 xywh {105 290 295 20} down_box BORDER_BOX labelsize 12 textsize 12 | ||
3577 | code0 {o->value(2);} | ||
3578 | } { | ||
3579 | MenuItem {} { | ||
3580 | label {650 MB (74 minute CD)} | ||
3581 | callback {long long x=650000000LL; | ||
3582 | string* sval=Convert::int64tostr(x); | ||
3583 | sizelimit->value(sval->c_str()); | ||
3584 | delete sval; | ||
3585 | sizelimit->deactivate();} | ||
3586 | xywh {20 20 36 21} labelsize 12 | ||
3587 | } | ||
3588 | MenuItem {} { | ||
3589 | label {700 MB (80 minute CD)} | ||
3590 | callback {long long x=700000000LL; | ||
3591 | string* sval=Convert::int64tostr(x); | ||
3592 | sizelimit->value(sval->c_str()); | ||
3593 | delete sval; | ||
3594 | sizelimit->deactivate();} | ||
3595 | xywh {30 30 36 21} labelsize 12 | ||
3596 | } | ||
3597 | MenuItem {} { | ||
3598 | label {1 GiB (Recommended for wave editors)} | ||
3599 | callback {long long x=1073741824LL; | ||
3600 | string* sval=Convert::int64tostr(x); | ||
3601 | sizelimit->value(sval->c_str()); | ||
3602 | delete sval; | ||
3603 | sizelimit->deactivate();} | ||
3604 | xywh {40 40 36 21} labelsize 12 | ||
3605 | } | ||
3606 | MenuItem {} { | ||
3607 | label {2 GiB (Max. legal WAV size)} | ||
3608 | callback {long long x=2147483648LL; | ||
3609 | string* sval=Convert::int64tostr(x); | ||
3610 | sizelimit->value(sval->c_str()); | ||
3611 | delete sval; | ||
3612 | sizelimit->deactivate();} | ||
3613 | xywh {50 50 36 21} labelsize 12 | ||
3614 | } | ||
3615 | MenuItem {} { | ||
3616 | label {4 GiB (Max. 32-bit limit)} | ||
3617 | callback {long long x=4294967296LL; | ||
3618 | string* sval=Convert::int64tostr(x); | ||
3619 | sizelimit->value(sval->c_str()); | ||
3620 | delete sval; | ||
3621 | sizelimit->deactivate();} | ||
3622 | xywh {60 60 36 21} labelsize 12 | ||
3623 | } | ||
3624 | MenuItem {} { | ||
3625 | label {4.7 GB (DVD size)} | ||
3626 | callback {long long x=4700000000LL; | ||
3627 | string* sval=Convert::int64tostr(x); | ||
3628 | sizelimit->value(sval->c_str()); | ||
3629 | delete sval; | ||
3630 | sizelimit->deactivate();} | ||
3631 | xywh {70 70 36 21} labelsize 12 | ||
3632 | } | ||
3633 | MenuItem {} { | ||
3634 | label {User defined, specify -->} | ||
3635 | callback {sizelimit->activate();} | ||
3636 | xywh {80 80 36 21} labelsize 12 | ||
3637 | } | ||
3638 | } | ||
3639 | Fl_Check_Button transfersource_mixleft { | ||
3640 | label {Mixer Left} | ||
3641 | callback {saverestoretrackselection(o);} | ||
3642 | xywh {85 115 20 20} down_box DOWN_BOX labelsize 12 align 4 | ||
3643 | } | ||
3644 | Fl_Check_Button transfersource_mixright { | ||
3645 | label Right | ||
3646 | callback {saverestoretrackselection(o);} | ||
3647 | xywh {105 115 20 20} down_box DOWN_BOX labelsize 12 align 8 | ||
3648 | } | ||
3649 | Fl_Group batch_stuff { | ||
3650 | label {batch stuff } open | ||
3651 | xywh {5 390 600 115} align 16 hide deactivate | ||
3652 | } { | ||
3653 | Fl_Box {} { | ||
3654 | label {Batch transfer list:} | ||
3655 | xywh {10 393 305 17} box FLAT_BOX color 52 labelfont 1 labelsize 12 align 20 deactivate | ||
3656 | } | ||
3657 | Fl_Output transfer_list { | ||
3658 | xywh {10 410 515 90} type Multiline labelsize 12 textsize 12 deactivate | ||
3659 | code0 {o->clear_visible_focus();} | ||
3660 | } | ||
3661 | Fl_Button button_addtobatch { | ||
3662 | label {To Batch} | ||
3663 | xywh {530 410 70 20} labelsize 12 align 16 deactivate | ||
3664 | } | ||
3665 | Fl_Button button_removefrombatch { | ||
3666 | label Remove | ||
3667 | xywh {530 430 70 20} labelsize 12 align 16 deactivate | ||
3668 | } | ||
3669 | } | ||
3670 | Fl_Output transfersource { | ||
3671 | label {Transfer source:} | ||
3672 | xywh {127 57 458 20} box NO_BOX labelfont 1 labelsize 12 textsize 12 | ||
3673 | } | ||
3674 | Fl_Button {} { | ||
3675 | label {?} | ||
3676 | callback {fl_message("This option allows you to limit the size of exported files. \\n" | ||
3677 | "In the dropdown box, the following units are used:\\n\\n" | ||
3678 | "MB - Megabyte, 1000x1000 bytes\\n" | ||
3679 | "GB - Gigabyte, 1000x1000x1000 bytes\\n" | ||
3680 | "GiB - Binary Gigabyte or Gibibyte, 1024x1024x1024 bytes\\n\\n" | ||
3681 | "In any situation, the actual byte count is displayed on the right.");} | ||
3682 | tooltip {Click here for an explanation about file splitting.} xywh {400 290 20 20} box FLAT_BOX down_box FLAT_BOX color 15 selection_color 15 labelfont 1 labelsize 11 labelcolor 7 | ||
3683 | } | ||
3684 | Fl_Button {} { | ||
3685 | label {?} | ||
3686 | callback {fl_message("Stamping files with another sample rates allows you \\n" | ||
3687 | "to export files with a sample rate that differs from the sample \\n" | ||
3688 | "rate at which the song was recorded. When using this option, \\n" | ||
3689 | "note that no resampling takes place; both the pitch and playback \\n" | ||
3690 | "speed will change compared to the original sample rate. ");} | ||
3691 | tooltip {Click here for an explanation about sample rate stamping} xywh {400 370 20 20} box FLAT_BOX down_box FLAT_BOX color 15 selection_color 15 labelfont 1 labelsize 11 labelcolor 7 | ||
3692 | } | ||
3693 | } | ||
3694 | Fl_Group tab_tohd24 { | ||
3695 | label {Copy to HD24} open | ||
3696 | xywh {0 45 605 461} color 52 labelfont 1 labelsize 12 | ||
3697 | } { | ||
3698 | Fl_Button button_transfertohd24 { | ||
3699 | label Transfer | ||
3700 | callback {recorder->control->button_stop_call(); //stop transport | ||
3701 | bool have_smpte=false; | ||
3702 | if (currproj==NULL) | ||
3703 | { | ||
3704 | fl_message("No project selected, nothing to do!\\nSelect a project on the Project/Song tab and try again."); | ||
3705 | return; | ||
3706 | } | ||
3707 | if (currsong==NULL) | ||
3708 | { | ||
3709 | fl_message("No song selected, nothing to do!\\nSelect a song on the Project/Song tab and try again."); | ||
3710 | return; | ||
3711 | } | ||
3712 | |||
3713 | int havefiles=0; | ||
3714 | for (unsigned int ch=1;ch<=currsong->logical_channels();ch++) { | ||
3715 | |||
3716 | if (strlen(filename[ch-1]->value())>0) { | ||
3717 | // track has a file selected | ||
3718 | havefiles=1; | ||
3719 | currsong->trackarmed(ch,true); | ||
3720 | continue; | ||
3721 | } | ||
3722 | int action=((Fl_Choice*)(trackaction[ch-1]))->value(); | ||
3723 | if (action==0) { /* 0=ERASE */ | ||
3724 | // track action says 'erase' | ||
3725 | havefiles=1; | ||
3726 | currsong->trackarmed(ch,true); | ||
3727 | continue; | ||
3728 | } | ||
3729 | if (action==1) { /* 1=SMPTE */ | ||
3730 | // track action says 'stripe with SMPTE/LTC' | ||
3731 | havefiles=1; | ||
3732 | have_smpte=true; | ||
3733 | currsong->trackarmed(ch,true); | ||
3734 | continue; | ||
3735 | } | ||
3736 | // no file, no timecode stripe and no erase, keep track. | ||
3737 | currsong->trackarmed(ch,false); | ||
3738 | |||
3739 | } | ||
3740 | if (havefiles==0) { | ||
3741 | fl_message( | ||
3742 | "To transfer files to the HD24, load one or more files.\\n" | ||
3743 | "Each file will be assigned to an empty track slot.\\n\\n" | ||
3744 | "Before transferring, you will be able to rearrange the\\n" | ||
3745 | "order of the tracks by clicking on one or more tracks\\n" | ||
3746 | "and clicking the up or down arrow buttons.\\n\\n" | ||
3747 | "When a track slot is empty, the existing track will be\\n" | ||
3748 | "preserved, unless 'Erase' or 'SMPTE' is selected on \\n" | ||
3749 | "the right of the track.\\n\\n" | ||
3750 | "When a file to transfer contains multiple tracks, you\\n" | ||
3751 | "can choose to mixdown the file to mono (the default), \\n" | ||
3752 | "or you can select the track that you want to transfer \\n" | ||
3753 | "to the HD24 drive." | ||
3754 | ); | ||
3755 | for (unsigned int ch=1;ch<=currsong->logical_channels();ch++) { | ||
3756 | currsong->trackarmed(ch,false); | ||
3757 | } | ||
3758 | return; | ||
3759 | } | ||
3760 | if (currsong->iswriteprotected()) | ||
3761 | { | ||
3762 | fl_message("The song is write protected."); | ||
3763 | for (unsigned int ch=1;ch<=currsong->logical_channels();ch++) { | ||
3764 | currsong->trackarmed(ch,false); | ||
3765 | } | ||
3766 | return; | ||
3767 | } | ||
3768 | // ask ARE YOU SURE???? | ||
3769 | bool sure=confirm("Are you sure you want to overwrite the existing audio?"); | ||
3770 | if (!sure) return; | ||
3771 | |||
3772 | // check if all files still exist | ||
3773 | |||
3774 | int filemissing=0; | ||
3775 | for (unsigned int misscheck=1;misscheck<=currsong->logical_channels();misscheck++) { | ||
3776 | if (strlen(filename[misscheck-1]->value())==0) continue; | ||
3777 | if (!(hd24utils::fileExists(filename[misscheck-1]->value()))) | ||
3778 | { | ||
3779 | filemissing=1; | ||
3780 | break; | ||
3781 | } | ||
3782 | } | ||
3783 | |||
3784 | if (filemissing==1) { | ||
3785 | fl_message("One or more files no longer exist. \\nPlease clear and reload the files, then try again."); | ||
3786 | return; | ||
3787 | } | ||
3788 | // end of checking if all files still exist | ||
3789 | transeng->targetsong(currsong); | ||
3790 | transeng->soundfile=soundfile; | ||
3791 | for (unsigned int filenum=1;filenum<=currsong->logical_channels();filenum++) | ||
3792 | { | ||
3793 | transeng->sourcefilename(filenum,filename[filenum-1]->value()); | ||
3794 | transeng->trackaction(filenum,((Fl_Choice*)(trackaction[filenum-1]))->value()); | ||
3795 | } | ||
3796 | transeng->transfer_to_hd24(); | ||
3797 | stop_transfer->hide(); | ||
3798 | if (transeng->lasterror()!=NULL) | ||
3799 | { | ||
3800 | if (transeng->lasterror()->c_str()!=NULL) | ||
3801 | { | ||
3802 | setstatus(transeng->lasterror()->c_str()); | ||
3803 | } | ||
3804 | else | ||
3805 | { | ||
3806 | setstatus("Done. No error messages."); | ||
3807 | } | ||
3808 | } else { | ||
3809 | setstatus("Done."); | ||
3810 | } | ||
3811 | ui_refresh("tohd24_done"); | ||
3812 | activate_ui(); | ||
3813 | fl_check();} selected | ||
3814 | xywh {530 480 70 20} labelsize 12 | ||
3815 | } | ||
3816 | Fl_Output filename1 { | ||
3817 | label {01 } | ||
3818 | callback {selectfilename(1);} | ||
3819 | xywh {40 50 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3820 | code0 {filename[0]=o;} | ||
3821 | } | ||
3822 | Fl_Output filename2 { | ||
3823 | label {02 } | ||
3824 | callback {selectfilename(2);} | ||
3825 | xywh {40 69 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3826 | code0 {filename[1]=o;} | ||
3827 | } | ||
3828 | Fl_Output filename3 { | ||
3829 | label {03 } | ||
3830 | callback {selectfilename(3);} | ||
3831 | xywh {40 88 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3832 | code0 {filename[2]=o;} | ||
3833 | } | ||
3834 | Fl_Output filename4 { | ||
3835 | label {04 } | ||
3836 | callback {selectfilename(4);} | ||
3837 | xywh {40 107 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3838 | code0 {filename[3]=o;} | ||
3839 | } | ||
3840 | Fl_Output filename5 { | ||
3841 | label {05 } | ||
3842 | callback {selectfilename(5);} | ||
3843 | xywh {40 126 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3844 | code0 {filename[4]=o;} | ||
3845 | } | ||
3846 | Fl_Output filename6 { | ||
3847 | label {06 } | ||
3848 | callback {selectfilename(6);} | ||
3849 | xywh {40 145 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3850 | code0 {filename[5]=o;} | ||
3851 | } | ||
3852 | Fl_Output filename7 { | ||
3853 | label {07 } | ||
3854 | callback {selectfilename(7);} | ||
3855 | xywh {40 164 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3856 | code0 {filename[6]=o;} | ||
3857 | } | ||
3858 | Fl_Output filename8 { | ||
3859 | label {08 } | ||
3860 | callback {selectfilename(8);} | ||
3861 | xywh {40 183 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3862 | code0 {filename[7]=o;} | ||
3863 | } | ||
3864 | Fl_Output filename9 { | ||
3865 | label {09 } | ||
3866 | callback {selectfilename(9);} | ||
3867 | xywh {40 202 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3868 | code0 {filename[8]=o;} | ||
3869 | } | ||
3870 | Fl_Output filename10 { | ||
3871 | label {10 } | ||
3872 | callback {selectfilename(10);} | ||
3873 | xywh {40 221 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3874 | code0 {filename[9]=o;} | ||
3875 | } | ||
3876 | Fl_Output filename11 { | ||
3877 | label {11 } | ||
3878 | callback {selectfilename(11);} | ||
3879 | xywh {40 240 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3880 | code0 {filename[10]=o;} | ||
3881 | } | ||
3882 | Fl_Output filename12 { | ||
3883 | label {12 } | ||
3884 | callback {selectfilename(12);} | ||
3885 | xywh {40 259 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3886 | code0 {filename[11]=o;} | ||
3887 | } | ||
3888 | Fl_Output filename13 { | ||
3889 | label {13 } | ||
3890 | callback {selectfilename(13);} | ||
3891 | xywh {40 278 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3892 | code0 {filename[12]=o;} | ||
3893 | } | ||
3894 | Fl_Output filename14 { | ||
3895 | label {14 } | ||
3896 | callback {selectfilename(14);} | ||
3897 | xywh {40 297 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3898 | code0 {filename[13]=o;} | ||
3899 | } | ||
3900 | Fl_Output filename15 { | ||
3901 | label {15 } | ||
3902 | callback {selectfilename(15);} | ||
3903 | xywh {40 316 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3904 | code0 {filename[14]=o;} | ||
3905 | } | ||
3906 | Fl_Output filename16 { | ||
3907 | label {16 } | ||
3908 | callback {selectfilename(16);} | ||
3909 | xywh {40 335 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3910 | code0 {filename[15]=o;} | ||
3911 | } | ||
3912 | Fl_Output filename17 { | ||
3913 | label {17 } | ||
3914 | callback {selectfilename(17);} | ||
3915 | xywh {40 354 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3916 | code0 {filename[16]=o;} | ||
3917 | } | ||
3918 | Fl_Output filename18 { | ||
3919 | label {18 } | ||
3920 | callback {selectfilename(18);} | ||
3921 | xywh {40 373 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3922 | code0 {filename[17]=o;} | ||
3923 | } | ||
3924 | Fl_Output filename19 { | ||
3925 | label {19 } | ||
3926 | callback {selectfilename(19);} | ||
3927 | xywh {40 392 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3928 | code0 {filename[18]=o;} | ||
3929 | } | ||
3930 | Fl_Output filename20 { | ||
3931 | label {20 } | ||
3932 | callback {selectfilename(20);} | ||
3933 | xywh {40 411 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3934 | code0 {filename[19]=o;} | ||
3935 | } | ||
3936 | Fl_Output filename21 { | ||
3937 | label {21 } | ||
3938 | callback {selectfilename(21);} | ||
3939 | xywh {40 430 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3940 | code0 {filename[20]=o;} | ||
3941 | } | ||
3942 | Fl_Output filename22 { | ||
3943 | label {22 } | ||
3944 | callback {selectfilename(22);} | ||
3945 | xywh {40 449 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3946 | code0 {filename[21]=o;} | ||
3947 | } | ||
3948 | Fl_Output filename23 { | ||
3949 | label {23 } | ||
3950 | callback {selectfilename(23);} | ||
3951 | xywh {40 468 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3952 | code0 {filename[22]=o;} | ||
3953 | } | ||
3954 | Fl_Output filename24 { | ||
3955 | label {24 } | ||
3956 | callback {selectfilename(24);} | ||
3957 | xywh {40 487 430 19} labelfont 1 labelsize 12 textsize 12 | ||
3958 | code0 {filename[23]=o;} | ||
3959 | } | ||
3960 | Fl_Repeat_Button button_moveup { | ||
3961 | callback {moveselected(-1);} | ||
3962 | image {images/up.gif} xywh {530 255 70 20} labelsize 12 align 17 | ||
3963 | } | ||
3964 | Fl_Repeat_Button button_movedown { | ||
3965 | callback {moveselected(1);} | ||
3966 | image {images/down.gif} xywh {530 275 70 20} labelsize 12 | ||
3967 | } | ||
3968 | Fl_Button button_load { | ||
3969 | label {Load...} | ||
3970 | callback {if (currsong == NULL) { | ||
3971 | fl_message("No song selected.\\nSelect a song on the Project/Song tab and try again."); | ||
3972 | return; | ||
3973 | return; | ||
3974 | } | ||
3975 | string* audiofiledir=hd24utils::getlastdir("audiofiledir"); | ||
3976 | |||
3977 | Fl_Native_File_Chooser chooser; | ||
3978 | chooser.directory(audiofiledir->c_str()); | ||
3979 | delete audiofiledir; | ||
3980 | chooser.title("Select the files to transfer:\\0"); | ||
3981 | chooser.type(Fl_Native_File_Chooser::BROWSE_MULTI_FILE); | ||
3982 | chooser.filter("Audio files\\t*.{wav,aif}\\0"); | ||
3983 | //chooser.preview(0); | ||
3984 | int tosplitornottosplit=0; | ||
3985 | |||
3986 | switch (chooser.show()) { | ||
3987 | case -1: break; //error | ||
3988 | case 1: break; //cancel | ||
3989 | default: | ||
3990 | if (chooser.filename()) { | ||
3991 | string* cfilename=new string(chooser.filename()); | ||
3992 | |||
3993 | string* fpath=new string(""); | ||
3994 | *fpath+=cfilename->substr(0,strlen(cfilename->c_str())-strlen(fl_filename_name(cfilename->c_str()))); | ||
3995 | hd24utils::setlastdir("audiofiledir",fpath->c_str()); | ||
3996 | delete cfilename; | ||
3997 | for (int n = 0; n < chooser.count(); n++ ) { | ||
3998 | string* cfilename=new string(chooser.filename(n)); | ||
3999 | int currfiletracks=countfiletracks(cfilename->c_str()); | ||
4000 | int totfiletracks=currfiletracks; | ||
4001 | int haveslot=0; | ||
4002 | while (currfiletracks>0) { | ||
4003 | if (totfiletracks>1) { | ||
4004 | if (tosplitornottosplit==0) { | ||
4005 | bool wantsplit= | ||
4006 | confirm("One or more selected files have more than 1 track. Do you wish to split them up?"); | ||
4007 | if (!wantsplit) { | ||
4008 | tosplitornottosplit=1; | ||
4009 | } else { | ||
4010 | tosplitornottosplit=2; | ||
4011 | } | ||
4012 | } | ||
4013 | } | ||
4014 | |||
4015 | haveslot=0; | ||
4016 | for (unsigned int freeslot=0;freeslot<currsong->logical_channels();freeslot++) { | ||
4017 | if (strlen(filename[freeslot]->value())==0) { | ||
4018 | haveslot=1; | ||
4019 | filename[freeslot]->value(chooser.filename(n)); | ||
4020 | // cout << "Clear slot " << freeslot << endl; | ||
4021 | ((Fl_Choice*)(trackaction[freeslot]))->clear(); | ||
4022 | if (tosplitornottosplit>1) { | ||
4023 | populate_trackactionbyfile(freeslot,3+(totfiletracks-currfiletracks)); | ||
4024 | } else { | ||
4025 | populate_trackactionbyfile(freeslot,2); | ||
4026 | } | ||
4027 | break; | ||
4028 | } | ||
4029 | } | ||
4030 | if (haveslot==0) { | ||
4031 | break; | ||
4032 | } | ||
4033 | if (tosplitornottosplit==1) { | ||
4034 | currfiletracks=0; | ||
4035 | } else { | ||
4036 | currfiletracks--; | ||
4037 | } | ||
4038 | } | ||
4039 | delete cfilename; | ||
4040 | if (haveslot==0) { | ||
4041 | fl_message("One or more files could not be assigned to a track slot.\\n" | ||
4042 | "Please clear one or more track slots and try again."); | ||
4043 | break; | ||
4044 | } | ||
4045 | } | ||
4046 | } | ||
4047 | }} | ||
4048 | xywh {530 50 70 20} labelsize 12 | ||
4049 | } | ||
4050 | Fl_Button button_clear { | ||
4051 | label Clear | ||
4052 | callback {for (unsigned int i=0;i<MAXCHANNELS;i++) { | ||
4053 | if (trackselected[i]==1) { | ||
4054 | filename[i]->value(""); | ||
4055 | trackselected[i]=0; | ||
4056 | |||
4057 | } | ||
4058 | }; | ||
4059 | redrawtracks();} | ||
4060 | xywh {530 70 70 20} labelsize 12 | ||
4061 | } | ||
4062 | Fl_Choice trackaction1 {open | ||
4063 | xywh {470 50 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4064 | code0 {this->populate_trackaction(this,o,1);} | ||
4065 | } {} | ||
4066 | Fl_Choice trackaction2 {open | ||
4067 | xywh {470 69 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4068 | code0 {this->populate_trackaction(this,o,2);} | ||
4069 | } {} | ||
4070 | Fl_Choice trackaction3 {open | ||
4071 | xywh {470 88 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4072 | code0 {this->populate_trackaction(this,o,3);} | ||
4073 | } {} | ||
4074 | Fl_Choice trackaction4 {open | ||
4075 | xywh {470 107 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4076 | code0 {this->populate_trackaction(this,o,4);} | ||
4077 | } {} | ||
4078 | Fl_Choice trackaction5 {open | ||
4079 | xywh {470 126 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4080 | code0 {this->populate_trackaction(this,o,5);} | ||
4081 | } {} | ||
4082 | Fl_Choice trackaction6 {open | ||
4083 | xywh {470 145 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4084 | code0 {this->populate_trackaction(this,o,6);} | ||
4085 | } {} | ||
4086 | Fl_Choice trackaction7 {open | ||
4087 | xywh {470 164 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4088 | code0 {this->populate_trackaction(this,o,7);} | ||
4089 | } {} | ||
4090 | Fl_Choice trackaction8 {open | ||
4091 | xywh {470 183 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4092 | code0 {this->populate_trackaction(this,o,8);} | ||
4093 | } {} | ||
4094 | Fl_Choice trackaction9 {open | ||
4095 | xywh {470 202 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4096 | code0 {this->populate_trackaction(this,o,9);} | ||
4097 | } {} | ||
4098 | Fl_Choice trackaction10 {open | ||
4099 | xywh {470 221 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4100 | code0 {this->populate_trackaction(this,o,10);} | ||
4101 | } {} | ||
4102 | Fl_Choice trackaction11 {open | ||
4103 | xywh {470 240 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4104 | code0 {this->populate_trackaction(this,o,11);} | ||
4105 | } {} | ||
4106 | Fl_Choice trackaction12 {open | ||
4107 | xywh {470 259 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4108 | code0 {this->populate_trackaction(this,o,12);} | ||
4109 | } {} | ||
4110 | Fl_Choice trackaction13 {open | ||
4111 | xywh {470 278 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4112 | code0 {this->populate_trackaction(this,o,13);} | ||
4113 | } {} | ||
4114 | Fl_Choice trackaction14 {open | ||
4115 | xywh {470 297 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4116 | code0 {this->populate_trackaction(this,o,14);} | ||
4117 | } {} | ||
4118 | Fl_Choice trackaction15 {open | ||
4119 | xywh {470 316 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4120 | code0 {this->populate_trackaction(this,o,15);} | ||
4121 | } {} | ||
4122 | Fl_Choice trackaction16 {open | ||
4123 | xywh {470 335 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4124 | code0 {this->populate_trackaction(this,o,16);} | ||
4125 | } {} | ||
4126 | Fl_Choice trackaction17 {open | ||
4127 | xywh {470 354 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4128 | code0 {this->populate_trackaction(this,o,17);} | ||
4129 | } {} | ||
4130 | Fl_Choice trackaction18 {open | ||
4131 | xywh {470 373 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4132 | code0 {this->populate_trackaction(this,o,18);} | ||
4133 | } {} | ||
4134 | Fl_Choice trackaction19 {open | ||
4135 | xywh {470 392 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4136 | code0 {this->populate_trackaction(this,o,19);} | ||
4137 | } {} | ||
4138 | Fl_Choice trackaction20 {open | ||
4139 | xywh {470 411 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4140 | code0 {this->populate_trackaction(this,o,20);} | ||
4141 | } {} | ||
4142 | Fl_Choice trackaction21 {open | ||
4143 | xywh {470 430 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4144 | code0 {this->populate_trackaction(this,o,21);} | ||
4145 | } {} | ||
4146 | Fl_Choice trackaction22 {open | ||
4147 | xywh {470 449 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4148 | code0 {this->populate_trackaction(this,o,22);} | ||
4149 | } {} | ||
4150 | Fl_Choice trackaction23 {open | ||
4151 | xywh {470 468 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4152 | code0 {this->populate_trackaction(this,o,23);} | ||
4153 | } {} | ||
4154 | Fl_Choice trackaction24 {open | ||
4155 | xywh {470 487 55 19} down_box BORDER_BOX labelsize 11 textsize 11 | ||
4156 | code0 {this->populate_trackaction(this,o,24);} | ||
4157 | } {} | ||
4158 | Fl_Button button_transfertohd24help { | ||
4159 | label Help | ||
4160 | callback {fl_message( | ||
4161 | "To transfer files to the HD24, load one or more files.\\n" | ||
4162 | "Each file will be assigned to an empty track slot.\\n\\n" | ||
4163 | "Before transferring, you will be able to rearrange the\\n" | ||
4164 | "order of the tracks by clicking on one or more tracks\\n" | ||
4165 | "and clicking the up or down arrow buttons.\\n\\n" | ||
4166 | "When a track slot is empty, the existing track will be\\n" | ||
4167 | "preserved, unless 'Erase' or 'SMPTE' is selected on \\n" | ||
4168 | "the right of the track.\\n\\n" | ||
4169 | "When a file to transfer contains multiple tracks, you\\n" | ||
4170 | "can choose to mixdown the file to mono (the default), \\n" | ||
4171 | "or you can select the track that you want to transfer \\n" | ||
4172 | "to the HD24 drive." | ||
4173 | );} | ||
4174 | xywh {530 455 70 20} labelsize 12 | ||
4175 | } | ||
4176 | } | ||
4177 | } | ||
4178 | Fl_Group uicanvas_futureversions {open | ||
4179 | xywh {5 10 1710 530} hide resizable | ||
4180 | } { | ||
4181 | Fl_Tabs Future_Tabs {open | ||
4182 | xywh {10 35 1595 485} | ||
4183 | } { | ||
4184 | Fl_Group tab_wave { | ||
4185 | label Wave open | ||
4186 | xywh {15 60 595 455} color 52 labelfont 1 labelsize 12 deactivate | ||
4187 | code0 {o->hide();} | ||
4188 | } { | ||
4189 | Fl_Box {} { | ||
4190 | label {A future version of HD24connect may display a wave form here. | ||
4191 | Initially, the purpose of this wave form would be to make it | ||
4192 | easier to select an export range.} | ||
4193 | xywh {15 68 460 222} align 21 | ||
4194 | } | ||
4195 | } | ||
4196 | Fl_Group tab_data { | ||
4197 | label Data open | ||
4198 | xywh {15 60 595 455} color 52 labelfont 1 labelsize 12 hide deactivate | ||
4199 | code0 {o->hide();} | ||
4200 | } { | ||
4201 | Fl_Box {} { | ||
4202 | label {A future version of HD24connect may display a list of data files here. | ||
4203 | Specifically, this would be a list of files associated with the current | ||
4204 | project and/or song. To make this possible, a single song on the | ||
4205 | HD24 drive may be sacrificed as data area. This tab would then contain | ||
4206 | functionality to import/export/list those files, as well as functionality to | ||
4207 | create a data area on the drive. | ||
4208 | Without data area on the HD24 drive itself, songs may still be given a | ||
4209 | unique identifier to allow, for instance, automatically associating a mix | ||
4210 | on the DAW computer with a song. } | ||
4211 | xywh {15 63 505 222} align 21 | ||
4212 | } | ||
4213 | } | ||
4214 | } | ||
4215 | } | ||
4216 | } | ||
4217 | } | ||
4218 | } | ||
4219 | } | ||
4220 | Function {make_cli(hd24fs* p_fsys)} {return_type void | ||
4221 | } { | ||
4222 | code {// make_cli: stands for make commandline interface | ||
4223 | // (intended to allow batch processing and regression testing) | ||
4224 | // both current and default to allow multi drive support | ||
4225 | defaulthd24=p_fsys; | ||
4226 | currenthd24=p_fsys;} {} | ||
4227 | } | ||
4228 | decl {/* ===RECORDER UI stuff ===================================================== */} {} | ||
4229 | Function {readmixer()} {open return_type void | ||
4230 | } { | ||
4231 | code {// set solo status of channel to value | ||
4232 | /* | ||
4233 | for (unsigned int i=0;i<MAXCHANNELS;i++) { | ||
4234 | solobutton[i]->value(mixer->mixerchannel[i]->control->solo()); | ||
4235 | solobutton[i]->redraw(); | ||
4236 | mutebutton[i]->value(mixer->mixerchannel[i]->control->mute()); | ||
4237 | mutebutton[i]->redraw(); | ||
4238 | } | ||
4239 | */} {} | ||
4240 | } | ||
4241 | decl {/* === UTILS ===================================================== */} {} | ||
4242 | Function {getlastprojdir(Fl_Input* o)} {return_type void | ||
4243 | } { | ||
4244 | code {string* projdir=hd24utils::getlastdir("projdir"); | ||
4245 | o->value(projdir->c_str()); | ||
4246 | delete projdir;} {} | ||
4247 | } | ||
4248 | Function {ui_restart()} {open | ||
4249 | } { | ||
4250 | code {//if (isportaudioinitialized()) { | ||
4251 | // portaudio_transport_stop(); | ||
4252 | //} | ||
4253 | if (recorder!=NULL) { | ||
4254 | if (recorder->control!=NULL) { | ||
4255 | recorder->control->button_stop_call(); | ||
4256 | } | ||
4257 | } | ||
4258 | Fl::remove_timeout(poll_callback); | ||
4259 | |||
4260 | recorder->~RecorderUI(); | ||
4261 | delete recorder; | ||
4262 | |||
4263 | Fl_Window * winx=Fl::first_window(); | ||
4264 | if (currproj!=NULL) | ||
4265 | { | ||
4266 | delete currproj; | ||
4267 | currproj=NULL; | ||
4268 | } | ||
4269 | |||
4270 | if (currsong!=NULL) | ||
4271 | { | ||
4272 | delete currsong; | ||
4273 | currsong=NULL; | ||
4274 | } | ||
4275 | |||
4276 | Fl_Window * winy=make_window(currenthd24); | ||
4277 | |||
4278 | winy->position(winx->x(),winx->y()); | ||
4279 | winy->end(); | ||
4280 | winy->show(); | ||
4281 | \#ifdef LINUX | ||
4282 | XSetWMHints(fl_display, fl_xid(winy), XGetWMHints(fl_display, fl_xid(winx))); | ||
4283 | \#endif | ||
4284 | winx->~Fl_Window(); | ||
4285 | delete winx; | ||
4286 | winx=NULL; | ||
4287 | //if (jackmtsample!=NULL) | ||
4288 | //{ | ||
4289 | // free(jackmtsample); | ||
4290 | //}} {} | ||
4291 | } | ||
4292 | Function {loadheaderfile()} {} { | ||
4293 | code {Fl_Native_File_Chooser chooser; | ||
4294 | chooser.title("Select header file\\0"); | ||
4295 | chooser.filter("Drive Images\\t*.{img,bin,h24,hd24}\\0"); | ||
4296 | chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); | ||
4297 | |||
4298 | string* headerdir=hd24utils::getlastdir("headerdir"); | ||
4299 | chooser.directory(headerdir->c_str()); | ||
4300 | delete headerdir; | ||
4301 | switch (chooser.show()) { | ||
4302 | case -1: break; //error | ||
4303 | case 1: break; //cancel | ||
4304 | default: | ||
4305 | if (chooser.filename()) { | ||
4306 | if (!(currenthd24->useheaderfile (chooser.filename()))) { | ||
4307 | fl_message("Couldn't load headerfile. Possible causes: \\n- Most likely you haven't selected a device or drive image yet.\\n- Maybe you have no read access to the file."); | ||
4308 | return; | ||
4309 | } | ||
4310 | string* strfile=new string(chooser.filename()); | ||
4311 | string* fpath=new string(""); | ||
4312 | *fpath+=strfile->substr(0,strlen(strfile->c_str())-strlen(fl_filename_name(strfile->c_str()))); | ||
4313 | hd24utils::setlastdir("headerdir",fpath->c_str()); | ||
4314 | ui_restart(); | ||
4315 | return; | ||
4316 | } | ||
4317 | break; | ||
4318 | }} {} | ||
4319 | } | ||
4320 | Function {anyfilesexist(hd24song* thesong)} {return_type bool | ||
4321 | } { | ||
4322 | code {bool anyexist=false; | ||
4323 | |||
4324 | struct stat fi; | ||
4325 | __uint32 channels=thesong->logical_channels(); | ||
4326 | for (unsigned int q=0; q<100; q++) | ||
4327 | { | ||
4328 | for (unsigned int handle=0;handle<channels;handle++) | ||
4329 | { | ||
4330 | if (track[handle]->value()==0) { | ||
4331 | // channel not selected for export | ||
4332 | continue; | ||
4333 | } | ||
4334 | string* fname=transeng->generate_filename(handle,0,q); | ||
4335 | \#if (HD24DEBUG==1) | ||
4336 | cout << "check if file exists:" << *fname << endl; | ||
4337 | \#endif | ||
4338 | if ((stat (fname->c_str(), &fi) != -1) && ((fi.st_mode & S_IFDIR) == 0)) { | ||
4339 | anyexist=true; | ||
4340 | \#if (HD24DEBUG==1) | ||
4341 | cout << "yes, exists" << *fname << endl; | ||
4342 | \#endif | ||
4343 | delete fname; | ||
4344 | break; | ||
4345 | } | ||
4346 | |||
4347 | fname=transeng->generate_filename(handle,1,q); | ||
4348 | \#if (HD24DEBUG==1) | ||
4349 | cout << "check if file exists:" << *fname << endl; | ||
4350 | \#endif | ||
4351 | if ((stat (fname->c_str(), &fi) != -1) && ((fi.st_mode & S_IFDIR) == 0)) { | ||
4352 | anyexist=true; | ||
4353 | \#if (HD24DEBUG==1) | ||
4354 | cout << "yes, exists" << *fname << endl; | ||
4355 | \#endif | ||
4356 | delete fname; | ||
4357 | break; | ||
4358 | } | ||
4359 | \#if (HD24DEBUG==1) | ||
4360 | cout << "no, doesnt exist" << endl; | ||
4361 | \#endif | ||
4362 | |||
4363 | delete fname; | ||
4364 | } | ||
4365 | if (anyexist==true) break; | ||
4366 | } | ||
4367 | return anyexist;} {} | ||
4368 | } | ||
4369 | Function {fl_check()} {open return_type void | ||
4370 | } { | ||
4371 | code {refresh(stop_transfer); | ||
4372 | refresh(statusmsg); | ||
4373 | Fl::check();} {} | ||
4374 | } | ||
4375 | decl {bool mustdisplaytimer;} {public | ||
4376 | } | ||
4377 | decl {bool polling;} {public | ||
4378 | } | ||
4379 | decl {Fl_Text_Buffer* catalogbuffer;} {public | ||
4380 | } | ||
4381 | Function {HD24UserInterface(int argc,char** argv,char* absprogpath)} {open | ||
4382 | } { | ||
4383 | code {control=new HD24control(); | ||
4384 | control->parentui(this); | ||
4385 | control->ready(0); | ||
4386 | /*currpeakmode=0; | ||
4387 | for (unsigned int i=0;i<MAXCHANNELS;i++) { trackpeak[i]=0; } */ | ||
4388 | catalogbuffer=NULL; | ||
4389 | portaudio=new PortAudioWrapper(absprogpath); | ||
4390 | soundfile=new SoundFileWrapper(absprogpath); | ||
4391 | libjack=new JackWrapper(absprogpath); | ||
4392 | this->recorder=NULL; // will be initialized by make_window code | ||
4393 | this->transeng=new hd24transferengine();} {} | ||
4394 | } | ||
4395 | Function {~HD24UserInterface()} {open | ||
4396 | } { | ||
4397 | code {if (control!=NULL) delete control; | ||
4398 | if (portaudio!=NULL) delete portaudio; | ||
4399 | if (soundfile!=NULL) delete soundfile; | ||
4400 | if (libjack!=NULL) delete libjack; | ||
4401 | if (currsong!=NULL) delete currsong; | ||
4402 | if (currproj!=NULL) delete currproj; | ||
4403 | if (currenthd24==defaulthd24) | ||
4404 | { | ||
4405 | if (currenthd24!=NULL) delete currenthd24; | ||
4406 | } else { | ||
4407 | if (currenthd24!=NULL) delete currenthd24; | ||
4408 | if (defaulthd24!=NULL) delete defaulthd24; | ||
4409 | } | ||
4410 | if (transeng!=NULL) | ||
4411 | { | ||
4412 | delete transeng; | ||
4413 | transeng=NULL; | ||
4414 | }} {} | ||
4415 | } | ||
4416 | Function {confirm(const char* question)} {open return_type bool | ||
4417 | } { | ||
4418 | code {int result=fl_choice("%s","No","Yes",NULL,question); | ||
4419 | if (result==1) { | ||
4420 | return true; | ||
4421 | } | ||
4422 | return false;} {} | ||
4423 | } | ||
4424 | Function {samplerate()} {open return_type __uint32 | ||
4425 | } { | ||
4426 | code {// returns current samplerate of the UI, used by mixer | ||
4427 | if (currsong==NULL) return 44100; | ||
4428 | return currsong->samplerate();} {} | ||
4429 | } | ||
4430 | decl {friend class ScrubWheel;} {} | ||
4431 | decl {int refreshingui;} {} | ||
4432 | Function {saverestoretrackselection(Fl_Check_Button* o)} {open return_type void | ||
4433 | } { | ||
4434 | code {int i; | ||
4435 | if (o->value()==1) | ||
4436 | { | ||
4437 | if ( | ||
4438 | (transfersource_mixleft->value() | ||
4439 | +transfersource_mixright->value()) | ||
4440 | ==1) | ||
4441 | { | ||
4442 | // save selected tracks | ||
4443 | // disable track selection | ||
4444 | // (repopulate formats list/file name/whatever?) | ||
4445 | for (i=0;i<MAXCHANNELS;i++) | ||
4446 | { | ||
4447 | tracksave[i]=track[i]->value(); | ||
4448 | track[i]->value(1); | ||
4449 | track[i]->deactivate(); | ||
4450 | button_invert_tracks->deactivate(); | ||
4451 | } | ||
4452 | fileformat->deactivate(); | ||
4453 | return; | ||
4454 | } | ||
4455 | } | ||
4456 | |||
4457 | if (o->value()==0) | ||
4458 | { | ||
4459 | if ( | ||
4460 | (transfersource_mixleft->value() | ||
4461 | +transfersource_mixright->value()) | ||
4462 | ==0) | ||
4463 | { | ||
4464 | // restore tracks | ||
4465 | // enable track selection | ||
4466 | for (i=0;i<MAXCHANNELS;i++) | ||
4467 | { | ||
4468 | track[i]->value(tracksave[i]); | ||
4469 | track[i]->activate(); | ||
4470 | button_invert_tracks->activate(); | ||
4471 | |||
4472 | } | ||
4473 | fileformat->activate(); | ||
4474 | } | ||
4475 | }} {} | ||
4476 | } | ||
4477 | Function {showprogtitle()} {open return_type void | ||
4478 | } { | ||
4479 | code {recorder->control->dispwrite(0,"HD24connect " | ||
4480 | "HD24VERSION ",3000);} {} | ||
4481 | } | ||
4482 | decl {bool closingdown;} {public | ||
4483 | } | ||
4484 | Function {finish()} {open return_type void | ||
4485 | } { | ||
4486 | code {this->control->ready(0); | ||
4487 | this->closingdown=true; | ||
4488 | this->recorder->finish();} {} | ||
4489 | } | ||
4490 | Function {poll_callback(void* user)} {open return_type {static void} | ||
4491 | } { | ||
4492 | code {HD24UserInterface* mythis=(HD24UserInterface*)user; | ||
4493 | //RecorderUI* mythis=(RecorderUI*)user; | ||
4494 | \#if (HD24DEBUG==1) | ||
4495 | //cout << "poll_callback" << endl; | ||
4496 | \#endif | ||
4497 | if (mythis->control->ready()!=1) { return; } | ||
4498 | |||
4499 | |||
4500 | if (mythis->busy!=1) { | ||
4501 | mythis->busy=1; | ||
4502 | hd24song* mycurrsong=mythis->currsong; | ||
4503 | |||
4504 | if (mythis->recorder->control->song()!=mythis->currsong) | ||
4505 | { | ||
4506 | mythis->recorder->control->song(mythis->currsong); /* tell recorder that the song is gone */ | ||
4507 | } | ||
4508 | |||
4509 | if (mycurrsong!=NULL) { | ||
4510 | mycurrsong->bufferpoll(); | ||
4511 | } | ||
4512 | |||
4513 | |||
4514 | mythis->uiredrawcount=(mythis->uiredrawcount+1)%UIREFRESH; | ||
4515 | if (mythis->uiredrawcount==0) { | ||
4516 | |||
4517 | for (unsigned int i=0;i<MAXCHANNELS;i++) { | ||
4518 | // if (mythis->Tabs->value()==mythis->tabCopyToPC) { | ||
4519 | // if (mythis->trackpeak[i]>.01) { | ||
4520 | // if (mythis->trackpeak[i]>.9) | ||
4521 | // { | ||
4522 | // mythis->trackled[i]->color(1); | ||
4523 | // mythis->trackled[i]->redraw(); | ||
4524 | // } else { | ||
4525 | // if (mythis->trackpeak[i]>.7) { | ||
4526 | // mythis->trackled[i]->color(3); | ||
4527 | // mythis->trackled[i]->redraw(); | ||
4528 | // } else { | ||
4529 | // mythis->trackled[i]->color(2); | ||
4530 | // mythis->trackled[i]->redraw(); | ||
4531 | // } | ||
4532 | // } | ||
4533 | // } else { | ||
4534 | // mythis->trackled[i]->color(52); | ||
4535 | // mythis->trackled[i]->redraw(); | ||
4536 | // } | ||
4537 | // } | ||
4538 | } | ||
4539 | |||
4540 | if (mythis->Tabs->value()==mythis->tabMixer) { | ||
4541 | // mythis->mixer->redraw(); | ||
4542 | mythis->mixer->control->updatemeters(); | ||
4543 | } | ||
4544 | if (mythis->Tabs->value()==mythis->tabRecorder) { | ||
4545 | // mythis->mixer->redraw(); | ||
4546 | // mythis->recorder->control->updatemeters(); | ||
4547 | } | ||
4548 | // Fl check?? | ||
4549 | } | ||
4550 | } | ||
4551 | if (mythis->recorder!=NULL) { | ||
4552 | RecorderUI::poll_callback(mythis->recorder); | ||
4553 | } | ||
4554 | mythis->busy=0; | ||
4555 | Fl::add_timeout(TIMEOUT,poll_callback,user);} {} | ||
4556 | } | ||
4557 | decl {Fl_Box* trackled[24];} {public | ||
4558 | } | ||
4559 | Function {setlocbuttonlabel(int i)} {open return_type void | ||
4560 | } { | ||
4561 | code {hd24song* locsong=this->currsong; | ||
4562 | int numpoints=0; | ||
4563 | if (locsong!=NULL) | ||
4564 | { | ||
4565 | numpoints=locsong->locatepointcount(); | ||
4566 | } | ||
4567 | __uint32 locatepos=locsong->getlocatepos(i); | ||
4568 | string* locname1=new string(""); | ||
4569 | if (!(((i==0)||(i==numpoints)))) { | ||
4570 | *locname1+="+"; | ||
4571 | string* dur=locsong->display_duration(locatepos); | ||
4572 | *locname1+=*dur; | ||
4573 | delete (dur); | ||
4574 | } else { | ||
4575 | if (i!=0) | ||
4576 | { | ||
4577 | *locname1+="+"; | ||
4578 | string* dur=locsong->display_duration(locatepos); | ||
4579 | *locname1+=*dur; | ||
4580 | delete (dur); | ||
4581 | } else { | ||
4582 | *locname1+="START"; | ||
4583 | } | ||
4584 | } | ||
4585 | |||
4586 | *locname1="Seek to "+*locname1; | ||
4587 | int l=strlen(locname1->c_str()); | ||
4588 | for (i=0;i<l;i++) { | ||
4589 | locbuttonlabel[i]=locname1->c_str()[i]; | ||
4590 | locbuttonlabel[i+1]=(char)0; | ||
4591 | } | ||
4592 | |||
4593 | button_golocatepoint->label(&(this->locbuttonlabel[0])); | ||
4594 | delete locname1;} {} | ||
4595 | } | ||
4596 | decl {char locbuttonlabel[64];} {} | ||
4597 | } | ||
diff --git a/src/frontend/ui_hd24connect.txt b/src/frontend/ui_hd24connect.txt new file mode 100644 index 0000000..e25538a --- /dev/null +++ b/src/frontend/ui_hd24connect.txt | |||
@@ -0,0 +1,387 @@ | |||
1 | # generated by Fast Light User Interface Designer (fluid) version 1.0107 | ||
2 | 1 | ||
3 | -60 | ||
4 | REC | ||
5 | INP | ||
6 | -48 | ||
7 | -36 | ||
8 | -24 | ||
9 | -15 | ||
10 | -9 | ||
11 | -6 | ||
12 | -3 | ||
13 | -1 | ||
14 | CLIP | ||
15 | HD24connect | ||
16 | &File | ||
17 | &Detect HD24 drives | ||
18 | &Open drive image... | ||
19 | &Save drive image... | ||
20 | &Export catalog... | ||
21 | Save the disk directory to a printable text file | ||
22 | &Print catalog | ||
23 | Save the disk directory to a printable text file | ||
24 | &Recovery | ||
25 | &Select device... | ||
26 | Load &header file... | ||
27 | &Create header file... | ||
28 | Recover song from &power failure | ||
29 | E&xit | ||
30 | &Help | ||
31 | &About | ||
32 | Report a &Bug... | ||
33 | Request a &Feature... | ||
34 | &Credits | ||
35 | Transfer | ||
36 | Cancel | ||
37 | Drive | ||
38 | Drive name: | ||
39 | FS version: | ||
40 | Number of projects: | ||
41 | Rename... | ||
42 | Free space preview: | ||
43 | at | ||
44 | 44100 | ||
45 | 48000 | ||
46 | 88200 | ||
47 | 96000 | ||
48 | Hz, | ||
49 | 2 | ||
50 | 6 | ||
51 | 8 | ||
52 | 12 | ||
53 | 16 | ||
54 | 24 | ||
55 | tracks | ||
56 | Drive information | ||
57 | Drive contents | ||
58 | Project/Song | ||
59 | Song name: | ||
60 | Number of tracks: | ||
61 | Sample rate: | ||
62 | Bit depth: | ||
63 | Duration: | ||
64 | Rename... | ||
65 | Locate points: | ||
66 | Edit... | ||
67 | Write protected | ||
68 | Go | ||
69 | Number of songs: | ||
70 | Project name: | ||
71 | Rename... | ||
72 | Project information | ||
73 | Song information | ||
74 | Recorder | ||
75 | Play | ||
76 | Play | ||
77 | Play | ||
78 | Play | ||
79 | Play | ||
80 | arm | ||
81 | arm | ||
82 | Play | ||
83 | Play | ||
84 | Play | ||
85 | Play | ||
86 | Play | ||
87 | Play | ||
88 | Play | ||
89 | Play | ||
90 | Play | ||
91 | Play | ||
92 | Play | ||
93 | Play | ||
94 | Play | ||
95 | Play | ||
96 | Play | ||
97 | Play | ||
98 | SET LOC | ||
99 | Set Locate | ||
100 | AUTO LOOP | ||
101 | Auto Loop | ||
102 | Rewind | ||
103 | F Fwd | ||
104 | Stop | ||
105 | Play | ||
106 | LOOP START | ||
107 | Loop Start | ||
108 | LOOP END | ||
109 | Loop End | ||
110 | LOC 0 | ||
111 | Locate 0 | ||
112 | Record | ||
113 | arm | ||
114 | arm | ||
115 | arm | ||
116 | arm | ||
117 | arm | ||
118 | arm | ||
119 | arm | ||
120 | arm | ||
121 | arm | ||
122 | arm | ||
123 | arm | ||
124 | arm | ||
125 | arm | ||
126 | arm | ||
127 | arm | ||
128 | arm | ||
129 | arm | ||
130 | arm | ||
131 | arm | ||
132 | arm | ||
133 | arm | ||
134 | arm | ||
135 | arm | ||
136 | arm | ||
137 | Arm tracks | ||
138 | S | ||
139 | Solo | ||
140 | M | ||
141 | Mute | ||
142 | H | ||
143 | M | ||
144 | S | ||
145 | F | ||
146 | AUTO | ||
147 | PLAY | ||
148 | RTN | ||
149 | REC | ||
150 | REHEARSE | ||
151 | PITCH | ||
152 | REHEARSE | ||
153 | Set Locate | ||
154 | PUNCH IN | ||
155 | Set Locate | ||
156 | PUNCH OUT | ||
157 | Set Locate | ||
158 | Peak\012mode | ||
159 | arm | ||
160 | Peak\012clear | ||
161 | arm | ||
162 | Auto\012input | ||
163 | arm | ||
164 | All\012input | ||
165 | arm | ||
166 | Stereo input mapping | ||
167 | Normal | ||
168 | Swap Left and Right | ||
169 | Mix to mono | ||
170 | Use Left only | ||
171 | Use Right only | ||
172 | Mixer | ||
173 | Solo | ||
174 | Mute | ||
175 | S | ||
176 | Solo | ||
177 | M | ||
178 | Mute | ||
179 | MONO | ||
180 | MAIN | ||
181 | 1 | ||
182 | 2 | ||
183 | 3 | ||
184 | 4 | ||
185 | 5 | ||
186 | 6 | ||
187 | 7 | ||
188 | 8 | ||
189 | 9 | ||
190 | 10 | ||
191 | 11 | ||
192 | 12 | ||
193 | 13 | ||
194 | 14 | ||
195 | 15 | ||
196 | 16 | ||
197 | 17 | ||
198 | 18 | ||
199 | 19 | ||
200 | 20 | ||
201 | 21 | ||
202 | 22 | ||
203 | 23 | ||
204 | 24 | ||
205 | Copy to PC | ||
206 | Tracks: | ||
207 | Invert | ||
208 | 01 | ||
209 | 02 | ||
210 | 03 | ||
211 | 04 | ||
212 | 05 | ||
213 | 06 | ||
214 | 07 | ||
215 | 08 | ||
216 | 09 | ||
217 | 10 | ||
218 | 11 | ||
219 | 12 | ||
220 | 13 | ||
221 | 14 | ||
222 | 15 | ||
223 | 16 | ||
224 | 17 | ||
225 | 18 | ||
226 | 19 | ||
227 | 20 | ||
228 | 21 | ||
229 | 22 | ||
230 | 23 | ||
231 | 24 | ||
232 | Transfer | ||
233 | Browse... | ||
234 | Project dir: | ||
235 | From: | ||
236 | To: | ||
237 | Range... | ||
238 | Export file format: | ||
239 | Automatically limit size of exported files | ||
240 | When exporting multiple songs at once, prefix file names with song number | ||
241 | only if multiple songs have the same song name | ||
242 | Transfer source: | ||
243 | Transfer target: | ||
244 | Transfer options: | ||
245 | bytes | ||
246 | Note: The actual file size will be a rough approximation of the requested split size. | ||
247 | Stamp files with a custom sample rate | ||
248 | Sample rate: | ||
249 | 44100 Hz | ||
250 | 48000 Hz | ||
251 | 88200 Hz | ||
252 | 96000 Hz | ||
253 | User defined, specify --> | ||
254 | Hz | ||
255 | Split every: | ||
256 | 650 MB (74 minute CD) | ||
257 | 700 MB (80 minute CD) | ||
258 | 1 GiB (Recommended for wave editors) | ||
259 | 2 GiB (Max. legal WAV size) | ||
260 | 4 GiB (Max. 32-bit limit) | ||
261 | 4.7 GB (DVD size) | ||
262 | User defined, specify --> | ||
263 | Copy to HD24 | ||
264 | Transfer | ||
265 | 01 | ||
266 | 02 | ||
267 | 03 | ||
268 | 04 | ||
269 | 05 | ||
270 | 06 | ||
271 | 07 | ||
272 | 08 | ||
273 | 09 | ||
274 | 10 | ||
275 | 11 | ||
276 | 12 | ||
277 | 13 | ||
278 | 14 | ||
279 | 15 | ||
280 | 16 | ||
281 | 17 | ||
282 | 18 | ||
283 | 19 | ||
284 | 20 | ||
285 | 21 | ||
286 | 22 | ||
287 | 23 | ||
288 | 24 | ||
289 | Load... | ||
290 | Clear | ||
291 | font | ||
292 | label | ||
293 | label | ||
294 | label | ||
295 | label | ||
296 | label | ||
297 | label | ||
298 | label | ||
299 | label | ||
300 | label | ||
301 | label | ||
302 | label | ||
303 | label | ||
304 | label | ||
305 | label | ||
306 | label | ||
307 | label | ||
308 | label | ||
309 | label | ||
310 | label | ||
311 | label | ||
312 | label | ||
313 | label | ||
314 | label | ||
315 | label | ||
316 | label | ||
317 | label | ||
318 | label | ||
319 | label | ||
320 | label | ||
321 | label | ||
322 | label | ||
323 | label | ||
324 | label | ||
325 | label | ||
326 | label | ||
327 | label | ||
328 | label | ||
329 | label | ||
330 | label | ||
331 | label | ||
332 | label | ||
333 | label | ||
334 | label | ||
335 | label | ||
336 | label | ||
337 | label | ||
338 | label | ||
339 | label | ||
340 | label | ||
341 | label | ||
342 | label | ||
343 | label | ||
344 | label | ||
345 | label | ||
346 | label | ||
347 | label | ||
348 | label | ||
349 | label | ||
350 | label | ||
351 | label | ||
352 | label | ||
353 | label | ||
354 | label | ||
355 | label | ||
356 | label | ||
357 | label | ||
358 | label | ||
359 | label | ||
360 | label | ||
361 | label | ||
362 | label | ||
363 | label | ||
364 | label | ||
365 | label | ||
366 | label | ||
367 | label | ||
368 | label | ||
369 | label | ||
370 | label | ||
371 | label | ||
372 | label | ||
373 | label | ||
374 | label | ||
375 | label | ||
376 | label | ||
377 | label | ||
378 | label | ||
379 | label | ||
380 | label | ||
381 | label | ||
382 | label | ||
383 | label | ||
384 | label | ||
385 | label | ||
386 | label | ||
387 | label | ||
diff --git a/src/frontend/ui_hd24trackchannel.fl b/src/frontend/ui_hd24trackchannel.fl new file mode 100644 index 0000000..748313e --- /dev/null +++ b/src/frontend/ui_hd24trackchannel.fl | |||
@@ -0,0 +1,322 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#include <config.h>} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <FL/FLTKstuff.H>} {public | ||
9 | } | ||
10 | |||
11 | decl {\#include <ui_hd24connect.h>} {public | ||
12 | } | ||
13 | |||
14 | class HD24TrackChannel {open : {public Fl_Group} | ||
15 | } { | ||
16 | decl {\#define PEAKMODE_NOHOLD 0} {public | ||
17 | } | ||
18 | decl {\#define PEAKMODE_TEMPHOLD 1} {public | ||
19 | } | ||
20 | decl {\#define PEAKMODE_CONTHOLD 2} {public | ||
21 | } | ||
22 | decl {\#define PEAKMODE_MAXHOLD 33} {public | ||
23 | } | ||
24 | decl {int mode;} {} | ||
25 | decl {int maxledslit; /* for peak hold */} {public | ||
26 | } | ||
27 | decl {int holdtime;} {public | ||
28 | } | ||
29 | decl {RecorderUI* ui;} {selected | ||
30 | } | ||
31 | decl {Fl_Box* levelled[10];} {public | ||
32 | } | ||
33 | decl {Fl_Window* win;} {} | ||
34 | decl {unsigned int channel;} {} | ||
35 | Function {make_window()} {open | ||
36 | } { | ||
37 | Fl_Window ledchannel {open | ||
38 | xywh {20 74 20 120} type Double color 0 labelcolor 7 | ||
39 | code0 {o->position(parent()->x(),parent()->y());} | ||
40 | class Fl_Group visible | ||
41 | } { | ||
42 | Fl_Box tracknum { | ||
43 | label 1 | ||
44 | xywh {3 76 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 10 labelcolor 6 align 2 | ||
45 | } | ||
46 | Fl_Box led1 { | ||
47 | xywh {3 76 12 6} box FLAT_BOX color 6 labelfont 1 labelsize 10 labelcolor 6 align 2 hide | ||
48 | code0 {levelled[0]=led1;} | ||
49 | } | ||
50 | Fl_Box recled { | ||
51 | xywh {3 96 12 6} box FLAT_BOX color 1 labelfont 1 labelsize 10 labelcolor 1 align 2 hide | ||
52 | } | ||
53 | Fl_Box inputled { | ||
54 | xywh {3 104 12 6} box FLAT_BOX color 6 labelfont 1 labelsize 10 labelcolor 6 align 2 hide | ||
55 | } | ||
56 | Fl_Box led2 { | ||
57 | xywh {3 68 12 6} box FLAT_BOX color 6 labelfont 1 labelsize 10 labelcolor 6 align 2 hide | ||
58 | code0 {levelled[1]=led2;} | ||
59 | } | ||
60 | Fl_Box led3 { | ||
61 | xywh {3 60 12 6} box FLAT_BOX color 6 labelfont 1 labelsize 10 labelcolor 6 align 2 hide | ||
62 | code0 {levelled[2]=led3;} | ||
63 | } | ||
64 | Fl_Box led4 { | ||
65 | xywh {3 52 12 6} box FLAT_BOX color 6 labelfont 1 labelsize 10 labelcolor 6 align 2 hide | ||
66 | code0 {levelled[3]=led4;} | ||
67 | } | ||
68 | Fl_Box led5 { | ||
69 | xywh {3 44 12 6} box FLAT_BOX color 6 labelfont 1 labelsize 10 labelcolor 6 align 2 hide | ||
70 | code0 {levelled[4]=led5;} | ||
71 | } | ||
72 | Fl_Box led6 { | ||
73 | xywh {3 36 12 6} box FLAT_BOX color 6 labelfont 1 labelsize 10 labelcolor 6 align 2 hide | ||
74 | code0 {levelled[5]=led6;} | ||
75 | } | ||
76 | Fl_Box led7 { | ||
77 | xywh {3 28 12 6} box FLAT_BOX color 93 labelfont 1 labelsize 10 labelcolor 93 align 2 hide | ||
78 | code0 {levelled[6]=led7;} | ||
79 | } | ||
80 | Fl_Box led8 { | ||
81 | xywh {3 20 12 6} box FLAT_BOX color 93 labelfont 1 labelsize 10 labelcolor 93 align 2 hide | ||
82 | code0 {levelled[7]=led8;} | ||
83 | } | ||
84 | Fl_Box led9 { | ||
85 | xywh {3 12 12 6} box FLAT_BOX color 93 labelfont 1 labelsize 10 labelcolor 93 align 2 hide | ||
86 | code0 {levelled[8]=led9;} | ||
87 | } | ||
88 | Fl_Box led10 { | ||
89 | xywh {3 4 12 6} box FLAT_BOX color 1 labelfont 1 labelsize 10 labelcolor 1 align 2 hide | ||
90 | code0 {levelled[9]=led10;} | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | Function {setval(float levelval)} {open | ||
95 | } { | ||
96 | code {int lednum=0; | ||
97 | double myval=(double)levelval; | ||
98 | |||
99 | // reset peaks if desired | ||
100 | switch (mode) { | ||
101 | case PEAKMODE_NOHOLD: this->peakreset(); break; | ||
102 | case PEAKMODE_TEMPHOLD: | ||
103 | if (this->holdtime>PEAKMODE_MAXHOLD) { | ||
104 | peakreset(); | ||
105 | } else { | ||
106 | this->holdtime++; | ||
107 | } | ||
108 | break; | ||
109 | case PEAKMODE_CONTHOLD: | ||
110 | break; | ||
111 | default: | ||
112 | this->mode=PEAKMODE_NOHOLD; | ||
113 | peakreset(); | ||
114 | break; | ||
115 | } | ||
116 | |||
117 | int ledslit=0; | ||
118 | |||
119 | if (myval>= ledlimit[lednum]) { ledslit=1; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
120 | if (myval>= ledlimit[lednum]) { ledslit=2; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
121 | if (myval>= ledlimit[lednum]) { ledslit=3; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
122 | if (myval>= ledlimit[lednum]) { ledslit=4; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
123 | if (myval>= ledlimit[lednum]) { ledslit=5; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
124 | if (myval>= ledlimit[lednum]) { ledslit=6; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
125 | if (myval>= ledlimit[lednum]) { ledslit=7; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
126 | if (myval>= ledlimit[lednum]) { ledslit=8; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
127 | if (myval>= ledlimit[lednum]) { ledslit=9; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
128 | if (myval>= ledlimit[lednum]) { ledslit=10; this->levelled[lednum++]->show(); } else { this->levelled[lednum++]->hide(); } | ||
129 | |||
130 | if (ledslit >this->maxledslit ) { | ||
131 | this->maxledslit=ledslit; | ||
132 | this->holdtime=0; | ||
133 | } else { | ||
134 | if ((this->maxledslit)>0) { | ||
135 | this->levelled[maxledslit-1]->show(); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | checkblink();} {} | ||
140 | } | ||
141 | Function {init_window()} {open return_type void | ||
142 | } { | ||
143 | code {this->mode=PEAKMODE_NOHOLD; | ||
144 | this->win=(Fl_Window*)make_window(); | ||
145 | this->ui=NULL; | ||
146 | this->channel=0; | ||
147 | this->maxledslit=0; | ||
148 | this->holdtime=0; | ||
149 | this->ledlimit[0]=(double)pow(10,(double)((double)-30/(double)10)); // -30 dB | ||
150 | this->ledlimit[1]=(double)pow(10,(double)((double)-24/(double)10)); // -24 dB | ||
151 | this->ledlimit[2]=(double)pow(10,(double)((double)-18/(double)10)); | ||
152 | this->ledlimit[3]=(double)pow(10,(double)((double)-12/(double)10)); //... | ||
153 | this->ledlimit[4]=(double)pow(10,(double)((double)-7.5/(double)10)); | ||
154 | this->ledlimit[5]=(double)pow(10,(double)((double)-4.5/(double)10)); | ||
155 | this->ledlimit[6]=(double)pow(10,(double)((double)-3/(double)10)); | ||
156 | this->ledlimit[7]=(double)pow(10,(double)((double)-1.5/(double)10)); | ||
157 | this->ledlimit[8]=(double)pow(10,(double)((double)-.5/(double)10)); | ||
158 | this->ledlimit[9]=(double)pow(10,(double)((double)0/(double)10)); // -0 dB | ||
159 | |||
160 | this->setval(0); | ||
161 | |||
162 | return;} {} | ||
163 | } | ||
164 | Function {HD24TrackChannel(int a,int b,int c,int d,const char* e):Fl_Group(a,b,c,d,e)} {open | ||
165 | } { | ||
166 | code {init_window();} {} | ||
167 | } | ||
168 | Function {HD24TrackChannel(int a,int b,int c,int d):Fl_Group(a,b,c,d,NULL)} {open | ||
169 | } { | ||
170 | code {init_window();} {} | ||
171 | } | ||
172 | Function {setchnum(__uint32 i)} {open | ||
173 | } { | ||
174 | code {/* As copy_label does not work on older versions of fltk, | ||
175 | the label now persists within the object but outside this | ||
176 | function. This solves the problem that is nowadays addressed | ||
177 | by copy_label, but without requiring an up-to-date version | ||
178 | of FLTK (1.1.6 or later). */ | ||
179 | channel=i; | ||
180 | snprintf(&labeltext[0],8,"%ld",i); | ||
181 | this->tracknum->label(labeltext);} {} | ||
182 | } | ||
183 | Function {setui(RecorderUI* p_ui)} {open | ||
184 | } { | ||
185 | code {this->ui=p_ui;} {} | ||
186 | } | ||
187 | Function {checkblink()} {open | ||
188 | } { | ||
189 | code {if (ui==NULL) return; | ||
190 | /* | ||
191 | TODO: Make available | ||
192 | if (ui->currenthd24==NULL) return; | ||
193 | */ | ||
194 | if (channel==0) return; | ||
195 | |||
196 | |||
197 | bool showinputled=false; | ||
198 | /* | ||
199 | if (ui->currenthd24->isallinput()) { | ||
200 | if (ui->control->song()==NULL) { | ||
201 | // no song, show all input leds | ||
202 | showinputled=true; | ||
203 | } else { | ||
204 | // song selected, only show as many | ||
205 | // input leds as channels in the song | ||
206 | if (channel<=ui->control->song()->logical_channels()) { | ||
207 | showinputled=ui->control->song()->istrackmonitoringinput(channel); | ||
208 | } | ||
209 | } | ||
210 | } else { | ||
211 | */ | ||
212 | if (ui->control->song()!=NULL) { | ||
213 | showinputled=ui->control->song()->istrackmonitoringinput(channel); | ||
214 | } | ||
215 | /* | ||
216 | } | ||
217 | */ | ||
218 | |||
219 | if (ui->control->song()!=NULL) { | ||
220 | if (ui->control->song()->logical_channels()<channel) { | ||
221 | this->recled->hide(); | ||
222 | } else { | ||
223 | if (ui->control->song()->trackarmed(channel)) { | ||
224 | if (ui->blinkcounter<8) { | ||
225 | this->recled->hide(); | ||
226 | } else { | ||
227 | this->recled->show(); | ||
228 | } | ||
229 | } else { | ||
230 | this->recled->hide(); | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | if (showinputled) { | ||
235 | this->inputled->show(); | ||
236 | } else { | ||
237 | this->inputled->hide(); | ||
238 | } | ||
239 | |||
240 | return;} {} | ||
241 | } | ||
242 | decl {double ledlimit[10];} {} | ||
243 | Function {peakreset()} {return_type void | ||
244 | } { | ||
245 | code {maxledslit=0; | ||
246 | holdtime=0;} {} | ||
247 | } | ||
248 | Function {peakmode(int p_peakmode)} {return_type void | ||
249 | } { | ||
250 | code {this->mode=p_peakmode; | ||
251 | peakreset();} {} | ||
252 | } | ||
253 | decl {char labeltext[10];} {} | ||
254 | } | ||
255 | |||
256 | class TrackInfo {: {public Fl_Group} | ||
257 | } { | ||
258 | Function {make_window()} {} { | ||
259 | Fl_Window ledchannel { | ||
260 | xywh {5 69 20 120} type Double color 0 labelcolor 7 align 16 hide | ||
261 | code0 {o->position(parent()->x(),parent()->y());} | ||
262 | class Fl_Group | ||
263 | } { | ||
264 | Fl_Box led1 { | ||
265 | label {-60} | ||
266 | xywh {3 76 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 6 align 16 | ||
267 | } | ||
268 | Fl_Box recled { | ||
269 | label REC | ||
270 | xywh {3 96 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 1 align 16 | ||
271 | } | ||
272 | Fl_Box inputled { | ||
273 | label INP | ||
274 | xywh {3 104 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 6 align 16 | ||
275 | } | ||
276 | Fl_Box led2 { | ||
277 | label {-48} | ||
278 | xywh {3 68 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 6 align 16 | ||
279 | } | ||
280 | Fl_Box led3 { | ||
281 | label {-36} | ||
282 | xywh {3 60 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 6 align 16 | ||
283 | } | ||
284 | Fl_Box led4 { | ||
285 | label {-24} | ||
286 | xywh {3 52 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 6 align 16 | ||
287 | } | ||
288 | Fl_Box led5 { | ||
289 | label {-15} | ||
290 | xywh {3 44 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 1 align 16 | ||
291 | } | ||
292 | Fl_Box led6 { | ||
293 | label {-9} | ||
294 | xywh {3 36 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 6 align 16 | ||
295 | } | ||
296 | Fl_Box led7 { | ||
297 | label {-6} | ||
298 | xywh {3 28 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 93 align 16 | ||
299 | } | ||
300 | Fl_Box led8 { | ||
301 | label {-3} | ||
302 | xywh {3 20 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 93 align 16 | ||
303 | } | ||
304 | Fl_Box led9 { | ||
305 | label {-1} | ||
306 | xywh {3 12 12 6} box FLAT_BOX color 0 labelfont 1 labelsize 9 labelcolor 93 align 16 | ||
307 | } | ||
308 | Fl_Box led10 { | ||
309 | label CLIP | ||
310 | xywh {0 4 22 6} box FLAT_BOX color 0 labelfont 1 labelsize 8 labelcolor 1 align 16 | ||
311 | } | ||
312 | } | ||
313 | } | ||
314 | Function {TrackInfo(int a,int b,int c,int d,const char* e):Fl_Group(a,b,c,d,e)} {open | ||
315 | } { | ||
316 | code {make_window();} {} | ||
317 | } | ||
318 | Function {TrackInfo(int a,int b,int c,int d):Fl_Group(a,b,c,d,NULL)} {open | ||
319 | } { | ||
320 | code {make_window();} {} | ||
321 | } | ||
322 | } | ||
diff --git a/src/frontend/ui_help_about.fl b/src/frontend/ui_help_about.fl new file mode 100755 index 0000000..2bd0a3b --- /dev/null +++ b/src/frontend/ui_help_about.fl | |||
@@ -0,0 +1,68 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | class UserInterface_HelpAbout {open | ||
6 | } { | ||
7 | Function {make_window()} {open | ||
8 | } { | ||
9 | Fl_Window {} { | ||
10 | label {About HD24connect} open | ||
11 | xywh {567 209 340 350} type Double color 52 modal visible | ||
12 | } { | ||
13 | Fl_Box {} { | ||
14 | xywh {10 10 320 305} box DOWN_BOX color 7 | ||
15 | } | ||
16 | Fl_Box {} { | ||
17 | image {images/hd24connect.png} xywh {45 25 250 77} | ||
18 | } | ||
19 | Fl_Button {} { | ||
20 | label OK | ||
21 | callback {/* Find the window regardless of its class name */ | ||
22 | Fl_Window * x=Fl::first_window(); | ||
23 | x->~Fl_Window();} | ||
24 | xywh {125 320 90 25} labelsize 12 | ||
25 | } | ||
26 | Fl_Box {} { | ||
27 | label {HD24connect version HD24VERSION} | ||
28 | xywh {45 110 250 20} labelsize 12 | ||
29 | } | ||
30 | Fl_Box {} { | ||
31 | label {This program was written as an independent effort,} | ||
32 | xywh {15 130 305 20} labelsize 11 | ||
33 | } | ||
34 | Fl_Box {} { | ||
35 | label {and is neither endorsed by nor affiliated with Alesis.} | ||
36 | xywh {15 145 305 20} labelsize 11 | ||
37 | } | ||
38 | Fl_Box {} { | ||
39 | label {No warranty of any kind is given or implied.} selected | ||
40 | xywh {15 175 305 20} labelsize 11 | ||
41 | } | ||
42 | Fl_Box {} { | ||
43 | label {Share and enjoy!} | ||
44 | xywh {10 290 310 20} labelsize 11 | ||
45 | } | ||
46 | Fl_Box {} { | ||
47 | label {Use at your own risk.} | ||
48 | xywh {15 190 305 20} labelsize 11 | ||
49 | } | ||
50 | Fl_Box {} { | ||
51 | label {If you find this program useful, please make a } | ||
52 | xywh {15 215 305 20} labelsize 11 | ||
53 | } | ||
54 | Fl_Box {} { | ||
55 | label {donation to the author. See } | ||
56 | xywh {15 230 305 20} labelsize 11 | ||
57 | } | ||
58 | Fl_Box {} { | ||
59 | label {http://ringbreak.dnd.utwente.nl/~mrjb/hd24tools/} | ||
60 | xywh {15 245 305 20} labelsize 11 | ||
61 | } | ||
62 | Fl_Box {} { | ||
63 | label {Feel free to request additional features.} | ||
64 | xywh {15 260 305 20} labelsize 11 | ||
65 | } | ||
66 | } | ||
67 | } | ||
68 | } | ||
diff --git a/src/frontend/ui_mixer.fl b/src/frontend/ui_mixer.fl new file mode 100644 index 0000000..11dee83 --- /dev/null +++ b/src/frontend/ui_mixer.fl | |||
@@ -0,0 +1,2225 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0109 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#define MAXSAMRATE 48000} {public | ||
6 | } | ||
7 | |||
8 | decl {\#define maxfilterunits 200} {public | ||
9 | } | ||
10 | |||
11 | decl {\#define maxreverbunits 20} {public | ||
12 | } | ||
13 | |||
14 | decl {\#define maxreverbseconds 1} {public | ||
15 | } | ||
16 | |||
17 | decl {\#define eqperchan 4} {public | ||
18 | } | ||
19 | |||
20 | decl {\#define Pi2 (2*3.1415926535897)} {public | ||
21 | } | ||
22 | |||
23 | decl {\#include <config.h>} {public | ||
24 | } | ||
25 | |||
26 | decl {\#include <string>} {public | ||
27 | } | ||
28 | |||
29 | decl {\#include <vector>} {public | ||
30 | } | ||
31 | |||
32 | decl {\#include <soundlibs.h>} {public | ||
33 | } | ||
34 | |||
35 | decl {\#include <iostream>} {public | ||
36 | } | ||
37 | |||
38 | decl {\#include <fstream>} {public | ||
39 | } | ||
40 | |||
41 | decl {\#include <FL/FLTKstuff.H>} {public | ||
42 | } | ||
43 | |||
44 | decl {\#include <FL/filename.H>} {public | ||
45 | } | ||
46 | |||
47 | decl {\#include <convertlib.h>} {public | ||
48 | } | ||
49 | |||
50 | decl {\#include <WidgetPDial.h>} {public | ||
51 | } | ||
52 | |||
53 | decl {\#include <time.h>} {public | ||
54 | } | ||
55 | |||
56 | decl {\#include <math.h>} {public | ||
57 | } | ||
58 | |||
59 | decl {\#include <ui_hd24connect.h>} {public | ||
60 | } | ||
61 | |||
62 | class stereosample {open | ||
63 | } { | ||
64 | decl {float left;} {public | ||
65 | } | ||
66 | decl {float right;} {public | ||
67 | } | ||
68 | } | ||
69 | |||
70 | decl {class MixerChannelControl;} {public | ||
71 | } | ||
72 | |||
73 | decl {class MixerChannelUI;} {public | ||
74 | } | ||
75 | |||
76 | decl {class MixerChannelData;} {public | ||
77 | } | ||
78 | |||
79 | decl {class MasterChannelUI;} {public | ||
80 | } | ||
81 | |||
82 | decl {class MasterChannelControl;} {public | ||
83 | } | ||
84 | |||
85 | decl {class MixerControl;} {public | ||
86 | } | ||
87 | |||
88 | decl {class MixerChannelUI;} {public | ||
89 | } | ||
90 | |||
91 | class MixerLevelMeterData {} { | ||
92 | decl {\#define PEAKMODE_NOHOLD 0} {public | ||
93 | } | ||
94 | decl {\#define PEAKMODE_TEMPHOLD 1} {public | ||
95 | } | ||
96 | decl {\#define PEAKMODE_CONTHOLD 2} {public | ||
97 | } | ||
98 | decl {\#define PEAKMODE_MAXHOLD 33} {public | ||
99 | } | ||
100 | decl {int mode;} {public | ||
101 | } | ||
102 | decl {double dB;} {public | ||
103 | } | ||
104 | decl {double peakvalue; /* for peak hold */} {public | ||
105 | } | ||
106 | decl {double metervalue;} {public | ||
107 | } | ||
108 | decl {int holdtime;} {public | ||
109 | } | ||
110 | decl {int dBrange;} {public | ||
111 | } | ||
112 | } | ||
113 | |||
114 | class MixerLevelMeterControl {} { | ||
115 | decl {MixerLevelMeterData* data;} {} | ||
116 | Function {MixerLevelMeterControl()} {open | ||
117 | } { | ||
118 | code {data=new MixerLevelMeterData; | ||
119 | init();} {} | ||
120 | } | ||
121 | Function {~MixerLevelMeterControl()} {open | ||
122 | } { | ||
123 | code {delete data;} {} | ||
124 | } | ||
125 | Function {setvalue(double levelval)} {open | ||
126 | } { | ||
127 | code {data->dB=20*log10(levelval); | ||
128 | return; | ||
129 | |||
130 | // reset peaks if desired | ||
131 | switch (data->mode) { | ||
132 | case PEAKMODE_NOHOLD: this->peakreset(); break; | ||
133 | case PEAKMODE_TEMPHOLD: | ||
134 | if (data->holdtime>PEAKMODE_MAXHOLD) { | ||
135 | peakreset(); | ||
136 | } else { | ||
137 | data->holdtime++; | ||
138 | } | ||
139 | break; | ||
140 | case PEAKMODE_CONTHOLD: | ||
141 | break; | ||
142 | default: | ||
143 | data->mode=PEAKMODE_NOHOLD; | ||
144 | peakreset(); | ||
145 | break; | ||
146 | } | ||
147 | |||
148 | if (levelval>data->metervalue) { | ||
149 | data->peakvalue=data->metervalue; | ||
150 | data->holdtime=0; | ||
151 | }} {} | ||
152 | } | ||
153 | Function {peakmode(int p_peakmode)} {open return_type void | ||
154 | } { | ||
155 | code {data->mode=p_peakmode; | ||
156 | peakreset();} {} | ||
157 | } | ||
158 | Function {peakreset()} {open return_type void | ||
159 | } { | ||
160 | code {data->peakvalue=0; | ||
161 | data->holdtime=0;} {} | ||
162 | } | ||
163 | Function {init()} {open return_type void | ||
164 | } { | ||
165 | code {data->peakvalue=0; | ||
166 | data->holdtime=0; | ||
167 | |||
168 | data->dBrange=60; | ||
169 | this->setvalue(0); | ||
170 | return;} {} | ||
171 | } | ||
172 | Function {getpctvalue()} {open return_type float | ||
173 | } { | ||
174 | code {float pct=100-(100*(-(data->dB)/(data->dBrange))); | ||
175 | |||
176 | if (pct<0) { pct=0; } | ||
177 | if (pct>100) { pct=100; } | ||
178 | |||
179 | return pct;} {} | ||
180 | } | ||
181 | } | ||
182 | |||
183 | class MixerLevelMeterUI {: {public Fl_Group} | ||
184 | } { | ||
185 | decl {MixerLevelMeterControl* control;} {public | ||
186 | } | ||
187 | Function {MixerLevelMeterUI(int a,int b,int c,int d,const char* e):Fl_Group(a,b,c,d,e)} {} { | ||
188 | code {init_ui();} {} | ||
189 | } | ||
190 | Function {MixerLevelMeterUI(int a,int b,int c,int d):Fl_Group(a,b,c,d,NULL)} {} { | ||
191 | code {init_ui();} {} | ||
192 | } | ||
193 | Function {init_ui()} {open private | ||
194 | } { | ||
195 | code {this->control=new MixerLevelMeterControl();} {} | ||
196 | } | ||
197 | Function {draw()} {open | ||
198 | } { | ||
199 | code {float pct=(control->getpctvalue())/100; | ||
200 | |||
201 | int zro=y(); | ||
202 | int bot=zro+128; | ||
203 | int myx=x(); | ||
204 | int top=bot- ((int)( pct*128)); | ||
205 | |||
206 | fl_color(fl_rgb_color(0,255,0)); | ||
207 | fl_line(myx,top,myx,bot); | ||
208 | myx++; | ||
209 | fl_line(myx,top,myx,bot); | ||
210 | myx--; | ||
211 | |||
212 | fl_color(fl_rgb_color(0,0,0)); | ||
213 | fl_line(myx,zro,myx,top); | ||
214 | myx++; | ||
215 | fl_line(myx,zro,myx,top); | ||
216 | |||
217 | return;} {} | ||
218 | } | ||
219 | Function {~MixerLevelMeterUI()} {open | ||
220 | } { | ||
221 | code {delete control;} {} | ||
222 | } | ||
223 | } | ||
224 | |||
225 | class MixerChannelData {open | ||
226 | } { | ||
227 | decl {int bypass; /* 1 to bypass all mixing */} {public | ||
228 | } | ||
229 | decl {friend class MixerChannelUI;} {} | ||
230 | decl {friend class MixerChannelControl;} {} | ||
231 | decl {MixerChannelUI* parentui;} {} | ||
232 | decl {double trackpeak;} {public | ||
233 | } | ||
234 | decl {int enable_eq; /* overall eq settings */} {public | ||
235 | } | ||
236 | decl {int enable_pan; /* overall eq settings */} {public | ||
237 | } | ||
238 | decl {int eq_on[eqperchan];} {public | ||
239 | } | ||
240 | decl {double eq_gain[eqperchan];} {public | ||
241 | } | ||
242 | decl {double eq_freq[eqperchan];} {public | ||
243 | } | ||
244 | decl {double eq_Q[eqperchan];} {public | ||
245 | } | ||
246 | decl {double eq_type[eqperchan];} {public | ||
247 | } | ||
248 | decl {double fadermult;} {public | ||
249 | } | ||
250 | decl {double faderval;} {public | ||
251 | } | ||
252 | decl {double panvalue;} {public | ||
253 | } | ||
254 | decl {float* delaybuffer;} {} | ||
255 | decl {long delaybuffersize;} {public | ||
256 | } | ||
257 | decl {long delaybuffersam;} {public | ||
258 | } | ||
259 | decl {int solo;} {} | ||
260 | decl {int mute;} {} | ||
261 | decl {int ch_number;} {} | ||
262 | decl {char strchnum[4];} {} | ||
263 | decl {float* sample;} {public | ||
264 | } | ||
265 | decl {int mixmono;} {} | ||
266 | decl {MixerControl* parentmixercontrol;} {} | ||
267 | decl {__uint32 samplerate;} {public | ||
268 | } | ||
269 | decl {int selected;} {} | ||
270 | decl {int ringbufpos[maxreverbunits];} {} | ||
271 | } | ||
272 | |||
273 | class MixerChannelControl {open | ||
274 | } { | ||
275 | decl {friend class MixerChannelUI;} {} | ||
276 | decl {friend class MixerChannelData;} {} | ||
277 | decl {MixerChannelData* data;} {public | ||
278 | } | ||
279 | Function {init()} {open return_type void | ||
280 | } { | ||
281 | code {data->bypass=0; | ||
282 | data->trackpeak=0; | ||
283 | data->enable_eq=1; | ||
284 | data->enable_pan=1; | ||
285 | data->solo=0; | ||
286 | data->mute=0; | ||
287 | data->sample=(float *)malloc(24000*sizeof(float)); | ||
288 | data->eq_gain[0]=0; | ||
289 | data->eq_gain[1]=0; | ||
290 | data->eq_gain[2]=0; | ||
291 | data->eq_gain[3]=0; | ||
292 | data->eq_Q[0]=1; | ||
293 | data->eq_Q[1]=1; | ||
294 | data->eq_Q[2]=1; | ||
295 | data->eq_Q[3]=1; | ||
296 | data->eq_on[0]=1; | ||
297 | data->eq_on[1]=1; | ||
298 | data->eq_on[2]=1; | ||
299 | data->eq_on[3]=1; | ||
300 | data->eq_freq[0]=100; | ||
301 | data->eq_freq[1]=600; | ||
302 | data->eq_freq[2]=1600; | ||
303 | data->eq_freq[3]=6000; | ||
304 | data->samplerate=44100; // TODO: set to proper val | ||
305 | data->faderval=90; | ||
306 | data->fadermult=1; | ||
307 | data->panvalue=0; | ||
308 | |||
309 | |||
310 | data->delaybuffersize=maxreverbunits*maxreverbseconds*MAXSAMRATE; | ||
311 | data->delaybuffer=(float *)malloc(sizeof(float)*(data->delaybuffersize)); | ||
312 | if (data->delaybuffer==NULL) cout << " out of mem L" << endl; | ||
313 | data->delaybuffersam=data->delaybuffersize; | ||
314 | for (int i=0;i<data->delaybuffersize;i++) | ||
315 | { | ||
316 | data->delaybuffer[i]=0; | ||
317 | } | ||
318 | data->ringbufpos[0]=881; | ||
319 | data->ringbufpos[1]=883; | ||
320 | data->ringbufpos[2]=887; | ||
321 | data->ringbufpos[3]=907; | ||
322 | data->ringbufpos[4]=911; | ||
323 | data->ringbufpos[5]=919; | ||
324 | data->ringbufpos[6]=929; | ||
325 | data->ringbufpos[7]=937; | ||
326 | data->ringbufpos[8]=941; | ||
327 | data->ringbufpos[9]=947; | ||
328 | data->ringbufpos[10]=953; | ||
329 | data->ringbufpos[11]=967; | ||
330 | data->ringbufpos[12]=971; | ||
331 | data->ringbufpos[13]=977; | ||
332 | data->ringbufpos[14]=983; | ||
333 | data->ringbufpos[15]=991; | ||
334 | data->ringbufpos[16]=997; | ||
335 | data->ringbufpos[17]=1009; | ||
336 | data->ringbufpos[18]=1013; | ||
337 | data->ringbufpos[19]=1019; | ||
338 | |||
339 | return;} {} | ||
340 | } | ||
341 | Function {MixerChannelControl()} {open | ||
342 | } { | ||
343 | code {data=new MixerChannelData(); | ||
344 | init();} {} | ||
345 | } | ||
346 | Function {~MixerChannelControl()} {open | ||
347 | } { | ||
348 | code {free (data->sample); | ||
349 | data->sample=NULL; | ||
350 | free (data->delaybuffer); | ||
351 | data->delaybuffer=NULL; | ||
352 | delete data; | ||
353 | data=NULL;} {} | ||
354 | } | ||
355 | Function {fadervalue(const double p_val)} {} { | ||
356 | code {double lin; | ||
357 | if (p_val == 0) { | ||
358 | lin=0; | ||
359 | } else { | ||
360 | lin=pow(10,(p_val-90)/60); | ||
361 | } | ||
362 | data->fadermult=lin; | ||
363 | data->faderval=p_val; | ||
364 | data->parentui->fader->value(p_val); | ||
365 | data->parentui->redraw();} {} | ||
366 | } | ||
367 | Function {fadervalue()} {open return_type double | ||
368 | } { | ||
369 | code {return data->faderval;} {} | ||
370 | } | ||
371 | Function {updatemeters()} {open return_type void | ||
372 | } { | ||
373 | code {// update and redraw meterlevels object | ||
374 | this->parentui()->mixled->control->setvalue(data->trackpeak); | ||
375 | this->parentui()->mixled->redraw(); | ||
376 | // then, reset peak value | ||
377 | trackpeak(0);} {} | ||
378 | } | ||
379 | Function {solo(int p_val)} {open return_type void | ||
380 | } { | ||
381 | code {data->solo=p_val; | ||
382 | data->parentui->mixsolo->value(p_val); | ||
383 | data->parentui->mixsolo->damage(); | ||
384 | data->parentui->mixsolo->redraw(); | ||
385 | if (p_val==1) | ||
386 | { | ||
387 | this->parentmixercontrol()->selectedchannel(this->channel_number()-1); | ||
388 | }} {} | ||
389 | } | ||
390 | Function {mute(int p_val)} {open return_type void | ||
391 | } { | ||
392 | code {data->mute=p_val; | ||
393 | data->parentui->mixmute->value(p_val); | ||
394 | data->parentui->mixmute->damage(); | ||
395 | data->parentui->mixmute->redraw(); | ||
396 | //if (ui!=NULL) { | ||
397 | // ui->readmixer(); | ||
398 | //}} {} | ||
399 | } | ||
400 | Function {solo()} {open return_type int | ||
401 | } { | ||
402 | code {return data->solo;} {} | ||
403 | } | ||
404 | Function {mute()} {open return_type int | ||
405 | } { | ||
406 | code {return data->mute;} {} | ||
407 | } | ||
408 | Function {issolo()} {open return_type int | ||
409 | } { | ||
410 | code {return data->solo;} {} | ||
411 | } | ||
412 | Function {ismute()} {open return_type int | ||
413 | } { | ||
414 | code {return data->mute;} {} | ||
415 | } | ||
416 | Function {getfadermult()} {open return_type double | ||
417 | } { | ||
418 | code {return data->fadermult;} {} | ||
419 | } | ||
420 | Function {trackpeak()} {open return_type double | ||
421 | } { | ||
422 | code {return data->trackpeak;} {} | ||
423 | } | ||
424 | Function {trackpeak(double peakval)} {open return_type void | ||
425 | } { | ||
426 | code {data->trackpeak=peakval;} {} | ||
427 | } | ||
428 | Function {channel_number(int ch)} {open return_type void | ||
429 | } { | ||
430 | code {data->ch_number=ch; | ||
431 | snprintf(data->strchnum,3,"%d",ch); | ||
432 | data->parentui->mixmute->label(data->strchnum);} {} | ||
433 | } | ||
434 | Function {channel_number()} {open return_type int | ||
435 | } { | ||
436 | code {return data->ch_number;} {} | ||
437 | } | ||
438 | Function {parentmixercontrol(MixerControl* p_parentmixercontrol)} {open return_type void | ||
439 | } { | ||
440 | code {data->parentmixercontrol=p_parentmixercontrol;} {} | ||
441 | } | ||
442 | Function {parentui(MixerChannelUI* p_parentui)} {open return_type void | ||
443 | } { | ||
444 | code {data->parentui=p_parentui;} {} | ||
445 | } | ||
446 | Function {parentui()} {open return_type {MixerChannelUI*} | ||
447 | } { | ||
448 | code {return data->parentui;} {} | ||
449 | } | ||
450 | Function {parentmixercontrol()} {open return_type {MixerControl*} | ||
451 | } { | ||
452 | code {return data->parentmixercontrol;} {} | ||
453 | } | ||
454 | Function {panvalue(const double p_val)} {open | ||
455 | } { | ||
456 | code {data->panvalue=p_val; | ||
457 | data->parentui->mixpan->value(p_val); | ||
458 | data->parentui->mixpan->damage(); | ||
459 | data->parentui->mixpan->redraw();} {} | ||
460 | } | ||
461 | Function {panvalue()} {open return_type double | ||
462 | } { | ||
463 | code {return data->panvalue;} {} | ||
464 | } | ||
465 | Function {sample(int framenum,float samval)} {open | ||
466 | } { | ||
467 | code {if (data==NULL) return; | ||
468 | if ((data->sample)==NULL) return; | ||
469 | data->sample[framenum]=samval; | ||
470 | /*float q=1; | ||
471 | if (samval<0) { | ||
472 | q=-1; | ||
473 | } | ||
474 | if ((samval*q) > data->trackpeak) { | ||
475 | data->trackpeak=samval*q; | ||
476 | }*/} {} | ||
477 | } | ||
478 | Function {sample(int framenum)} {return_type float | ||
479 | } { | ||
480 | code {return data->sample[framenum];} {} | ||
481 | } | ||
482 | Function {getsample(stereosample* sam,int framenum)} {open return_type void | ||
483 | } { | ||
484 | code {float monosam=data->sample[framenum]; | ||
485 | |||
486 | if (data->bypass==1) | ||
487 | { | ||
488 | /* Bypass all mixer functions, just return the sample */ | ||
489 | sam->left=monosam/2; | ||
490 | sam->right=monosam/2; | ||
491 | return; | ||
492 | } | ||
493 | |||
494 | float panval; | ||
495 | if (data->enable_eq==1) { | ||
496 | int Q=1; | ||
497 | // FilterCell(unsigned long Unit, double Input, double Frequency, double Q, double Gain, unsigned long Type) | ||
498 | if (eq_on(0)==1 && (eq_gain(0)!=0)) monosam=FilterCell(0,monosam,eq_freq(0),Q,eq_gain(0),7); | ||
499 | if (eq_on(1)==1 && (eq_gain(1)!=0)) monosam=FilterCell(1,monosam,eq_freq(1),Q,eq_gain(1),7); | ||
500 | if (eq_on(2)==1 && (eq_gain(2)!=0)) monosam=FilterCell(2,monosam,eq_freq(2),Q,eq_gain(2),7); | ||
501 | if (eq_on(3)==1 && (eq_gain(3)!=0)) monosam=FilterCell(3,monosam,eq_freq(3),Q,eq_gain(3),7); | ||
502 | } | ||
503 | |||
504 | monosam*=getfadermult(); | ||
505 | |||
506 | sam->left=monosam; | ||
507 | sam->right=monosam; | ||
508 | |||
509 | if (data->enable_pan==1) | ||
510 | { | ||
511 | panval=panvalue(); | ||
512 | } else { | ||
513 | panval=0; | ||
514 | } | ||
515 | |||
516 | float pctright=(panval+127)/254; | ||
517 | float pctleft=1-pctright; | ||
518 | sam->left*=pctleft; | ||
519 | sam->right*=pctright; | ||
520 | |||
521 | float subsamval=fabs(monosam); | ||
522 | if (subsamval > trackpeak()) { | ||
523 | trackpeak(subsamval); | ||
524 | } | ||
525 | |||
526 | return;} {} | ||
527 | } | ||
528 | Function {channelselect(int select)} {return_type void | ||
529 | } { | ||
530 | code {data->selected=select; | ||
531 | parentui()->mixchsel->value(select); | ||
532 | parentui()->mixchsel->redraw();} {} | ||
533 | } | ||
534 | Function {FilterCell(unsigned long Unit, double Input, double Frequency, double Q, double Gain, unsigned long Type)} {return_type double | ||
535 | } { | ||
536 | code {__uint32 SampleRate=data->samplerate; | ||
537 | |||
538 | /* --------------------------------------------------------------- */ | ||
539 | double Output,S,omega,A,sn,cs,alpha,beta,temp1,temp2,temp3,temp4; | ||
540 | Output=Input; | ||
541 | |||
542 | /* -- check if frequency, Q, gain or type has changed.. and, if so, update coefficients */ | ||
543 | if ( ( Frequency != filter_f[Unit] ) || ( Gain != filter_g[Unit] ) || ( Q != filter_q[Unit] ) || ( Type != filter_t[Unit] ) ) { | ||
544 | filter_f[Unit] = Frequency; filter_q[Unit] = Q; filter_g[Unit] = Gain; filter_t[Unit] = Type; /* remember last frequency, q, gain and type */ | ||
545 | switch (Type) { | ||
546 | case 0: /* no filtering */ | ||
547 | filter_b0[Unit] = pow( 10.0, Gain / 20.0 ); /* convert from dB to linear */ | ||
548 | break; | ||
549 | case 1: /* lowpass */ | ||
550 | Gain = pow( 10.0, Gain / 20.0 ); /* convert from dB to linear */ | ||
551 | omega = ( Pi2 * Frequency ) / SampleRate; | ||
552 | sn = sin( omega ); cs = cos( omega ); | ||
553 | alpha = sn / ( 2.0 * Q ); | ||
554 | filter_a0[Unit] = 1.0 / ( 1.0 + alpha ); | ||
555 | filter_a1[Unit] = ( -2.0 * cs ) * filter_a0[Unit]; | ||
556 | filter_a2[Unit] = ( 1.0 - alpha ) * filter_a0[Unit]; | ||
557 | filter_b1[Unit] = ( 1.0 - cs ) * filter_a0[Unit] * Gain; | ||
558 | filter_b0[Unit] = filter_b1[Unit] * 0.5; | ||
559 | break; | ||
560 | case 2: /* highpass */ | ||
561 | Gain = pow( 10.0, Gain / 20.0 ); /* convert from dB to linear */ | ||
562 | omega = ( Pi2 * Frequency ) / SampleRate; | ||
563 | sn = sin( omega ); cs = cos( omega ); | ||
564 | alpha = sn / ( 2.0 * Q ); | ||
565 | filter_a0[Unit] = 1.0 / ( 1.0 + alpha ); | ||
566 | filter_a1[Unit] = ( -2.0 * cs ) * filter_a0[Unit]; | ||
567 | filter_a2[Unit] = ( 1.0 - alpha ) * filter_a0[Unit]; | ||
568 | filter_b1[Unit] = -( 1.0 + cs ) * filter_a0[Unit] * Gain; | ||
569 | filter_b0[Unit] = -filter_b1[Unit] * 0.5; | ||
570 | break; | ||
571 | case 3: /* bandpass */ | ||
572 | Gain = pow( 10.0, Gain / 20.0 ); /* convert from dB to linear */ | ||
573 | omega = ( Pi2 * Frequency ) / SampleRate; | ||
574 | sn = sin( omega ); cs = cos( omega ); | ||
575 | alpha = sn / ( 2.0 * Q ); | ||
576 | filter_a0[Unit] = 1.0 / ( 1.0 + alpha ); | ||
577 | filter_a1[Unit] = ( -2.0 * cs ) * filter_a0[Unit]; | ||
578 | filter_a2[Unit] = ( 1.0 - alpha ) * filter_a0[Unit]; | ||
579 | filter_b0[Unit] = alpha * filter_a0[Unit] * Gain; | ||
580 | break; | ||
581 | case 4: /* notch */ | ||
582 | Gain = pow( 10.0, Gain / 20.0 ); /* convert from dB to linear */ | ||
583 | omega = ( Pi2 * Frequency ) / SampleRate; | ||
584 | sn = sin( omega ); cs = cos( omega ); | ||
585 | alpha = sn / ( 2.0 * Q ); | ||
586 | filter_a0[Unit] = 1.0 / ( 1.0 + alpha ); | ||
587 | filter_a1[Unit] = ( -2.0 * cs ) * filter_a0[Unit]; | ||
588 | filter_a2[Unit] = ( 1.0 - alpha ) * filter_a0[Unit]; | ||
589 | filter_b0[Unit] = filter_a0[Unit] * Gain; | ||
590 | filter_b1[Unit] = filter_a1[Unit] * Gain; | ||
591 | break; | ||
592 | case 5: /* lowshelf */ | ||
593 | /* "shelf slope" 1.0 = max slope, because neither Q nor bandwidth is used in */ | ||
594 | /* those filters (note: true only for lowshelf and highshelf, not peaking). */ | ||
595 | S = 1.0; /* used only by lowshelf and highshelf */ | ||
596 | A = pow( 10.0 , ( Gain / 40.0 ) ); /* Gain is expressed in dB */ | ||
597 | omega = ( Pi2 * Frequency ) / SampleRate; | ||
598 | sn = sin( omega ); cs = cos( omega ); | ||
599 | temp1 = A + 1.0; temp2 = A - 1.0; temp3 = temp1 * cs; temp4 = temp2 * cs; | ||
600 | beta = sn * sqrt( ( A * A + 1.0 ) / S - temp2 * temp2 ); | ||
601 | filter_a0[Unit] = 1.0 / ( temp1 + temp4 + beta ); | ||
602 | filter_a1[Unit] = ( -2.0 * ( temp2 + temp3 ) ) * filter_a0[Unit]; | ||
603 | filter_a2[Unit] = ( temp1 + temp4 - beta ) * filter_a0[Unit]; | ||
604 | filter_b0[Unit] = ( A * ( temp1 - temp4 + beta ) ) * filter_a0[Unit]; | ||
605 | filter_b1[Unit] = ( 2.0 * A * ( temp2 - temp3 ) ) * filter_a0[Unit]; | ||
606 | filter_b2[Unit] = ( A * ( temp1 - temp4 - beta ) ) * filter_a0[Unit]; | ||
607 | break; | ||
608 | case 6: /* highshelf */ | ||
609 | /* "shelf slope" 1.0 = max slope, because neither Q nor bandwidth is used in */ | ||
610 | /* those filters (note: true only for lowshelf and highshelf, not peaking). */ | ||
611 | S = 1.0; /* used only by lowshelf and highshelf */ | ||
612 | A = pow( 10.0, ( Gain / 40.0 ) ); /* Gain is expressed in dB */ | ||
613 | omega = ( Pi2 * Frequency ) / SampleRate; | ||
614 | sn = sin( omega ); cs = cos( omega ); | ||
615 | temp1 = A + 1.0; temp2 = A - 1.0; temp3 = temp1 * cs; temp4 = temp2 * cs; | ||
616 | beta = sn * sqrt( ( A * A + 1.0 ) / S - temp2 * temp2 ); | ||
617 | filter_a0[Unit] = 1.0 / ( temp1 - temp4 + beta ); | ||
618 | filter_a1[Unit] = ( 2.0 * ( temp2 - temp3 ) ) * filter_a0[Unit]; | ||
619 | filter_a2[Unit] = ( temp1 - temp4 - beta ) * filter_a0[Unit]; | ||
620 | filter_b0[Unit] = ( A * ( temp1 + temp4 + beta ) ) * filter_a0[Unit]; | ||
621 | filter_b1[Unit] = ( -2.0 * A * ( temp2 + temp3 ) ) * filter_a0[Unit]; | ||
622 | filter_b2[Unit] = ( A * ( temp1 + temp4 - beta ) ) * filter_a0[Unit]; | ||
623 | break; | ||
624 | case 7: /* peaking */ | ||
625 | A = pow( 10.0, ( Gain / 40.0 ) ); /* Gain is expressed in dB */ | ||
626 | omega = ( Pi2 * Frequency ) / SampleRate; | ||
627 | sn = sin( omega ); cs = cos( omega ); | ||
628 | alpha = sn / ( 2.0 * Q ); | ||
629 | temp1 = alpha * A; | ||
630 | temp2 = alpha / A; | ||
631 | filter_a0[Unit] = 1.0 / ( 1.0 + temp2 ); | ||
632 | filter_a1[Unit] = ( -2.0 * cs ) * filter_a0[Unit]; | ||
633 | filter_a2[Unit] = ( 1.0 - temp2 ) * filter_a0[Unit]; | ||
634 | filter_b0[Unit] = ( 1.0 + temp1 ) * filter_a0[Unit]; | ||
635 | filter_b2[Unit] = ( 1.0 - temp1 ) * filter_a0[Unit]; | ||
636 | break; | ||
637 | } | ||
638 | } | ||
639 | /* -- filter loop: if you don't change the parameters of the filter dynamically, ~only this code will be executed. */ | ||
640 | switch (Type) { | ||
641 | case 0: /* no filtering */ | ||
642 | Output = filter_b0[Unit]*Input; | ||
643 | break; | ||
644 | case 1: /* lowpass */ | ||
645 | case 2: /* highpass */ | ||
646 | Output = filter_b0[Unit]*Input | ||
647 | + filter_b1[Unit]*filter_i1[Unit] | ||
648 | + filter_b0[Unit]*filter_i2[Unit] | ||
649 | - filter_a1[Unit]*filter_o1[Unit] | ||
650 | - filter_a2[Unit]*filter_o2[Unit]; | ||
651 | break; | ||
652 | case 3: /* bandpass */ | ||
653 | Output = filter_b0[Unit]*Input | ||
654 | - filter_b0[Unit]*filter_i2[Unit] | ||
655 | - filter_a1[Unit]*filter_o1[Unit] | ||
656 | - filter_a2[Unit]*filter_o2[Unit]; | ||
657 | break; | ||
658 | case 4: /* notch */ | ||
659 | Output = filter_b0[Unit]*Input | ||
660 | + filter_b1[Unit]*filter_i1[Unit] | ||
661 | + filter_b0[Unit]*filter_i2[Unit] | ||
662 | - filter_a1[Unit]*filter_o1[Unit] | ||
663 | - filter_a2[Unit]*filter_o2[Unit]; | ||
664 | break; | ||
665 | case 5: /* low shelving */ | ||
666 | case 6: /* high shelving */ | ||
667 | Output = filter_b0[Unit]*Input | ||
668 | + filter_b1[Unit]*filter_i1[Unit] | ||
669 | + filter_b2[Unit]*filter_i2[Unit] | ||
670 | - filter_a1[Unit]*filter_o1[Unit] | ||
671 | - filter_a2[Unit]*filter_o2[Unit]; | ||
672 | break; | ||
673 | case 7: /* peaking */ | ||
674 | Output = filter_b0[Unit]*Input | ||
675 | + filter_a1[Unit]*filter_i1[Unit] | ||
676 | + filter_b2[Unit]*filter_i2[Unit] | ||
677 | - filter_a1[Unit]*filter_o1[Unit] | ||
678 | - filter_a2[Unit]*filter_o2[Unit]; | ||
679 | break; | ||
680 | } | ||
681 | filter_o2[Unit]=filter_o1[Unit]; | ||
682 | filter_o1[Unit]=Output; | ||
683 | filter_i2[Unit]=filter_i1[Unit]; | ||
684 | filter_i1[Unit]=Input; /* update variables for recursion */ | ||
685 | |||
686 | return(Output);} {} | ||
687 | } | ||
688 | Function {eq_gain(int whicheq,double gain)} {open return_type void | ||
689 | } { | ||
690 | code {if (whicheq>4) return; | ||
691 | if (whicheq<0) return; | ||
692 | data->eq_gain[whicheq]=gain; | ||
693 | |||
694 | |||
695 | //cout << "set freq to "<<freq <<" for (base0)ch "<<channel_number()-1 << endl; | ||
696 | WidgetPDial* gainwidget=NULL; | ||
697 | Fl_Output* dispwidget=NULL; | ||
698 | switch (whicheq) { | ||
699 | case 0: | ||
700 | { | ||
701 | gainwidget=parentmixercontrol()->parentui()->gain1; | ||
702 | dispwidget=parentmixercontrol()->parentui()->dispgain1; | ||
703 | break; | ||
704 | } | ||
705 | case 1: | ||
706 | { | ||
707 | gainwidget=parentmixercontrol()->parentui()->gain2; | ||
708 | dispwidget=parentmixercontrol()->parentui()->dispgain2; | ||
709 | break; | ||
710 | } | ||
711 | case 2: | ||
712 | { | ||
713 | gainwidget=parentmixercontrol()->parentui()->gain3; | ||
714 | dispwidget=parentmixercontrol()->parentui()->dispgain3; | ||
715 | break; | ||
716 | } | ||
717 | case 3: | ||
718 | { | ||
719 | gainwidget=parentmixercontrol()->parentui()->gain4; | ||
720 | dispwidget=parentmixercontrol()->parentui()->dispgain4; | ||
721 | break; | ||
722 | } | ||
723 | } | ||
724 | if (dispwidget!=NULL) | ||
725 | { | ||
726 | string* sval=Convert::int64tostr((__sint64)gain); | ||
727 | dispwidget->value(sval->c_str()); | ||
728 | delete sval; | ||
729 | dispwidget->redraw(); | ||
730 | } | ||
731 | if (gainwidget!=NULL) | ||
732 | { | ||
733 | gainwidget->value(gain); | ||
734 | gainwidget->redraw(); | ||
735 | }} {} | ||
736 | } | ||
737 | Function {eq_gain(int whicheq)} {open return_type double | ||
738 | } { | ||
739 | code {if (whicheq>4) return 0; | ||
740 | if (whicheq<0) return 0; | ||
741 | return data->eq_gain[whicheq];} {} | ||
742 | } | ||
743 | Function {eq_freq(int whicheq,double freq)} {open return_type void | ||
744 | } { | ||
745 | code {if (whicheq>4) return; | ||
746 | if (whicheq<0) return; | ||
747 | data->eq_freq[whicheq]=freq; | ||
748 | //cout << "set freq to "<<freq <<" for (base0)ch "<<channel_number()-1 << endl; | ||
749 | WidgetPDial* freqwidget=NULL; | ||
750 | Fl_Output* dispwidget=NULL; | ||
751 | switch (whicheq) { | ||
752 | case 0: | ||
753 | { | ||
754 | freqwidget=parentmixercontrol()->parentui()->freq1; | ||
755 | dispwidget=parentmixercontrol()->parentui()->dispfreq1; | ||
756 | break; | ||
757 | } | ||
758 | case 1: | ||
759 | { | ||
760 | freqwidget=parentmixercontrol()->parentui()->freq2; | ||
761 | dispwidget=parentmixercontrol()->parentui()->dispfreq2; | ||
762 | break; | ||
763 | } | ||
764 | case 2: | ||
765 | { | ||
766 | freqwidget=parentmixercontrol()->parentui()->freq3; | ||
767 | dispwidget=parentmixercontrol()->parentui()->dispfreq3; | ||
768 | break; | ||
769 | } | ||
770 | case 3: | ||
771 | { | ||
772 | freqwidget=parentmixercontrol()->parentui()->freq4; | ||
773 | dispwidget=parentmixercontrol()->parentui()->dispfreq4; | ||
774 | break; | ||
775 | } | ||
776 | } | ||
777 | if (dispwidget!=NULL) | ||
778 | { | ||
779 | string* sval=Convert::int64tostr((__sint64)freq); | ||
780 | dispwidget->value(sval->c_str()); | ||
781 | delete sval; | ||
782 | dispwidget->redraw(); | ||
783 | } | ||
784 | if (freqwidget!=NULL) | ||
785 | { | ||
786 | freqwidget->value(freq); | ||
787 | freqwidget->redraw(); | ||
788 | }} {} | ||
789 | } | ||
790 | Function {eq_freq(int whicheq)} {return_type double | ||
791 | } { | ||
792 | code {if (whicheq>4) return 0; | ||
793 | if (whicheq<0) return 0; | ||
794 | return data->eq_freq[whicheq];} {} | ||
795 | } | ||
796 | Function {eq_on(int whicheq,int onoff)} {return_type void | ||
797 | } { | ||
798 | code {if (whicheq>4) return; | ||
799 | if (whicheq<0) return; | ||
800 | data->eq_on[whicheq]=onoff; | ||
801 | |||
802 | switch (whicheq) { | ||
803 | case 0: parentmixercontrol()->parentui()->eqon1->value(onoff); break; | ||
804 | case 1: parentmixercontrol()->parentui()->eqon2->value(onoff); break; | ||
805 | case 2: parentmixercontrol()->parentui()->eqon3->value(onoff); break; | ||
806 | case 3: parentmixercontrol()->parentui()->eqon4->value(onoff); break; | ||
807 | } | ||
808 | parentmixercontrol()->parentui()->eqon1->redraw(); | ||
809 | parentmixercontrol()->parentui()->eqon2->redraw(); | ||
810 | parentmixercontrol()->parentui()->eqon3->redraw(); | ||
811 | parentmixercontrol()->parentui()->eqon4->redraw();} {} | ||
812 | } | ||
813 | Function {eq_on(int whicheq)} {return_type int | ||
814 | } { | ||
815 | code {if (whicheq>4) return 0; | ||
816 | if (whicheq<0) return 0; | ||
817 | return data->eq_on[whicheq];} {} | ||
818 | } | ||
819 | Function {eq_Q(int whicheq,double Q)} {return_type void | ||
820 | } { | ||
821 | code {if (whicheq>4) return; | ||
822 | if (whicheq<0) return; | ||
823 | data->eq_Q[whicheq]=Q; | ||
824 | //cout << "set freq to "<<freq <<" for (base0)ch "<<channel_number()-1 << endl; | ||
825 | |||
826 | //switch (whicheq) { | ||
827 | // case 0: parentmixercontrol()->parentui()->Q1->value(freq); break; | ||
828 | // case 1: parentmixercontrol()->parentui()->Q2->value(freq); break; | ||
829 | // case 2: parentmixercontrol()->parentui()->Q3->value(freq); break; | ||
830 | // case 3: parentmixercontrol()->parentui()->Q4->value(freq); break; | ||
831 | //} | ||
832 | //parentmixercontrol()->parentui()->freq1->redraw(); | ||
833 | //parentmixercontrol()->parentui()->freq2->redraw(); | ||
834 | //parentmixercontrol()->parentui()->freq3->redraw(); | ||
835 | //parentmixercontrol()->parentui()->freq4->redraw();} {} | ||
836 | } | ||
837 | Function {eq_Q(int whicheq)} {return_type double | ||
838 | } { | ||
839 | code {if (whicheq>4) return 0; | ||
840 | if (whicheq<0) return 0; | ||
841 | return data->eq_Q[whicheq];} {} | ||
842 | } | ||
843 | decl {double filter_i1[eqperchan]; /* temporary variables */} {} | ||
844 | decl {double filter_i2[eqperchan];} {} | ||
845 | decl {double filter_o1[eqperchan];} {} | ||
846 | decl {double filter_o2[eqperchan];} {} | ||
847 | decl {double filter_a0[eqperchan]; /*coefficients */} {} | ||
848 | decl {double filter_a1[eqperchan];} {} | ||
849 | decl {double filter_a2[eqperchan];} {} | ||
850 | decl {double filter_b0[eqperchan]; /*coefficients */} {} | ||
851 | decl {double filter_b1[eqperchan];} {} | ||
852 | decl {double filter_b2[eqperchan];} {} | ||
853 | decl {double filter_f[eqperchan]; /* last freq used */} {} | ||
854 | decl {double filter_q[eqperchan]; /* last Q used */} {} | ||
855 | decl {double filter_g[eqperchan]; /* last gain used */} {} | ||
856 | decl {unsigned long filter_t[eqperchan]; /* last T used */} {} | ||
857 | Function {pan_enabled(int yesno)} {open return_type void | ||
858 | } { | ||
859 | code {data->enable_pan=yesno;} {} | ||
860 | } | ||
861 | Function {pan_enabled()} {open return_type int | ||
862 | } { | ||
863 | code {return data->enable_pan;} {} | ||
864 | } | ||
865 | Function {eq_enabled(int yesno)} {return_type void | ||
866 | } { | ||
867 | code {data->enable_eq=yesno;} {} | ||
868 | } | ||
869 | Function {eq_enabled()} {open return_type int | ||
870 | } { | ||
871 | code {return data->enable_eq;} {} | ||
872 | } | ||
873 | Function {bypass(int yesno)} {open return_type void | ||
874 | } { | ||
875 | code {data->bypass=yesno;} {} | ||
876 | } | ||
877 | Function {bypass()} {open return_type int | ||
878 | } { | ||
879 | code {return data->bypass;} {} | ||
880 | } | ||
881 | Function {samplerate(__uint32 p_samplerate)} {open return_type void | ||
882 | } { | ||
883 | code {data->samplerate=p_samplerate;} {} | ||
884 | } | ||
885 | Function {samplerate()} {open return_type __uint32 | ||
886 | } { | ||
887 | code {return data->samplerate;} {} | ||
888 | } | ||
889 | } | ||
890 | |||
891 | class MixerChannelUI {open : {public Fl_Group} | ||
892 | } { | ||
893 | decl {MixerChannelControl* control;} {public | ||
894 | } | ||
895 | Function {MixerChannelUI(int a,int b,int c,int d,const char* e):Fl_Group(a,b,c,d,e)} {open | ||
896 | } { | ||
897 | code {init_ui();} {} | ||
898 | } | ||
899 | Function {MixerChannelUI(int a,int b,int c,int d):Fl_Group(a,b,c,d,NULL)} {open | ||
900 | } { | ||
901 | code {init_ui();} {} | ||
902 | } | ||
903 | Function {init_ui()} {open private | ||
904 | } { | ||
905 | code {this->control=new MixerChannelControl(); | ||
906 | this->control->parentui(this); | ||
907 | make_window();} {} | ||
908 | } | ||
909 | Function {make_window()} {open | ||
910 | } { | ||
911 | Fl_Window channelstrip {open | ||
912 | xywh {698 377 20 235} type Double | ||
913 | code0 {o->position(this->x(),this->y());} | ||
914 | class Fl_Group visible | ||
915 | } { | ||
916 | Fl_Group resources {open | ||
917 | xywh {80 62 150 98} hide deactivate | ||
918 | } { | ||
919 | Fl_Button button_mute_up { | ||
920 | tooltip Play image {images/button_mute.gif} xywh {80 62 5 13} labelsize 11 align 16 deactivate | ||
921 | } | ||
922 | Fl_Button button_mute_dn { | ||
923 | tooltip Play image {images/button_mute_dn.gif} xywh {85 62 35 13} labelsize 11 align 16 deactivate | ||
924 | } | ||
925 | Fl_Button button_solo_up { | ||
926 | tooltip Play image {images/button_solo.gif} xywh {80 62 5 13} labelsize 11 align 16 deactivate | ||
927 | } | ||
928 | Fl_Button button_solo_dn { | ||
929 | tooltip Play image {images/button_solo_dn.gif} xywh {85 62 45 13} labelsize 11 align 16 deactivate | ||
930 | } | ||
931 | } | ||
932 | Fl_Button mixmute { | ||
933 | label 1 | ||
934 | callback {//mute(0,o->value()); | ||
935 | this->control->mute(o->value());} | ||
936 | tooltip Mute xywh {0 65 20 15} selection_color 1 labelfont 1 labelsize 10 align 2 | ||
937 | code0 {o->up_image(button_mute_up->image()); o->down_image(button_mute_dn->image());} | ||
938 | class Fl_Image_Toggle_Button | ||
939 | } | ||
940 | Fl_Button mixsolo { | ||
941 | callback {this->control->solo(o->value());} | ||
942 | tooltip Solo xywh {0 45 20 15} selection_color 2 | ||
943 | code0 {o->up_image(button_solo_up->image()); o->down_image(button_solo_dn->image());} | ||
944 | class Fl_Image_Toggle_Button | ||
945 | } | ||
946 | Fl_Dial mixpan { | ||
947 | callback {control->panvalue(o->value());} | ||
948 | xywh {0 25 20 20} minimum -127 maximum 127 step 1 | ||
949 | class WidgetPDial | ||
950 | } | ||
951 | Fl_Round_Button mixchsel { | ||
952 | callback {this->control->parentmixercontrol()->selectedchannel(this->control->channel_number()-1);} | ||
953 | xywh {0 0 15 20} down_box ROUND_DOWN_BOX align 2 | ||
954 | } | ||
955 | Fl_Group mixled {open | ||
956 | xywh {18 93 4 132} | ||
957 | class MixerLevelMeterUI | ||
958 | } {} | ||
959 | Fl_Slider fader { | ||
960 | callback {control->fadervalue(o->value());} | ||
961 | image {images/fader.gif} xywh {0 92 18 128} type {Vert Knob} color 8 labelfont 1 labelsize 10 align 0 minimum 127 maximum 0 step 1 value 90 | ||
962 | code0 {o->clear_visible_focus();} | ||
963 | } | ||
964 | } | ||
965 | } | ||
966 | Function {~MixerChannelUI()} {open | ||
967 | } { | ||
968 | code {delete control;} {} | ||
969 | } | ||
970 | } | ||
971 | |||
972 | class MasterChannelData {open | ||
973 | } { | ||
974 | decl {friend class MasterChannelUI;} {} | ||
975 | decl {friend class MasterChannelControl;} {} | ||
976 | decl {MasterChannelUI* parentui;} {} | ||
977 | decl {double trackpeak[2];} {public | ||
978 | } | ||
979 | decl {int eq_on[eqperchan];} {public | ||
980 | } | ||
981 | decl {double eq_gain[eqperchan];} {public | ||
982 | } | ||
983 | decl {double eq_freq[eqperchan];} {public | ||
984 | } | ||
985 | decl {double eq_Q[eqperchan];} {public | ||
986 | } | ||
987 | decl {double eq_type[eqperchan];} {public | ||
988 | } | ||
989 | decl {double fadermult[2];} {public | ||
990 | } | ||
991 | decl {double fadervalue;} {public | ||
992 | } | ||
993 | decl {double panvalue;} {public | ||
994 | } | ||
995 | decl {float* delaybuffer;} {} | ||
996 | decl {long delaybuffersize;} {public | ||
997 | } | ||
998 | decl {long delaybuffersam;} {public | ||
999 | } | ||
1000 | decl {int solo;} {} | ||
1001 | decl {int mute;} {} | ||
1002 | decl {int ch_number;} {} | ||
1003 | decl {char strchnum[4];} {} | ||
1004 | decl {float* sample;} {public | ||
1005 | } | ||
1006 | decl {int mixmono;} {} | ||
1007 | } | ||
1008 | |||
1009 | class MasterChannelControl {open | ||
1010 | } { | ||
1011 | decl {friend class MasterChannelUI;} {} | ||
1012 | Function {init()} {open return_type void | ||
1013 | } { | ||
1014 | code {data->solo=0; | ||
1015 | data->mute=0; | ||
1016 | data->mixmono=0; | ||
1017 | data->sample=(float *)malloc(24000*sizeof(float)); | ||
1018 | data->trackpeak[0]=0; | ||
1019 | data->trackpeak[1]=0; | ||
1020 | data->fadermult[0]=1; | ||
1021 | data->fadermult[1]=1; | ||
1022 | data->panvalue=0; | ||
1023 | data->fadervalue=90; | ||
1024 | return;} {} | ||
1025 | } | ||
1026 | decl {MasterChannelData* data;} {} | ||
1027 | Function {MasterChannelControl()} {open | ||
1028 | } { | ||
1029 | code {data=new MasterChannelData; | ||
1030 | init();} {} | ||
1031 | } | ||
1032 | Function {~MasterChannelControl()} {open | ||
1033 | } { | ||
1034 | code {free (data->sample); | ||
1035 | delete data;} {} | ||
1036 | } | ||
1037 | Function {fadervalue(const double p_val)} {open | ||
1038 | } { | ||
1039 | code {double lin; | ||
1040 | if (p_val == 0) { | ||
1041 | lin=0; | ||
1042 | } else { | ||
1043 | lin=pow(10,(p_val-90)/60); | ||
1044 | } | ||
1045 | data->fadermult[0]=lin; | ||
1046 | data->fadermult[1]=lin; | ||
1047 | data->fadervalue=p_val; | ||
1048 | data->parentui->redraw(); | ||
1049 | //faderarray[channel]=lin; | ||
1050 | //mixmute[channel]->draw(); | ||
1051 | //mixfader[channel]->draw(); | ||
1052 | //mixled[channel]->draw(); | ||
1053 | //masterled[0]->draw(); | ||
1054 | //masterled[1]->draw(); | ||
1055 | //this->redraw();*/} {} | ||
1056 | } | ||
1057 | Function {fadervalue()} {open return_type double | ||
1058 | } { | ||
1059 | code {return data->fadervalue;} {} | ||
1060 | } | ||
1061 | Function {updatemeters()} {open return_type void | ||
1062 | } { | ||
1063 | code {// update and redraw meterlevels object | ||
1064 | this->parentui()->mixledleft->control->setvalue(data->trackpeak[0]); | ||
1065 | this->parentui()->mixledright->control->setvalue(data->trackpeak[1]); | ||
1066 | |||
1067 | this->parentui()->mixledleft->redraw(); | ||
1068 | this->parentui()->mixledright->redraw(); | ||
1069 | // then, reset peak value | ||
1070 | trackpeak(0,0); | ||
1071 | trackpeak(1,0);} {} | ||
1072 | } | ||
1073 | Function {trackpeak(int lr)} {open return_type double | ||
1074 | } { | ||
1075 | code {return data->trackpeak[lr];} {} | ||
1076 | } | ||
1077 | Function {trackpeak(int lr,double peakval)} {open return_type void | ||
1078 | } { | ||
1079 | code {data->trackpeak[lr]=peakval;} {} | ||
1080 | } | ||
1081 | Function {parentui(MasterChannelUI* p_parentui)} {open return_type void | ||
1082 | } { | ||
1083 | code {data->parentui=p_parentui;} {} | ||
1084 | } | ||
1085 | Function {parentui()} {open return_type {MasterChannelUI*} | ||
1086 | } { | ||
1087 | code {return data->parentui;} {} | ||
1088 | } | ||
1089 | Function {sample(int framenum,float samval)} {open | ||
1090 | } { | ||
1091 | code {data->sample[framenum]=samval; | ||
1092 | /*float q=1; | ||
1093 | if (samval<0) { | ||
1094 | q=-1; | ||
1095 | } | ||
1096 | if ((samval*q) > data->trackpeak) { | ||
1097 | data->trackpeak=samval*q; | ||
1098 | }*/} {} | ||
1099 | } | ||
1100 | Function {sample(int framenum)} {open return_type float | ||
1101 | } { | ||
1102 | code {return data->sample[framenum];} {} | ||
1103 | } | ||
1104 | Function {getfadermult(int lr)} {open return_type double | ||
1105 | } { | ||
1106 | code {return data->fadermult[lr];} {} | ||
1107 | } | ||
1108 | Function {mixmono(int inval)} {open return_type void | ||
1109 | } { | ||
1110 | code {data->mixmono=inval; | ||
1111 | parentui()->mix_mono->value(inval); | ||
1112 | parentui()->mix_mono->redraw();} {} | ||
1113 | } | ||
1114 | Function {mixmono()} {open return_type int | ||
1115 | } { | ||
1116 | code {return data->mixmono;} {} | ||
1117 | } | ||
1118 | } | ||
1119 | |||
1120 | class MasterChannelUI {open : {public Fl_Group} | ||
1121 | } { | ||
1122 | decl {MasterChannelControl* control;} {public | ||
1123 | } | ||
1124 | Function {MasterChannelUI(int a,int b,int c,int d,const char* e):Fl_Group(a,b,c,d,e)} {open | ||
1125 | } { | ||
1126 | code {init_ui();} {} | ||
1127 | } | ||
1128 | Function {MasterChannelUI(int a,int b,int c,int d):Fl_Group(a,b,c,d,NULL)} {open | ||
1129 | } { | ||
1130 | code {init_ui();} {} | ||
1131 | } | ||
1132 | Function {init_ui()} {open private | ||
1133 | } { | ||
1134 | code {this->control=new MasterChannelControl(); | ||
1135 | this->control->parentui(this); | ||
1136 | make_window();} {} | ||
1137 | } | ||
1138 | Function {make_window()} {open | ||
1139 | } { | ||
1140 | Fl_Window channelstrip {open | ||
1141 | xywh {889 373 30 235} type Double | ||
1142 | code0 {o->position(this->x(),this->y());} | ||
1143 | class Fl_Group visible | ||
1144 | } { | ||
1145 | Fl_Group mixledleft {open | ||
1146 | xywh {2 92 4 132} | ||
1147 | class MixerLevelMeterUI | ||
1148 | } {} | ||
1149 | Fl_Group mixledright {open | ||
1150 | xywh {24 92 4 132} | ||
1151 | class MixerLevelMeterUI | ||
1152 | } {} | ||
1153 | Fl_Slider fader { | ||
1154 | callback {control->fadervalue(o->value());} | ||
1155 | image {images/fader.gif} xywh {6 92 18 128} type {Vert Knob} color 8 labelfont 1 labelsize 10 align 0 minimum 127 maximum 0 step 1 value 90 | ||
1156 | code0 {o->clear_visible_focus();} | ||
1157 | } | ||
1158 | Fl_Button mix_mono { | ||
1159 | label MONO | ||
1160 | callback {control->mixmono(o->value());} | ||
1161 | xywh {0 68 30 15} type Toggle selection_color 3 labelsize 8 | ||
1162 | code0 {o->clear_visible_focus();} | ||
1163 | } | ||
1164 | } | ||
1165 | } | ||
1166 | Function {~MasterChannelUI()} {open | ||
1167 | } { | ||
1168 | code {delete control;} {} | ||
1169 | } | ||
1170 | } | ||
1171 | |||
1172 | class MixerData {open | ||
1173 | } { | ||
1174 | decl {MixerUI* parentui;} {} | ||
1175 | decl {friend class MixerControl;} {} | ||
1176 | decl {int eqon;} {} | ||
1177 | decl {float* mixermasterout;} {public | ||
1178 | } | ||
1179 | decl {double trackpeak[2];} {public | ||
1180 | } | ||
1181 | decl {double fadermult[2];} {public | ||
1182 | } | ||
1183 | decl {__uint32 samplerate;} {public | ||
1184 | } | ||
1185 | decl {int selectedchannel;} {public | ||
1186 | } | ||
1187 | decl {double fadervalue;} {public | ||
1188 | } | ||
1189 | decl {__uint32 delaybuffersam;} {public | ||
1190 | } | ||
1191 | decl {int bypass;} {} | ||
1192 | } | ||
1193 | |||
1194 | class MixerControl {open | ||
1195 | } { | ||
1196 | decl {friend class MixerUI;} {} | ||
1197 | decl {MixerData* data;} {} | ||
1198 | Function {mix(int frames) /* <----------------------------------*/} {open | ||
1199 | } { | ||
1200 | code {int solo=0; | ||
1201 | int trackon[24]; // 0=mute, 1=normal, 2=solo | ||
1202 | MixerChannelControl* trackctl[24]; | ||
1203 | for (int tracknum=0;tracknum<24;tracknum++) { | ||
1204 | trackctl[tracknum]=parentui()->mixerchannel[tracknum]->control; | ||
1205 | trackon[tracknum]=1; // normal | ||
1206 | MixerChannelControl* track=trackctl[tracknum]; | ||
1207 | if (track->issolo()!=0) { | ||
1208 | solo=1; | ||
1209 | trackon[tracknum]++; | ||
1210 | } | ||
1211 | if (track->ismute()!=0) { | ||
1212 | trackon[tracknum]--; | ||
1213 | } | ||
1214 | track->eq_enabled(data->eqon); | ||
1215 | track->pan_enabled(1-(parentui()->fader_master->control->mixmono())); | ||
1216 | track->bypass(data->bypass); | ||
1217 | } | ||
1218 | |||
1219 | stereosample sam; | ||
1220 | for (int i=0;i<frames;i++) { | ||
1221 | float outleft=0; | ||
1222 | float outright=0; | ||
1223 | |||
1224 | |||
1225 | for (int j=0;j<24 /* tracks */;j++) { | ||
1226 | if (!(trackon[j]>solo)) continue; | ||
1227 | MixerChannelControl* track=trackctl[j]; | ||
1228 | |||
1229 | track->getsample(&sam,i); | ||
1230 | |||
1231 | outleft+=sam.left; | ||
1232 | outright+=sam.right; | ||
1233 | } | ||
1234 | outleft*=parentui()->fader_master->control->getfadermult(0); | ||
1235 | outright*=parentui()->fader_master->control->getfadermult(1); | ||
1236 | |||
1237 | /* clipping */ | ||
1238 | if (outleft>1) { | ||
1239 | outleft=1; } | ||
1240 | else { | ||
1241 | if (outleft<-1) outleft=-1; | ||
1242 | } | ||
1243 | if (outright>1) { | ||
1244 | outright=1; | ||
1245 | } else { | ||
1246 | if (outright<-1) outright=-1; | ||
1247 | } | ||
1248 | |||
1249 | |||
1250 | if (fabs(outleft) > parentui()->fader_master->control->trackpeak(0)) { | ||
1251 | parentui()->fader_master->control->trackpeak(0,fabs(outleft)); | ||
1252 | } | ||
1253 | if (fabs(outright) > parentui()->fader_master->control->trackpeak(1)) { | ||
1254 | parentui()->fader_master->control->trackpeak(1,fabs(outright)); | ||
1255 | } | ||
1256 | |||
1257 | /* / tape saturation emulation | ||
1258 | if (parentui()->tapesaton->value()==1) | ||
1259 | { | ||
1260 | int tapewidth=100; | ||
1261 | float myleft=0; | ||
1262 | float myright=0; | ||
1263 | for (int tapepos=0;tapepos<tapewidth;tapepos++) | ||
1264 | { | ||
1265 | float maxleft=.3+( ((rand()%32767)-16384)/(16384*5) ); | ||
1266 | float maxright=.3+( ((rand()%32767)-16384)/(16384*5) ); | ||
1267 | if (outleft>maxleft) { | ||
1268 | myleft+=maxleft; | ||
1269 | } else { | ||
1270 | myleft+=outleft; | ||
1271 | } | ||
1272 | if (outright>maxright) { | ||
1273 | myright+=maxright; | ||
1274 | } else { | ||
1275 | myright+=outright; | ||
1276 | } | ||
1277 | } | ||
1278 | outleft=myleft/tapewidth; | ||
1279 | outright=myright/tapewidth; | ||
1280 | } */ | ||
1281 | data->mixermasterout[i*25+0]=outleft; | ||
1282 | data->mixermasterout[i*25+1]=outright; | ||
1283 | }} {} | ||
1284 | } | ||
1285 | Function {init()} {open return_type void | ||
1286 | } { | ||
1287 | code {data->eqon=1; | ||
1288 | data->mixermasterout=(float *)malloc(512000*sizeof(float)); | ||
1289 | data->parentui=NULL; | ||
1290 | data->selectedchannel=0; | ||
1291 | data->bypass=1; | ||
1292 | |||
1293 | return;} {} | ||
1294 | } | ||
1295 | Function {MixerControl()} {} { | ||
1296 | code {data=new MixerData(); | ||
1297 | data->parentui=NULL; | ||
1298 | data->samplerate=0; | ||
1299 | init();} {} | ||
1300 | } | ||
1301 | Function {~MixerControl()} {} { | ||
1302 | code {free (data->mixermasterout); | ||
1303 | |||
1304 | //delaybuffersize=maxreverbunits*maxreverbseconds*MAXSAMRATE; | ||
1305 | //delaybuffer=(float *)malloc(sizeof(float)*delaybuffersize); | ||
1306 | //if (delaybuffer==NULL) cout << " out of mem L" << endl; | ||
1307 | //delaybuffersam=delaybuffersize; | ||
1308 | //for (int i=0;i<delaybuffersize;i++) | ||
1309 | //{ | ||
1310 | // delaybuffer[i]=0; | ||
1311 | //} | ||
1312 | delete data;} {} | ||
1313 | } | ||
1314 | Function {parentui(MixerUI* p_parentui)} {return_type void | ||
1315 | } { | ||
1316 | code {data->parentui=p_parentui;} {} | ||
1317 | } | ||
1318 | Function {parentui()} {return_type {MixerUI*} | ||
1319 | } { | ||
1320 | code {return data->parentui;} {} | ||
1321 | } | ||
1322 | Function {fadervalue(const double p_val)} {} { | ||
1323 | code {double lin; | ||
1324 | if (p_val == 0) { | ||
1325 | lin=0; | ||
1326 | } else { | ||
1327 | lin=pow(10,(p_val-90)/60); | ||
1328 | } | ||
1329 | data->fadermult[0]=lin; | ||
1330 | data->fadermult[1]=lin; | ||
1331 | data->fadervalue=p_val; | ||
1332 | //faderarray[channel]=lin; | ||
1333 | //mixmute[channel]->draw(); | ||
1334 | //mixfader[channel]->draw(); | ||
1335 | //mixled[channel]->draw(); | ||
1336 | //masterled[0]->draw(); | ||
1337 | //masterled[1]->draw(); | ||
1338 | parentui()->fader_master->fader->value(p_val); | ||
1339 | parentui()->fader_master->redraw(); //this->redraw();*/} {} | ||
1340 | } | ||
1341 | Function {fadervalue()} {return_type double | ||
1342 | } { | ||
1343 | code {return data->fadervalue;} {} | ||
1344 | } | ||
1345 | Function {trackpeak(int lr)} {return_type double | ||
1346 | } { | ||
1347 | code {return data->trackpeak[lr];} {} | ||
1348 | } | ||
1349 | Function {trackpeak(int lr,double peakval)} {return_type void | ||
1350 | } { | ||
1351 | code {data->trackpeak[lr]=peakval;} {} | ||
1352 | } | ||
1353 | Function {masterout(int tracknum,int framenum)} {return_type float | ||
1354 | } { | ||
1355 | code {return data->mixermasterout[framenum*25+tracknum];} {} | ||
1356 | } | ||
1357 | Function {lin2dB(double lin)} {return_type double | ||
1358 | } { | ||
1359 | code {return log10(lin)*20.0;} {} | ||
1360 | } | ||
1361 | Function {dB2lin(double dB)} {return_type double | ||
1362 | } { | ||
1363 | code {return pow(10.0,dB/20.0);} {} | ||
1364 | } | ||
1365 | Function {selectedchannel(int channel_base0)} {return_type void | ||
1366 | } { | ||
1367 | code {data->selectedchannel=channel_base0; | ||
1368 | for (int i=0;i<24;i++) { | ||
1369 | if (channel_base0!=i) { | ||
1370 | this->parentui()->mixerchannel[i]->control->channelselect(0); | ||
1371 | } else { | ||
1372 | this->parentui()->mixerchannel[i]->control->channelselect(1); | ||
1373 | } | ||
1374 | } | ||
1375 | MixerChannelControl* mixcontrol=this->parentui()->mixerchannel[channel_base0]->control; | ||
1376 | |||
1377 | // reloading controls with their own value causes a redraw. | ||
1378 | mixcontrol->eq_gain(0,mixcontrol->eq_gain(0)); | ||
1379 | mixcontrol->eq_gain(1,mixcontrol->eq_gain(1)); | ||
1380 | mixcontrol->eq_gain(2,mixcontrol->eq_gain(2)); | ||
1381 | mixcontrol->eq_gain(3,mixcontrol->eq_gain(3)); | ||
1382 | |||
1383 | mixcontrol->eq_freq(0,mixcontrol->eq_freq(0)); | ||
1384 | mixcontrol->eq_freq(1,mixcontrol->eq_freq(1)); | ||
1385 | mixcontrol->eq_freq(2,mixcontrol->eq_freq(2)); | ||
1386 | mixcontrol->eq_freq(3,mixcontrol->eq_freq(3)); | ||
1387 | |||
1388 | mixcontrol->eq_on(0,mixcontrol->eq_on(0)); | ||
1389 | mixcontrol->eq_on(1,mixcontrol->eq_on(1)); | ||
1390 | mixcontrol->eq_on(2,mixcontrol->eq_on(2)); | ||
1391 | mixcontrol->eq_on(3,mixcontrol->eq_on(3));} {} | ||
1392 | } | ||
1393 | Function {selectedchannel()} {return_type int | ||
1394 | } { | ||
1395 | code {return data->selectedchannel;} {} | ||
1396 | } | ||
1397 | Function {savemix(string* strfile)} {return_type {string*} | ||
1398 | } { | ||
1399 | code {fstream to_out(strfile->c_str(),ios::out); | ||
1400 | if (to_out==NULL) { | ||
1401 | string *error=new string(""); | ||
1402 | *error+="Cannot open mix file for writing."; | ||
1403 | return error; | ||
1404 | } | ||
1405 | |||
1406 | for (int i=0;i<24;i++) { | ||
1407 | MixerChannelControl* track=parentui()->mixerchannel[i]->control; | ||
1408 | to_out << "[Track="<<i+1<<"]" <<endl; | ||
1409 | to_out << "solo=" << track->solo() << endl; | ||
1410 | to_out << "mute=" << track->mute() << endl; | ||
1411 | to_out << "fader=" << track->fadervalue() << endl; | ||
1412 | to_out << "pan=" << track->panvalue() << endl; | ||
1413 | |||
1414 | for (int j=0;j<eqperchan;j++) { | ||
1415 | to_out << "eq_on[" << j << "]=" << track->eq_on(j) << endl; | ||
1416 | to_out << "eq_freq[" << j << "]=" << track->eq_freq(j) << endl; | ||
1417 | to_out << "eq_gain[" << j << "]=" << track->eq_gain(j) << endl; | ||
1418 | to_out << "eq_Q[" << j << "]=" << track->eq_Q(j) << endl; | ||
1419 | |||
1420 | } | ||
1421 | } | ||
1422 | to_out << "[Master]" << endl; | ||
1423 | to_out << "eqon=" << eq_on() << endl; | ||
1424 | to_out << "mono=" << parentui()->fader_master->control->mixmono() << endl; | ||
1425 | to_out << "fader=" << parentui()->fader_master->control->fadervalue()<< endl; | ||
1426 | |||
1427 | to_out.flush(); | ||
1428 | to_out.close(); | ||
1429 | return NULL;} {} | ||
1430 | } | ||
1431 | Function {savetrackmix(string* strfile,int base0track)} {return_type {string*} | ||
1432 | } { | ||
1433 | code {fstream to_out(strfile->c_str(),ios::out); | ||
1434 | if (to_out==NULL) { | ||
1435 | string *error=new string(""); | ||
1436 | *error+="Cannot open mix file for writing."; | ||
1437 | return error; | ||
1438 | } | ||
1439 | |||
1440 | int i=base0track; | ||
1441 | |||
1442 | MixerChannelControl* track=parentui()->mixerchannel[i]->control; | ||
1443 | to_out << "[Track="<<i+1<<"]" <<endl; | ||
1444 | to_out << "solo=" << track->solo() << endl; | ||
1445 | to_out << "mute=" << track->mute() << endl; | ||
1446 | to_out << "fader=" << track->fadervalue() << endl; | ||
1447 | to_out << "pan=" << track->panvalue() << endl; | ||
1448 | |||
1449 | for (int j=0;j<eqperchan;j++) { | ||
1450 | to_out << "eq_on[" << j << "]=" << track->eq_on(j) << endl; | ||
1451 | to_out << "eq_freq[" << j << "]=" << track->eq_freq(j) << endl; | ||
1452 | to_out << "eq_gain[" << j << "]=" << track->eq_gain(j) << endl; | ||
1453 | to_out << "eq_Q[" << j << "]=" << track->eq_Q(j) << endl; | ||
1454 | |||
1455 | } | ||
1456 | |||
1457 | to_out.flush(); | ||
1458 | to_out.close(); | ||
1459 | return NULL;} {} | ||
1460 | } | ||
1461 | Function {loadmix(string* strfile)} {return_type {string*} | ||
1462 | } { | ||
1463 | code {fstream from_in(strfile->c_str(),ios::in); | ||
1464 | if (from_in==NULL) { | ||
1465 | string *error=new string(""); | ||
1466 | *error+="Cannot open mix file for writing."; | ||
1467 | return error; | ||
1468 | } | ||
1469 | string line; | ||
1470 | int savechan=selectedchannel(); | ||
1471 | bool master=false; | ||
1472 | while (!(from_in.eof())) | ||
1473 | { | ||
1474 | getline(from_in,line); | ||
1475 | if (line=="") continue; | ||
1476 | if (line.substr(0,7)=="[Track=") { | ||
1477 | master=false; | ||
1478 | int ch=Convert::str2long(line.substr(7,2)); | ||
1479 | this->selectedchannel(ch-1); | ||
1480 | continue; | ||
1481 | } | ||
1482 | MixerChannelControl* track=parentui()->mixerchannel[selectedchannel()]->control; | ||
1483 | if (line.substr(0,8)=="[Master]") { | ||
1484 | master=true; | ||
1485 | continue; | ||
1486 | } | ||
1487 | if (master) { | ||
1488 | if (line.substr(0,5)=="mono=") { | ||
1489 | parentui()->fader_master->control->mixmono(Convert::str2long(line.substr(5,1))); | ||
1490 | continue; | ||
1491 | } | ||
1492 | if (line.substr(0,5)=="eqon=") { | ||
1493 | this->eq_on(Convert::str2long(line.substr(5,1))); | ||
1494 | continue; | ||
1495 | } | ||
1496 | } | ||
1497 | if (line.substr(0,5)=="solo=") { | ||
1498 | // mixsolo[this->selectedchannel]->value(Convert::str2long(line.substr(5,1))); | ||
1499 | track->solo(Convert::str2long(line.substr(5,1))); | ||
1500 | continue; | ||
1501 | } | ||
1502 | if (line.substr(0,5)=="mute=") { | ||
1503 | // mixmute[this->selectedchannel]->value(Convert::str2long(line.substr(5,1))); | ||
1504 | track->mute(Convert::str2long(line.substr(5,1))); | ||
1505 | continue; | ||
1506 | } | ||
1507 | if (line.substr(0,4)=="pan=") { | ||
1508 | track->panvalue(Convert::str2dbl(line.substr(4,10))); | ||
1509 | continue; | ||
1510 | } | ||
1511 | if ((line.substr(0,8)=="eq_freq[") | ||
1512 | &&(line.substr(9,2)=="]=")) | ||
1513 | { | ||
1514 | int whicheq=Convert::str2long(line.substr(8,1)); | ||
1515 | double freq=Convert::str2dbl(line.substr(11,10)); | ||
1516 | track->eq_freq(whicheq,freq); | ||
1517 | continue; | ||
1518 | |||
1519 | } | ||
1520 | if ((line.substr(0,8)=="eq_gain[") | ||
1521 | &&(line.substr(9,2)=="]=")) | ||
1522 | { | ||
1523 | int whicheq=Convert::str2long(line.substr(8,1)); | ||
1524 | double gain=Convert::str2dbl(line.substr(11,10)); | ||
1525 | track->eq_gain(whicheq,gain); | ||
1526 | continue; | ||
1527 | |||
1528 | } | ||
1529 | if ((line.substr(0,5)=="eq_Q[") | ||
1530 | &&(line.substr(6,2)=="]=")) | ||
1531 | { | ||
1532 | int whicheq=Convert::str2long(line.substr(5,1)); | ||
1533 | double Q=Convert::str2dbl(line.substr(8,10)); | ||
1534 | track->eq_Q(whicheq,Q); | ||
1535 | continue; | ||
1536 | } | ||
1537 | if ((line.substr(0,6)=="eq_on[") | ||
1538 | &&(line.substr(7,2)=="]=")) | ||
1539 | { | ||
1540 | int whicheq=Convert::str2long(line.substr(6,1)); | ||
1541 | int onoff=Convert::str2long(line.substr(9,10)); | ||
1542 | track->eq_on(whicheq,onoff); | ||
1543 | continue; | ||
1544 | } | ||
1545 | if (line.substr(0,6)=="fader=") { | ||
1546 | if (master) { | ||
1547 | this->fadervalue(Convert::str2dbl(line.substr(6,10))); | ||
1548 | } | ||
1549 | else | ||
1550 | { | ||
1551 | track->fadervalue(Convert::str2dbl(line.substr(6,10))); | ||
1552 | |||
1553 | } | ||
1554 | |||
1555 | continue; | ||
1556 | } | ||
1557 | |||
1558 | cout << "Unknown setting, ignoring: " << line << endl; | ||
1559 | } | ||
1560 | this->selectedchannel(savechan); | ||
1561 | from_in.close(); | ||
1562 | |||
1563 | return NULL;} {} | ||
1564 | } | ||
1565 | Function {loadtrackmix(string* strfile,int base0track)} {open return_type {string*} | ||
1566 | } { | ||
1567 | code {fstream from_in(strfile->c_str(),ios::in); | ||
1568 | if (from_in==NULL) { | ||
1569 | string *error=new string(""); | ||
1570 | *error+="Cannot open mix file for writing."; | ||
1571 | return error; | ||
1572 | } | ||
1573 | string line; | ||
1574 | int savechan=base0track; | ||
1575 | while (!(from_in.eof())) | ||
1576 | { | ||
1577 | getline(from_in,line); | ||
1578 | if (line=="") continue; | ||
1579 | if (line.substr(0,7)=="[Track=") { | ||
1580 | continue; | ||
1581 | } | ||
1582 | MixerChannelControl* track=parentui()->mixerchannel[selectedchannel()]->control; | ||
1583 | if (line.substr(0,5)=="solo=") { | ||
1584 | // mixsolo[this->selectedchannel]->value(Convert::str2long(line.substr(5,1))); | ||
1585 | track->solo(Convert::str2long(line.substr(5,1))); | ||
1586 | continue; | ||
1587 | } | ||
1588 | if (line.substr(0,5)=="mute=") { | ||
1589 | // mixmute[this->selectedchannel]->value(Convert::str2long(line.substr(5,1))); | ||
1590 | track->mute(Convert::str2long(line.substr(5,1))); | ||
1591 | continue; | ||
1592 | } | ||
1593 | if (line.substr(0,4)=="pan=") { | ||
1594 | track->panvalue(Convert::str2dbl(line.substr(4,10))); | ||
1595 | continue; | ||
1596 | } | ||
1597 | if ((line.substr(0,8)=="eq_freq[") | ||
1598 | &&(line.substr(9,2)=="]=")) | ||
1599 | { | ||
1600 | int whicheq=Convert::str2long(line.substr(8,1)); | ||
1601 | double freq=Convert::str2dbl(line.substr(11,10)); | ||
1602 | track->eq_freq(whicheq,freq); | ||
1603 | continue; | ||
1604 | |||
1605 | } | ||
1606 | if ((line.substr(0,8)=="eq_gain[") | ||
1607 | &&(line.substr(9,2)=="]=")) | ||
1608 | { | ||
1609 | int whicheq=Convert::str2long(line.substr(8,1)); | ||
1610 | double gain=Convert::str2dbl(line.substr(11,10)); | ||
1611 | track->eq_gain(whicheq,gain); | ||
1612 | continue; | ||
1613 | |||
1614 | } | ||
1615 | if ((line.substr(0,5)=="eq_Q[") | ||
1616 | &&(line.substr(6,2)=="]=")) | ||
1617 | { | ||
1618 | int whicheq=Convert::str2long(line.substr(5,1)); | ||
1619 | double Q=Convert::str2dbl(line.substr(8,10)); | ||
1620 | track->eq_Q(whicheq,Q); | ||
1621 | continue; | ||
1622 | } | ||
1623 | if ((line.substr(0,6)=="eq_on[") | ||
1624 | &&(line.substr(7,2)=="]=")) | ||
1625 | { | ||
1626 | int whicheq=Convert::str2long(line.substr(6,1)); | ||
1627 | int onoff=Convert::str2long(line.substr(9,10)); | ||
1628 | track->eq_on(whicheq,onoff); | ||
1629 | continue; | ||
1630 | } | ||
1631 | if (line.substr(0,6)=="fader=") { | ||
1632 | track->fadervalue(Convert::str2dbl(line.substr(6,10))); | ||
1633 | continue; | ||
1634 | } | ||
1635 | |||
1636 | cout << "Unknown setting, ignoring: " << line << endl; | ||
1637 | } | ||
1638 | this->selectedchannel(savechan); | ||
1639 | from_in.close(); | ||
1640 | |||
1641 | return NULL;} {} | ||
1642 | } | ||
1643 | Function {updatemeters()} {open | ||
1644 | } { | ||
1645 | code {MixerUI* pui=this->parentui(); | ||
1646 | if (pui==NULL) return; | ||
1647 | for (int tracknum=0;tracknum<24;tracknum++) { | ||
1648 | pui->mixerchannel[tracknum]->control->updatemeters(); | ||
1649 | } | ||
1650 | // update and redraw meterlevels object | ||
1651 | pui->fader_master->control->updatemeters();} {} | ||
1652 | } | ||
1653 | Function {samplerate(__uint32 p_samplerate)} {open return_type void | ||
1654 | } { | ||
1655 | code {data->samplerate=p_samplerate; | ||
1656 | |||
1657 | MixerUI* pui=this->parentui(); | ||
1658 | if (pui==NULL) return; | ||
1659 | for (int tracknum=0;tracknum<24;tracknum++) { | ||
1660 | pui->mixerchannel[tracknum]->control->samplerate(p_samplerate); | ||
1661 | }} {} | ||
1662 | } | ||
1663 | Function {samplerate()} {open return_type __uint32 | ||
1664 | } { | ||
1665 | code {return data->samplerate;} {} | ||
1666 | } | ||
1667 | Function {eq_on(int onoff)} {return_type void | ||
1668 | } { | ||
1669 | code {data->eqon=onoff; | ||
1670 | parentui()->eqon->value(onoff); | ||
1671 | parentui()->eqon->redraw();} {} | ||
1672 | } | ||
1673 | Function {eq_on()} {open return_type int | ||
1674 | } { | ||
1675 | code {return data->eqon;} {} | ||
1676 | } | ||
1677 | Function {bypass()} {return_type int | ||
1678 | } { | ||
1679 | code {return data->bypass;} {} | ||
1680 | } | ||
1681 | Function {bypass(int onoff)} {return_type void | ||
1682 | } { | ||
1683 | code {data->bypass=onoff; | ||
1684 | parentui()->bypass->value(onoff); | ||
1685 | parentui()->bypass->redraw();} {} | ||
1686 | } | ||
1687 | } | ||
1688 | |||
1689 | class MixerUI {open : {public Fl_Group} | ||
1690 | } { | ||
1691 | decl {MixerControl* control;} {public | ||
1692 | } | ||
1693 | decl {MixerChannelUI* mixerchannel[24];} {public | ||
1694 | } | ||
1695 | decl {/* ===MIXER UI stuff ===================================================== */} {} | ||
1696 | decl {HD24UserInterface* ui;} {} | ||
1697 | decl {Fl_Window* window} {} | ||
1698 | Function {make_window() /*<-----------------------------------*/} {open | ||
1699 | } { | ||
1700 | Fl_Window mixgroup {open | ||
1701 | xywh {41 257 605 460} type Double | ||
1702 | code0 {o->position(this->x(),this->y());} | ||
1703 | class Fl_Group visible | ||
1704 | } { | ||
1705 | Fl_Group resources {open | ||
1706 | xywh {70 52 150 98} hide deactivate | ||
1707 | } { | ||
1708 | Fl_Button button_small_up { | ||
1709 | tooltip arm image {images/button_small.gif} xywh {75 52 145 13} deactivate | ||
1710 | } | ||
1711 | Fl_Button button_small_dn { | ||
1712 | tooltip arm image {images/button_small_dn.gif} xywh {70 52 5 13} deactivate | ||
1713 | } | ||
1714 | } | ||
1715 | Fl_Group mixergroup {open | ||
1716 | xywh {-9 0 643 463} | ||
1717 | code0 {init_gui();} | ||
1718 | } { | ||
1719 | Fl_Box {} { | ||
1720 | xywh {-9 354 625 109} box BORDER_BOX | ||
1721 | } | ||
1722 | Fl_Box {} { | ||
1723 | label S | ||
1724 | tooltip Solo xywh {5 269 10 14} color 1 selection_color 1 labelfont 1 labelsize 12 | ||
1725 | } | ||
1726 | Fl_Box {} { | ||
1727 | label M | ||
1728 | tooltip Mute xywh {5 286 10 14} color 1 selection_color 1 labelfont 1 labelsize 12 | ||
1729 | } | ||
1730 | Fl_Group channelgroup {open selected | ||
1731 | xywh {0 210 584 250} deactivate | ||
1732 | } { | ||
1733 | Fl_Group mixerchannel1 {open | ||
1734 | xywh {17 221 20 231} box BORDER_BOX color 7 | ||
1735 | code0 {mixerchannel[0]=o;} | ||
1736 | class MixerChannelUI | ||
1737 | } {} | ||
1738 | Fl_Group mixerchannel2 {open | ||
1739 | xywh {37 221 20 231} box BORDER_BOX color 7 | ||
1740 | code0 {mixerchannel[1]=o;} | ||
1741 | class MixerChannelUI | ||
1742 | } {} | ||
1743 | Fl_Group mixerchannel3 {open | ||
1744 | xywh {57 221 20 231} box BORDER_BOX color 7 | ||
1745 | code0 {mixerchannel[2]=o;} | ||
1746 | class MixerChannelUI | ||
1747 | } {} | ||
1748 | Fl_Group mixerchannel4 {open | ||
1749 | xywh {77 221 20 231} box BORDER_BOX color 7 | ||
1750 | code0 {mixerchannel[3]=o;} | ||
1751 | class MixerChannelUI | ||
1752 | } {} | ||
1753 | Fl_Group mixerchannel5 {open | ||
1754 | xywh {97 221 20 231} box BORDER_BOX color 7 | ||
1755 | code0 {mixerchannel[4]=o;} | ||
1756 | class MixerChannelUI | ||
1757 | } {} | ||
1758 | Fl_Group mixerchannel6 {open | ||
1759 | xywh {117 221 20 231} box BORDER_BOX color 7 | ||
1760 | code0 {mixerchannel[5]=o;} | ||
1761 | class MixerChannelUI | ||
1762 | } {} | ||
1763 | Fl_Group mixerchannel7 {open | ||
1764 | xywh {137 221 20 231} box BORDER_BOX color 7 | ||
1765 | code0 {mixerchannel[6]=o;} | ||
1766 | class MixerChannelUI | ||
1767 | } {} | ||
1768 | Fl_Group mixerchannel8 {open | ||
1769 | xywh {157 221 20 231} box BORDER_BOX color 7 | ||
1770 | code0 {mixerchannel[7]=o;} | ||
1771 | class MixerChannelUI | ||
1772 | } {} | ||
1773 | Fl_Group mixerchannel9 {open | ||
1774 | xywh {177 221 20 231} box BORDER_BOX color 7 | ||
1775 | code0 {mixerchannel[8]=o;} | ||
1776 | class MixerChannelUI | ||
1777 | } {} | ||
1778 | Fl_Group mixerchannel10 {open | ||
1779 | xywh {197 221 20 231} box BORDER_BOX color 7 | ||
1780 | code0 {mixerchannel[9]=o;} | ||
1781 | class MixerChannelUI | ||
1782 | } {} | ||
1783 | Fl_Group mixerchannel11 {open | ||
1784 | xywh {217 221 20 231} box BORDER_BOX color 7 | ||
1785 | code0 {mixerchannel[10]=o;} | ||
1786 | class MixerChannelUI | ||
1787 | } {} | ||
1788 | Fl_Group mixerchannel12 {open | ||
1789 | xywh {237 221 20 231} box BORDER_BOX color 7 | ||
1790 | code0 {mixerchannel[11]=o;} | ||
1791 | class MixerChannelUI | ||
1792 | } {} | ||
1793 | Fl_Group mixerchannel13 {open | ||
1794 | xywh {257 221 20 231} box BORDER_BOX color 7 | ||
1795 | code0 {mixerchannel[12]=o;} | ||
1796 | class MixerChannelUI | ||
1797 | } {} | ||
1798 | Fl_Group mixerchannel14 {open | ||
1799 | xywh {277 221 20 231} box BORDER_BOX color 7 | ||
1800 | code0 {mixerchannel[13]=o;} | ||
1801 | class MixerChannelUI | ||
1802 | } {} | ||
1803 | Fl_Group mixerchannel15 {open | ||
1804 | xywh {297 221 20 231} box BORDER_BOX color 7 | ||
1805 | code0 {mixerchannel[14]=o;} | ||
1806 | class MixerChannelUI | ||
1807 | } {} | ||
1808 | Fl_Group mixerchannel16 {open | ||
1809 | xywh {317 221 20 231} box BORDER_BOX color 7 | ||
1810 | code0 {mixerchannel[15]=o;} | ||
1811 | class MixerChannelUI | ||
1812 | } {} | ||
1813 | Fl_Group mixerchannel17 {open | ||
1814 | xywh {337 221 20 231} box BORDER_BOX color 7 | ||
1815 | code0 {mixerchannel[16]=o;} | ||
1816 | class MixerChannelUI | ||
1817 | } {} | ||
1818 | Fl_Group mixerchannel18 {open | ||
1819 | xywh {357 221 20 231} box BORDER_BOX color 7 | ||
1820 | code0 {mixerchannel[17]=o;} | ||
1821 | class MixerChannelUI | ||
1822 | } {} | ||
1823 | Fl_Group mixerchannel19 {open | ||
1824 | xywh {377 221 20 231} box BORDER_BOX color 7 | ||
1825 | code0 {mixerchannel[18]=o;} | ||
1826 | class MixerChannelUI | ||
1827 | } {} | ||
1828 | Fl_Group mixerchannel20 {open | ||
1829 | xywh {397 221 20 231} box BORDER_BOX color 7 | ||
1830 | code0 {mixerchannel[19]=o;} | ||
1831 | class MixerChannelUI | ||
1832 | } {} | ||
1833 | Fl_Group mixerchannel21 {open | ||
1834 | xywh {417 221 20 231} box BORDER_BOX color 7 | ||
1835 | code0 {mixerchannel[20]=o;} | ||
1836 | class MixerChannelUI | ||
1837 | } {} | ||
1838 | Fl_Group mixerchannel22 {open | ||
1839 | xywh {437 221 20 231} box BORDER_BOX color 7 | ||
1840 | code0 {mixerchannel[21]=o;} | ||
1841 | class MixerChannelUI | ||
1842 | } {} | ||
1843 | Fl_Group mixerchannel23 {open | ||
1844 | xywh {457 221 20 231} box BORDER_BOX color 7 | ||
1845 | code0 {mixerchannel[22]=o;} | ||
1846 | class MixerChannelUI | ||
1847 | } {} | ||
1848 | Fl_Group mixerchannel24 {open | ||
1849 | xywh {477 221 20 231} box BORDER_BOX color 7 | ||
1850 | code0 {mixerchannel[23]=o;} | ||
1851 | class MixerChannelUI | ||
1852 | } {} | ||
1853 | } | ||
1854 | Fl_Tabs {} {open | ||
1855 | xywh {10 25 435 195} | ||
1856 | } { | ||
1857 | Fl_Group eqgroup { | ||
1858 | label EQ open | ||
1859 | xywh {10 45 435 175} labelfont 1 labelsize 10 deactivate | ||
1860 | } { | ||
1861 | Fl_Dial gain1 { | ||
1862 | callback {mixerchannel[control->selectedchannel()]->control->eq_gain(0,o->value());} | ||
1863 | xywh {20 159 30 30} minimum -20 maximum 20 step 10 | ||
1864 | class WidgetPDial | ||
1865 | } | ||
1866 | Fl_Dial gain2 { | ||
1867 | callback {mixerchannel[control->selectedchannel()]->control->eq_gain(1,o->value());} | ||
1868 | xywh {65 159 30 30} minimum -20 maximum 20 step 10 | ||
1869 | class WidgetPDial | ||
1870 | } | ||
1871 | Fl_Dial gain3 { | ||
1872 | callback {mixerchannel[control->selectedchannel()]->control->eq_gain(2,o->value());} | ||
1873 | xywh {110 159 30 30} minimum -20 maximum 20 step 10 | ||
1874 | class WidgetPDial | ||
1875 | } | ||
1876 | Fl_Dial gain4 { | ||
1877 | label GAIN | ||
1878 | callback {mixerchannel[control->selectedchannel()]->control->eq_gain(3,o->value());} | ||
1879 | xywh {155 159 30 30} labelfont 1 labelsize 12 align 8 minimum -20 maximum 20 step 10 | ||
1880 | class WidgetPDial | ||
1881 | } | ||
1882 | Fl_Dial freq1 { | ||
1883 | callback {mixerchannel[control->selectedchannel()]->control->eq_freq(0,o->value());} | ||
1884 | xywh {20 125 30 30} minimum 20 maximum 200 step 10 value 100 | ||
1885 | class WidgetPDial | ||
1886 | } | ||
1887 | Fl_Dial freq2 { | ||
1888 | callback {mixerchannel[control->selectedchannel()]->control->eq_freq(1,o->value());} | ||
1889 | xywh {65 125 30 30} minimum 150 maximum 1000 step 20 value 600 | ||
1890 | class WidgetPDial | ||
1891 | } | ||
1892 | Fl_Dial freq3 { | ||
1893 | callback {mixerchannel[control->selectedchannel()]->control->eq_freq(2,o->value());} | ||
1894 | xywh {110 125 30 30} minimum 800 maximum 3000 step 10 value 1600 | ||
1895 | class WidgetPDial | ||
1896 | } | ||
1897 | Fl_Dial freq4 { | ||
1898 | label FREQ | ||
1899 | callback {mixerchannel[control->selectedchannel()]->control->eq_freq(3,o->value());} | ||
1900 | xywh {155 125 30 30} labelfont 1 labelsize 12 align 8 minimum 3000 maximum 12000 step 1 value 6000 | ||
1901 | class WidgetPDial | ||
1902 | } | ||
1903 | Fl_Check_Button eqon1 { | ||
1904 | label { Low} | ||
1905 | callback {mixerchannel[control->selectedchannel()]->control->eq_on(0,o->value());} | ||
1906 | xywh {15 95 20 15} down_box DOWN_BOX value 1 labelsize 12 align 5 | ||
1907 | } | ||
1908 | Fl_Check_Button eqon2 { | ||
1909 | label {Lo/Mid} | ||
1910 | callback {mixerchannel[control->selectedchannel()]->control->eq_on(1,o->value());} | ||
1911 | xywh {60 95 20 15} down_box DOWN_BOX value 1 labelsize 12 align 5 | ||
1912 | } | ||
1913 | Fl_Check_Button eqon3 { | ||
1914 | label {Hi/Mid} | ||
1915 | callback {mixerchannel[control->selectedchannel()]->control->eq_on(2,o->value());} | ||
1916 | xywh {105 95 20 15} down_box DOWN_BOX value 1 labelsize 12 align 5 | ||
1917 | } | ||
1918 | Fl_Check_Button eqon4 { | ||
1919 | label High | ||
1920 | callback {mixerchannel[control->selectedchannel()]->control->eq_on(3,o->value());} | ||
1921 | xywh {150 95 20 15} down_box DOWN_BOX value 1 labelsize 12 align 5 | ||
1922 | } | ||
1923 | Fl_Check_Button eqon { | ||
1924 | label {Enable equalizer (all channels)} | ||
1925 | callback {control->eq_on(o->value());} | ||
1926 | xywh {15 50 205 20} down_box DOWN_BOX value 1 labelsize 12 | ||
1927 | } | ||
1928 | Fl_Check_Button reverbon { | ||
1929 | label {Reverb (not yet available)} | ||
1930 | callback {//mixerchannel[control->selectedchannel()]->control->reverb_on(o->value());} | ||
1931 | xywh {240 95 175 15} down_box DOWN_BOX value 1 labelsize 12 deactivate | ||
1932 | } | ||
1933 | Fl_Check_Button tapesaton { | ||
1934 | label {Tape emulation} | ||
1935 | callback {//mixerchannel[control->selectedchannel()]->control->reverb_on(o->value());} | ||
1936 | xywh {240 80 175 15} down_box DOWN_BOX value 1 labelsize 12 deactivate | ||
1937 | } | ||
1938 | Fl_Output dispgain1 { | ||
1939 | xywh {15 190 40 15} box FLAT_BOX color 53 labelsize 10 align 0 textsize 10 | ||
1940 | } | ||
1941 | Fl_Output dispgain2 { | ||
1942 | xywh {60 190 40 15} box FLAT_BOX color 53 labelsize 10 align 0 textsize 10 | ||
1943 | } | ||
1944 | Fl_Output dispgain3 { | ||
1945 | xywh {105 190 40 15} box FLAT_BOX color 53 labelsize 10 align 0 textsize 10 | ||
1946 | } | ||
1947 | Fl_Output dispgain4 { | ||
1948 | xywh {150 190 40 15} box FLAT_BOX color 53 labelsize 10 align 0 textsize 10 | ||
1949 | } | ||
1950 | Fl_Output dispfreq1 { | ||
1951 | xywh {15 109 40 15} box FLAT_BOX color 53 labelsize 10 align 0 textsize 10 | ||
1952 | } | ||
1953 | Fl_Output dispfreq2 { | ||
1954 | xywh {60 109 40 15} box FLAT_BOX color 53 labelsize 10 align 0 textsize 10 | ||
1955 | } | ||
1956 | Fl_Output dispfreq3 { | ||
1957 | xywh {105 109 40 15} box FLAT_BOX color 53 labelsize 10 align 0 textsize 10 | ||
1958 | } | ||
1959 | Fl_Output dispfreq4 { | ||
1960 | xywh {150 109 40 15} box FLAT_BOX color 53 labelsize 10 align 0 textsize 10 | ||
1961 | } | ||
1962 | } | ||
1963 | Fl_Tabs {} { | ||
1964 | label AUX | ||
1965 | xywh {10 45 330 175} labelfont 1 labelsize 10 hide | ||
1966 | } {} | ||
1967 | } | ||
1968 | Fl_Button bypass { | ||
1969 | label {Bypass Mixer} | ||
1970 | callback {control->bypass(o->value()); | ||
1971 | |||
1972 | switch (o->value()) | ||
1973 | { | ||
1974 | case 0: | ||
1975 | eqgroup->activate(); | ||
1976 | channelgroup->activate(); | ||
1977 | break; | ||
1978 | case 1: | ||
1979 | eqgroup->deactivate(); | ||
1980 | channelgroup->deactivate(); | ||
1981 | break; | ||
1982 | |||
1983 | }} | ||
1984 | tooltip Solo xywh {10 0 90 20} type Toggle value 1 selection_color 1 labelsize 12 | ||
1985 | } | ||
1986 | Fl_Group fader_master {open | ||
1987 | xywh {574 221 20 231} box BORDER_BOX color 7 | ||
1988 | class MasterChannelUI | ||
1989 | } {} | ||
1990 | } | ||
1991 | } | ||
1992 | } | ||
1993 | Function {MixerUI(int a,int b,int c,int d):Fl_Group(a,b,c,d,NULL)} {open | ||
1994 | } { | ||
1995 | code {control=new MixerControl(); | ||
1996 | control->parentui(this); | ||
1997 | this->window=(Fl_Window*)(this->make_window());} {} | ||
1998 | } | ||
1999 | Function {~MixerUI()} {open | ||
2000 | } { | ||
2001 | code {delete control;} {} | ||
2002 | } | ||
2003 | Function {init_gui()} {open | ||
2004 | } { | ||
2005 | code {int starty=(mixerchannel[0]->y()); | ||
2006 | int startx=(mixerchannel[0]->x()); | ||
2007 | fader_master->clear_visible_focus(); | ||
2008 | for (int i=1;i<=24;i++) | ||
2009 | { | ||
2010 | if (i==1) { | ||
2011 | mixerchannel[i-1]->control->channelselect(1); | ||
2012 | } | ||
2013 | mixerchannel[i-1]->position(startx+((i-1)*23),starty); | ||
2014 | // mixerchannel[i-1]->size(mixerchannel[0]->w(),mixerchannel[0]->h()); | ||
2015 | mixerchannel[i-1]->clear_visible_focus(); | ||
2016 | mixerchannel[i-1]->control->channel_number(i); | ||
2017 | |||
2018 | mixerchannel[i-1]->control->parentmixercontrol(this->control); | ||
2019 | |||
2020 | // set values on freq/gain displays: | ||
2021 | mixerchannel[i-1]->control->eq_freq(0,mixerchannel[i-1]->control->eq_freq(0)); | ||
2022 | mixerchannel[i-1]->control->eq_freq(1,mixerchannel[i-1]->control->eq_freq(1)); | ||
2023 | mixerchannel[i-1]->control->eq_freq(2,mixerchannel[i-1]->control->eq_freq(2)); | ||
2024 | mixerchannel[i-1]->control->eq_freq(3,mixerchannel[i-1]->control->eq_freq(3)); | ||
2025 | |||
2026 | mixerchannel[i-1]->control->eq_gain(0,mixerchannel[i-1]->control->eq_gain(0)); | ||
2027 | mixerchannel[i-1]->control->eq_gain(1,mixerchannel[i-1]->control->eq_gain(1)); | ||
2028 | mixerchannel[i-1]->control->eq_gain(2,mixerchannel[i-1]->control->eq_gain(2)); | ||
2029 | mixerchannel[i-1]->control->eq_gain(3,mixerchannel[i-1]->control->eq_gain(3)); | ||
2030 | |||
2031 | |||
2032 | // eq_freq[(i-1)*eqperchan+0]=100; | ||
2033 | // eq_freq[(i-1)*eqperchan+1]=600; | ||
2034 | // eq_freq[(i-1)*eqperchan+2]=1600; | ||
2035 | // eq_freq[(i-1)*eqperchan+3]=6000; | ||
2036 | // eq_on[(i-1)*eqperchan+0]=eqon1->value(); | ||
2037 | // eq_on[(i-1)*eqperchan+1]=eqon2->value(); | ||
2038 | // eq_on[(i-1)*eqperchan+2]=eqon3->value(); | ||
2039 | // eq_on[(i-1)*eqperchan+3]=eqon4->value(); | ||
2040 | // for (int j=0;j<4;j++) { | ||
2041 | // eq_gain[(i-1)*eqperchan+j]=0; | ||
2042 | // | ||
2043 | // eq_Q[(i-1)*eqperchan+j]=1; | ||
2044 | // eq_type[(i-1)*eqperchan+j]=7; | ||
2045 | // } | ||
2046 | mixerchannel[i-1]->clear_visible_focus(); | ||
2047 | // mixsolo[i-1]->position(8+(startx)+((i-1)*23),mixsolo[i-1]->y()); | ||
2048 | // mixsolo[i-1]->size(mixsolo[0]->w(),mixsolo[0]->h()); | ||
2049 | // mixsolo[i-1]->up_image(mixsolo[0]->up_image()); | ||
2050 | // mixsolo[i-1]->down_image(mixsolo[0]->down_image()); | ||
2051 | |||
2052 | // mixmute[i-1]->position(mixsolo[i-1]->x(),mixmute[i-1]->y()); | ||
2053 | // mixmute[i-1]->size(mixmute[0]->w(),mixmute[0]->h()); | ||
2054 | // mixmute[i-1]->up_image(mixmute[0]->up_image()); | ||
2055 | // mixmute[i-1]->down_image(mixmute[0]->down_image()); | ||
2056 | |||
2057 | // mixfader[i-1]->position(mixsolo[i-1]->x(),mixfader[i-1]->y()); | ||
2058 | // mixfader[i-1]->size(mixfader[0]->w(),mixfader[0]->h()); | ||
2059 | |||
2060 | // mixchsel[i-1]->position(mixsolo[i-1]->x(),mixchsel[i-1]->y()); | ||
2061 | // mixpan[i-1]->position(mixsolo[i-1]->x(),mixpan[i-1]->y()); | ||
2062 | // mixled[i-1]->position(mixfader[i-1]->x()+17,mixfader[0]->y()); | ||
2063 | mixerchannel[i-1]->control->fadervalue(90); | ||
2064 | } | ||
2065 | |||
2066 | //masterled[0]->position(fader_master->x()-2,fader_master->y()); | ||
2067 | //masterled[1]->position(fader_master->x()+17,fader_master->y()); | ||
2068 | fader_master->control->fadervalue(90); | ||
2069 | //this->selectedchannel(0);} {} | ||
2070 | } | ||
2071 | Function {set_ui(HD24UserInterface* p_ui)} {open return_type void | ||
2072 | } { | ||
2073 | code {this->ui=p_ui;} {} | ||
2074 | } | ||
2075 | Function {loadfromfile()} {open return_type void | ||
2076 | } { | ||
2077 | code {string* mixdir=hd24utils::getlastdir("mixdir"); | ||
2078 | |||
2079 | Fl_Native_File_Chooser chooser; | ||
2080 | chooser.directory(mixdir->c_str()); | ||
2081 | delete mixdir; | ||
2082 | |||
2083 | chooser.title("Select a mix to load\\0"); | ||
2084 | chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); | ||
2085 | chooser.filter("Mixer settings\\t*.{mix}\\0"); | ||
2086 | //chooser.preview(0); | ||
2087 | switch (chooser.show()) { | ||
2088 | case -1: break; //error | ||
2089 | case 1: break; //cancel | ||
2090 | default: | ||
2091 | if (chooser.filename()) { | ||
2092 | string* cfilename=new string(chooser.filename()); | ||
2093 | |||
2094 | //cout << "filename = " << *strfile << endl; | ||
2095 | string* fpath=new string(""); | ||
2096 | *fpath+=cfilename->substr(0,strlen(cfilename->c_str())-strlen(fl_filename_name(cfilename->c_str()))); | ||
2097 | hd24utils::setlastdir("mixdir",fpath->c_str()); | ||
2098 | control->loadmix(cfilename); | ||
2099 | delete fpath; | ||
2100 | delete cfilename; | ||
2101 | } | ||
2102 | break; | ||
2103 | }} {} | ||
2104 | } | ||
2105 | Function {savetofile()} {open return_type void | ||
2106 | } { | ||
2107 | code {string* mixdir=new string(""); | ||
2108 | *mixdir+=*(hd24utils::getlastdir("mixdir")); | ||
2109 | |||
2110 | Fl_Native_File_Chooser chooser; | ||
2111 | chooser.filter("Mix files\\t*.mix"); | ||
2112 | chooser.title("Save mixer settings to file"); | ||
2113 | chooser.directory(mixdir->c_str()); | ||
2114 | chooser.options(Fl_Native_File_Chooser::NEW_FOLDER); | ||
2115 | chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); | ||
2116 | |||
2117 | switch (chooser.show()) { | ||
2118 | case -1: break; //error | ||
2119 | case 1: break; //cancel | ||
2120 | default: | ||
2121 | // save header to chooser.filename() | ||
2122 | |||
2123 | bool bFileexists=false; | ||
2124 | if (bFileexists) { | ||
2125 | bool choice=ui->confirm( | ||
2126 | "A file with this name already exists. Do you wish to overwrite it?" | ||
2127 | ); | ||
2128 | if (!(choice)) return; | ||
2129 | } | ||
2130 | string* strfile=new string(chooser.filename()); | ||
2131 | //cout << "filename = " << *strfile << endl; | ||
2132 | string* fpath=new string(""); | ||
2133 | *fpath+=strfile->substr(0,strlen(strfile->c_str())-strlen(fl_filename_name(strfile->c_str()))); | ||
2134 | hd24utils::setlastdir("mixdir",fpath->c_str()); | ||
2135 | |||
2136 | string* anyerrors=control->savemix(strfile); | ||
2137 | |||
2138 | delete strfile; | ||
2139 | delete fpath; | ||
2140 | if (anyerrors==NULL) { | ||
2141 | fl_message("Mix file saved successfully."); | ||
2142 | } else { | ||
2143 | delete anyerrors; | ||
2144 | fl_message("Could not write mix file. Access denied? Disk full?"); | ||
2145 | } | ||
2146 | break; | ||
2147 | } | ||
2148 | delete mixdir;} {} | ||
2149 | } | ||
2150 | Function {loadtrackmixfromfile()} {open return_type void | ||
2151 | } { | ||
2152 | code {string* mixdir=hd24utils::getlastdir("mixdir"); | ||
2153 | |||
2154 | Fl_Native_File_Chooser chooser; | ||
2155 | chooser.directory(mixdir->c_str()); | ||
2156 | delete mixdir; | ||
2157 | |||
2158 | chooser.title("Select a mix to load\\0"); | ||
2159 | chooser.type(Fl_Native_File_Chooser::BROWSE_FILE); | ||
2160 | chooser.filter("Mixer settings\\t*.{mix}\\0"); | ||
2161 | //chooser.preview(0); | ||
2162 | switch (chooser.show()) { | ||
2163 | case -1: break; //error | ||
2164 | case 1: break; //cancel | ||
2165 | default: | ||
2166 | if (chooser.filename()) { | ||
2167 | string* cfilename=new string(chooser.filename()); | ||
2168 | |||
2169 | //cout << "filename = " << *strfile << endl; | ||
2170 | string* fpath=new string(""); | ||
2171 | *fpath+=cfilename->substr(0,strlen(cfilename->c_str())-strlen(fl_filename_name(cfilename->c_str()))); | ||
2172 | hd24utils::setlastdir("mixdir",fpath->c_str()); | ||
2173 | control->loadtrackmix(cfilename,control->selectedchannel()); | ||
2174 | delete fpath; | ||
2175 | delete cfilename; | ||
2176 | } | ||
2177 | break; | ||
2178 | }} {} | ||
2179 | } | ||
2180 | Function {savetrackmixtofile()} {open return_type void | ||
2181 | } { | ||
2182 | code {string* mixdir=new string(""); | ||
2183 | *mixdir+=*(hd24utils::getlastdir("mixdir")); | ||
2184 | |||
2185 | Fl_Native_File_Chooser chooser; | ||
2186 | chooser.filter("Mix files\\t*.mix"); | ||
2187 | chooser.title("Save mixer settings to file"); | ||
2188 | chooser.directory(mixdir->c_str()); | ||
2189 | chooser.options(Fl_Native_File_Chooser::NEW_FOLDER); | ||
2190 | chooser.type(Fl_Native_File_Chooser::BROWSE_SAVE_FILE); | ||
2191 | |||
2192 | switch (chooser.show()) { | ||
2193 | case -1: break; //error | ||
2194 | case 1: break; //cancel | ||
2195 | default: | ||
2196 | // save header to chooser.filename() | ||
2197 | |||
2198 | bool bFileexists=false; | ||
2199 | if (bFileexists) { | ||
2200 | bool choice=ui->confirm( | ||
2201 | "A file with this name already exists. Do you wish to overwrite it?" | ||
2202 | ); | ||
2203 | if (!(choice)) return; | ||
2204 | } | ||
2205 | string* strfile=new string(chooser.filename()); | ||
2206 | //cout << "filename = " << *strfile << endl; | ||
2207 | string* fpath=new string(""); | ||
2208 | *fpath+=strfile->substr(0,strlen(strfile->c_str())-strlen(fl_filename_name(strfile->c_str()))); | ||
2209 | hd24utils::setlastdir("mixdir",fpath->c_str()); | ||
2210 | |||
2211 | string* anyerrors=control->savetrackmix(strfile,control->selectedchannel()); | ||
2212 | |||
2213 | delete strfile; | ||
2214 | if (anyerrors==NULL) { | ||
2215 | fl_message("Mix file saved successfully."); | ||
2216 | } else { | ||
2217 | delete anyerrors; | ||
2218 | fl_message("Could not write mix file. Access denied? Disk full?"); | ||
2219 | } | ||
2220 | delete fpath; | ||
2221 | break; | ||
2222 | } | ||
2223 | delete mixdir;} {} | ||
2224 | } | ||
2225 | } | ||
diff --git a/src/frontend/ui_recorder.fl b/src/frontend/ui_recorder.fl new file mode 100644 index 0000000..f650f5f --- /dev/null +++ b/src/frontend/ui_recorder.fl | |||
@@ -0,0 +1,3639 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0109 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {\#define RECORDERDEBUG 0} {public | ||
6 | } | ||
7 | |||
8 | decl {\#define MAXSAMRATE 48000} {public | ||
9 | } | ||
10 | |||
11 | decl {\#define AUDIOLIB_PORTAUDIO 1} {public | ||
12 | } | ||
13 | |||
14 | decl {\#define AUDIOLIB_JACK 2} {public | ||
15 | } | ||
16 | |||
17 | decl {\#define AUDIOLIB_SNDFILE 3} {public | ||
18 | } | ||
19 | |||
20 | decl {\#define Pi2 (2*3.1415926535897)} {public | ||
21 | } | ||
22 | |||
23 | decl {\#include <config.h>} {public | ||
24 | } | ||
25 | |||
26 | decl {\#include <string>} {public | ||
27 | } | ||
28 | |||
29 | decl {\#include <vector>} {public | ||
30 | } | ||
31 | |||
32 | decl {\#include <soundlibs.h>} {public | ||
33 | } | ||
34 | |||
35 | decl {\#include <iostream>} {public | ||
36 | } | ||
37 | |||
38 | decl {\#include <fstream>} {public | ||
39 | } | ||
40 | |||
41 | decl {\#include <FL/FLTKstuff.H>} {public | ||
42 | } | ||
43 | |||
44 | decl {\#include <FL/filename.H>} {public | ||
45 | } | ||
46 | |||
47 | decl {\#include <convertlib.h>} {public | ||
48 | } | ||
49 | |||
50 | decl {\#include <time.h>} {public | ||
51 | } | ||
52 | |||
53 | decl {\#include <math.h>} {public | ||
54 | } | ||
55 | |||
56 | decl {\#include <hd24fs.h>} {public | ||
57 | } | ||
58 | |||
59 | decl {\#include <ui_hd24connect.h>} {public | ||
60 | } | ||
61 | |||
62 | decl {\#include <ui_mixer.h>} {public | ||
63 | } | ||
64 | |||
65 | decl {class MixerControl;} {public | ||
66 | } | ||
67 | |||
68 | decl {\#include <sharedlibs.h>} {public | ||
69 | } | ||
70 | |||
71 | decl {class RecorderChannelData;} {public | ||
72 | } | ||
73 | |||
74 | decl {class RecorderChannelControl;} {public | ||
75 | } | ||
76 | |||
77 | decl {class RecorderChannelUI;} {public | ||
78 | } | ||
79 | |||
80 | decl {class RecorderData;} {public | ||
81 | } | ||
82 | |||
83 | decl {class RecorderControl;} {public | ||
84 | } | ||
85 | |||
86 | decl {class RecorderUI;} {public | ||
87 | } | ||
88 | |||
89 | class ScrubWheel {: {public Fl_Roller} | ||
90 | } { | ||
91 | decl {int myval;} {} | ||
92 | decl {RecorderUI* ui;} {} | ||
93 | decl {int lastx;} {} | ||
94 | Function {handle(int e)} {open return_type int | ||
95 | } { | ||
96 | code {/*char *fltk_eventnames[] = | ||
97 | { | ||
98 | "FL_NO_EVENT", | ||
99 | "FL_PUSH", | ||
100 | "FL_RELEASE", | ||
101 | "FL_ENTER", | ||
102 | "FL_LEAVE", | ||
103 | "FL_DRAG", | ||
104 | "FL_FOCUS", | ||
105 | "FL_UNFOCUS", | ||
106 | "FL_KEYDOWN", | ||
107 | "FL_KEYUP", | ||
108 | "FL_CLOSE", | ||
109 | "FL_MOVE", | ||
110 | "FL_SHORTCUT", | ||
111 | "FL_DEACTIVATE", | ||
112 | "FL_ACTIVATE", | ||
113 | "FL_HIDE", | ||
114 | "FL_SHOW", | ||
115 | "FL_PASTE", | ||
116 | "FL_SELECTIONCLEAR", | ||
117 | "FL_MOUSEWHEEL", | ||
118 | "FL_DND_ENTER", | ||
119 | "FL_DND_DRAG", | ||
120 | "FL_DND_LEAVE", | ||
121 | "FL_DND_RELEASE", | ||
122 | }; | ||
123 | |||
124 | */ | ||
125 | if (e==FL_DRAG) { | ||
126 | myval=Fl::event_x()-lastx; | ||
127 | RecorderControl::button_scrub_call(myval,this->ui->control); | ||
128 | } | ||
129 | lastx=Fl::event_x(); | ||
130 | return 1;} {} | ||
131 | } | ||
132 | Function {ScrubWheel(int a,int b,int c,int d,const char* e):Fl_Roller(a,b,c,d,e)} {open | ||
133 | } { | ||
134 | code {myval=0;} {} | ||
135 | } | ||
136 | Function {draw()} {open | ||
137 | } { | ||
138 | code {//draw goes here | ||
139 | return Fl_Roller::draw();} {} | ||
140 | } | ||
141 | Function {value()} {open return_type int | ||
142 | } { | ||
143 | code {return this->myval;} {} | ||
144 | } | ||
145 | Function {value(int newval)} {open return_type int | ||
146 | } { | ||
147 | code {int oldval=this->myval; | ||
148 | this->myval=newval; // not very useful but whatever | ||
149 | return oldval;} {} | ||
150 | } | ||
151 | Function {setui(RecorderUI* p_ui)} {open | ||
152 | } { | ||
153 | code {this->ui=p_ui;} {} | ||
154 | } | ||
155 | } | ||
156 | |||
157 | class AudioSystem {open | ||
158 | } { | ||
159 | decl {AudioStorage* tape;} {} | ||
160 | decl {__uint32 samrate;} {public | ||
161 | } | ||
162 | decl {bool closingdown;} {public | ||
163 | } | ||
164 | decl {MixerControl* mixercontrol;} {} | ||
165 | decl {RecorderControl* recorder;} {} | ||
166 | decl {PortAudioWrapper* portaudio;} {public | ||
167 | } | ||
168 | decl {SoundFileWrapper* soundfile;} {public | ||
169 | } | ||
170 | decl {JackWrapper* libjack;} {} | ||
171 | decl {PaStreamParameters* inputParameters;} {} | ||
172 | decl {PaStreamParameters* outputParameters;} {} | ||
173 | decl {PaStream* portaudiostream;} {} | ||
174 | decl {jack_client_t *jackclient;} {} | ||
175 | decl {__uint32 jackrate;} {} | ||
176 | decl {__uint32 portaudiooffset;} {public | ||
177 | } | ||
178 | decl {int as_initialized;} {} | ||
179 | decl {int portaudio_initialized;} {} | ||
180 | decl {int jack_initialized;} {} | ||
181 | decl {int as_looppos;} {} | ||
182 | decl {bool as_mustloop;} {} | ||
183 | decl {jack_port_t *output_port[24];} {} | ||
184 | decl {jack_port_t *output_master[2];} {} | ||
185 | decl {jack_port_t *input_port[24];} {} | ||
186 | decl {long* mtsample;} {} | ||
187 | decl {bool havestreamtime;} {} | ||
188 | decl {__sint64 streamtime;} {public | ||
189 | } | ||
190 | Function {AudioSystem(RecorderControl* rec)} {open | ||
191 | } { | ||
192 | code {\#if (RECORDERDEBUG==1) | ||
193 | cout << "AudioSystem::AudioSystem()" << endl; | ||
194 | \#endif | ||
195 | initvars(rec);} {} | ||
196 | } | ||
197 | Function {initvars(RecorderControl* rec)} {open return_type void | ||
198 | } { | ||
199 | code {this->tape=NULL; | ||
200 | this->samrate=0; | ||
201 | this->closingdown=false; | ||
202 | this->mixercontrol=NULL; | ||
203 | this->recorder=rec; | ||
204 | this->portaudio=NULL; | ||
205 | this->soundfile=NULL; | ||
206 | this->libjack=NULL; | ||
207 | this->jackclient=NULL; | ||
208 | this->portaudiostream=NULL; | ||
209 | this->portaudio_initialized=0; | ||
210 | this->as_initialized=false; | ||
211 | this->jack_initialized=false; | ||
212 | this->as_looppos=0; | ||
213 | this->as_mustloop=false; | ||
214 | this->inputParameters=NULL; | ||
215 | this->outputParameters=NULL; | ||
216 | this->inputParameters=new PaStreamParameters; | ||
217 | this->outputParameters=new PaStreamParameters; | ||
218 | this->mtsample=NULL; | ||
219 | for (int i=0;i<24;i++) { | ||
220 | this->output_port[i]=NULL; | ||
221 | this->input_port[i]=NULL; | ||
222 | } | ||
223 | this->output_master[0]=NULL; | ||
224 | this->output_master[1]=NULL; | ||
225 | this->havestreamtime=false;} {} | ||
226 | } | ||
227 | Function {currentlocation(__uint32 newpos)} {open return_type void | ||
228 | } { | ||
229 | code {if (tape==NULL) return; | ||
230 | tape->currentlocation(newpos);} {} | ||
231 | } | ||
232 | Function {currentlocation()} {return_type __uint32 | ||
233 | } { | ||
234 | code {if (tape==NULL) return 0; | ||
235 | return tape->currentlocation();} {} | ||
236 | } | ||
237 | Function {jack_process(jack_nframes_t nframes, void *arg)} {open private return_type {static int} | ||
238 | } { | ||
239 | code {\#ifndef LIBJACK | ||
240 | \#if (RECORDERDEBUG==1) | ||
241 | cout << "no libjack" << endl; | ||
242 | \#endif | ||
243 | \#endif | ||
244 | |||
245 | \#ifdef LIBJACK | ||
246 | |||
247 | RecorderControl* recordercontrol=(RecorderControl*)arg; | ||
248 | |||
249 | if (recordercontrol==NULL) { | ||
250 | cout << "no control" << endl; | ||
251 | return 0; | ||
252 | } | ||
253 | AudioSystem* audio=recordercontrol->audio; | ||
254 | if (audio==NULL) | ||
255 | { | ||
256 | cout << "no audiosys" << endl; | ||
257 | return 0; | ||
258 | } | ||
259 | if ((audio->libjack)==NULL) | ||
260 | { | ||
261 | \#if (RECORDERDEBUG==1) | ||
262 | cout << "no libjack" << endl; | ||
263 | \#endif | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | if (!(audio->libjack->libloaded)) | ||
268 | { | ||
269 | cout << "no jacklib" << endl; | ||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | RecorderControl* mythis=recordercontrol; | ||
274 | //RecorderUI* mythis=recordercontrol; //(RecorderUI*)arg; | ||
275 | //AudioSystem* audio=mythis->control->audio; | ||
276 | |||
277 | |||
278 | jack_client_t* currjackclient=audio->jackclient; | ||
279 | if (currjackclient==NULL) return 0; | ||
280 | MixerControl* mixer=audio->mixer(); | ||
281 | if (mixer==NULL) return 0; | ||
282 | jack_position_t current; | ||
283 | jack_transport_state_t transport_state=audio->libjack->jack_transport_query(currjackclient,¤t); | ||
284 | |||
285 | hd24song* mysong=(hd24song*)audio->tape; | ||
286 | if (mysong==NULL) return 0; /* nothing to do! */ | ||
287 | |||
288 | hd24fs* myfs=mysong->fs(); | ||
289 | |||
290 | __sint64 frame_time = (__sint64)(audio->libjack->jack_get_current_transport_frame(currjackclient)); | ||
291 | |||
292 | MixerChannelControl* mixerchannel[24]; | ||
293 | |||
294 | |||
295 | for (unsigned int tracknum=0;tracknum<MAXCHANNELS;tracknum++) | ||
296 | { | ||
297 | mixerchannel[tracknum]=mixer->parentui()->mixerchannel[tracknum]->control; | ||
298 | } | ||
299 | |||
300 | unsigned int i; | ||
301 | __sint64 intsamval=0; | ||
302 | mysong->golocatepos(frame_time); | ||
303 | int jumpedloop=0; | ||
304 | if (transport_state!=JackTransportStopped) | ||
305 | { | ||
306 | __sint64 frpos=frame_time; | ||
307 | __sint64 posoffset=0; | ||
308 | for (i=0;i<nframes;i++) | ||
309 | { | ||
310 | if ( mythis->loopmode()==1 ) | ||
311 | { | ||
312 | posoffset++; | ||
313 | if ((frpos+i)==(__sint64)(mysong->getlocatepos(hd24song::LOCATEPOS_LOOPEND))) | ||
314 | { | ||
315 | frpos=mysong->getlocatepos(hd24song::LOCATEPOS_LOOPSTART); | ||
316 | mysong->golocatepos(frpos); | ||
317 | posoffset=0; | ||
318 | jumpedloop=1; | ||
319 | } | ||
320 | } | ||
321 | |||
322 | mysong->getmultitracksample( | ||
323 | (long*)((&audio->mtsample[i*25])), | ||
324 | hd24song::READMODE_REALTIME | ||
325 | ); | ||
326 | } | ||
327 | if (jumpedloop==1) | ||
328 | { | ||
329 | audio->hd24_transport_locate((__sint64)(frpos+posoffset)); | ||
330 | } | ||
331 | } | ||
332 | |||
333 | for (unsigned int tracknum=0;tracknum<MAXCHANNELS;tracknum++) | ||
334 | { | ||
335 | jack_default_audio_sample_t *out = | ||
336 | (jack_default_audio_sample_t *)(audio->libjack->jack_port_get_buffer (audio->output_port[tracknum], nframes)); | ||
337 | jack_default_audio_sample_t *in = | ||
338 | (jack_default_audio_sample_t *)(audio->libjack->jack_port_get_buffer (audio->input_port[tracknum], nframes)); | ||
339 | for (i=0;i<nframes;i++) | ||
340 | { | ||
341 | if (transport_state!=JackTransportStopped) { | ||
342 | long* xb=(long*)(&(audio->mtsample[i*25+tracknum])); | ||
343 | intsamval=xb[0]; | ||
344 | intsamval=((intsamval>>16)+((intsamval%256)<<16)+(intsamval & 0xff00)); | ||
345 | if (intsamval>=(1<<23)) { | ||
346 | intsamval-=(1<<24); | ||
347 | } | ||
348 | double samval=(intsamval/(double)0x800000); | ||
349 | out[i]=samval; // send pre-fader, pre-mixer channel output to JACK | ||
350 | } else { | ||
351 | out[i]=0; | ||
352 | } | ||
353 | |||
354 | mixerchannel[tracknum]->sample(i,out[i]); | ||
355 | |||
356 | // ... except if we are monitoring input, in which case regular reading etc is | ||
357 | // still going on, but we will just copy the incoming signal to the output: | ||
358 | // (with the possible exception of tracks being recorded but that's for later) | ||
359 | if (myfs->isallinput()) { | ||
360 | out[i]=in[i]; | ||
361 | } | ||
362 | |||
363 | if (fabs(out[i]) > mythis->data->trackpeak[i]) { | ||
364 | mythis->data->trackpeak[tracknum]=fabs(out[i]); | ||
365 | } | ||
366 | } | ||
367 | } | ||
368 | mixer->mix(nframes); | ||
369 | jack_default_audio_sample_t *masterL = | ||
370 | (jack_default_audio_sample_t *)(audio->libjack->jack_port_get_buffer (audio->output_master[0], nframes)); | ||
371 | jack_default_audio_sample_t *masterR = | ||
372 | (jack_default_audio_sample_t *)(audio->libjack->jack_port_get_buffer (audio->output_master[1], nframes)); | ||
373 | if ((masterL!=NULL)&&(masterR!=NULL)) { | ||
374 | for (i=0;i<nframes;i++) | ||
375 | { | ||
376 | masterL[i] = mixer->masterout(0,i); // left | ||
377 | masterR[i] = mixer->masterout(1,i); // right | ||
378 | } | ||
379 | } | ||
380 | \#endif | ||
381 | |||
382 | return 0;} {} | ||
383 | } | ||
384 | Function {jack_shutdown(void *arg)} {private return_type {static void} | ||
385 | } { | ||
386 | code {\#ifdef LIBJACK | ||
387 | AudioSystem* audio=(AudioSystem*)arg; | ||
388 | if (audio->jackclient==NULL) { | ||
389 | return; | ||
390 | } | ||
391 | if (audio->mtsample!=NULL) { | ||
392 | memutils::myfree("jack_shutdown",audio->mtsample); | ||
393 | audio->mtsample=NULL; | ||
394 | } | ||
395 | audio->jackclient=NULL; | ||
396 | return; | ||
397 | \#endif} {} | ||
398 | } | ||
399 | Function {jackinit()} {open private return_type void | ||
400 | } { | ||
401 | code {if (portaudio_initialized==1) | ||
402 | { | ||
403 | \#if (RECORDERDEBUG==1) | ||
404 | cout << "not initializing jack because portaudio is active" << endl; | ||
405 | \#endif | ||
406 | return; | ||
407 | } | ||
408 | if (!(libjack->libloaded)) | ||
409 | { | ||
410 | \#if (RECORDERDEBUG==1) | ||
411 | cout << "not initializing jack because its lib is not loaded" << endl; | ||
412 | \#endif | ||
413 | return; | ||
414 | } | ||
415 | if (this->closingdown) { | ||
416 | if (jackclient!=NULL) | ||
417 | { | ||
418 | jack_shutdown(this); | ||
419 | } | ||
420 | jackclient=NULL; | ||
421 | return; | ||
422 | } | ||
423 | \#ifdef LIBJACK | ||
424 | //button_setlocate->value(0); | ||
425 | //highlight_setbuttons(0); // value of setlocate button | ||
426 | //mustdisplaytimer=true; | ||
427 | if (jackclient==NULL) { | ||
428 | jackclient = libjack->jack_client_new("HD24connect"); | ||
429 | |||
430 | if (jackclient == NULL) { | ||
431 | // error: jack open failed. | ||
432 | \#if (RECORDERDEBUG==1) | ||
433 | cout << "error: jack open failed." << endl; | ||
434 | \#endif | ||
435 | return; | ||
436 | } | ||
437 | mtsample=(long *)memutils::mymalloc("jackinit",512000,1); | ||
438 | |||
439 | libjack->jack_set_process_callback ( | ||
440 | jackclient, | ||
441 | (int (*)(jack_nframes_t, void*))jack_process, | ||
442 | recorder); // was: this (=audiosystem) | ||
443 | libjack->jack_on_shutdown (jackclient, jack_shutdown, this); | ||
444 | jackrate=libjack->jack_get_sample_rate (jackclient); | ||
445 | int i; | ||
446 | for (i=1;i<=MAXCHANNELS;i++) { | ||
447 | string portnameout="output"; | ||
448 | string portnamein="input"; | ||
449 | |||
450 | string* tracknum=Convert::int2str(i); | ||
451 | portnameout+=*tracknum; | ||
452 | portnamein+=*tracknum; | ||
453 | delete(tracknum); | ||
454 | |||
455 | output_port[i-1]=libjack->jack_port_register (jackclient, portnameout.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | ||
456 | input_port[i-1]=libjack->jack_port_register (jackclient, portnamein.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsInput, 0); | ||
457 | } | ||
458 | string portnameout="master_out_L"; | ||
459 | output_master[0]=libjack->jack_port_register (jackclient, portnameout.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | ||
460 | portnameout="master_out_R"; | ||
461 | output_master[1]=libjack->jack_port_register (jackclient, portnameout.c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0); | ||
462 | if (libjack->jack_activate(jackclient)) { | ||
463 | \#if (RECORDERDEBUG==1) | ||
464 | cout << "cannot activate jack client" << endl; | ||
465 | \#endif | ||
466 | }; | ||
467 | } | ||
468 | \#endif} {} | ||
469 | } | ||
470 | Function {isjackinitialized()} {open private return_type bool | ||
471 | } { | ||
472 | code {if (this->jackclient!=NULL) | ||
473 | { | ||
474 | return true; | ||
475 | } | ||
476 | return false;} {} | ||
477 | } | ||
478 | Function {portaudioinit()} {open private return_type void | ||
479 | } { | ||
480 | code {\#ifndef LIBPORTAUDIO | ||
481 | return; | ||
482 | \#endif | ||
483 | \#ifdef LIBPORTAUDIO | ||
484 | //if (currsong==NULL) return; | ||
485 | //\#if (RECORDERDEBUG==1) | ||
486 | //cout << "Init portaudio" << endl; | ||
487 | //\#endif | ||
488 | //mustdisplaytimer=true; | ||
489 | PaError err; | ||
490 | err=(*(portaudio->Pa_Initialize))(); | ||
491 | if (err!=paNoError) { | ||
492 | this->portaudiostream=NULL; | ||
493 | (*(portaudio->Pa_Terminate))(); return; | ||
494 | \#if (RECORDERDEBUG==1) | ||
495 | cout << "Error during init portaudio" << endl; | ||
496 | \#endif | ||
497 | } | ||
498 | this->mustloop(false); | ||
499 | this->as_looppos=0; | ||
500 | this->portaudio_initialized=1; | ||
501 | this->as_initialized=1; | ||
502 | \#endif} {} | ||
503 | } | ||
504 | Function {isportaudioinitialized()} {open private return_type bool | ||
505 | } { | ||
506 | code {if (!(portaudio->libloaded)) { | ||
507 | return false; | ||
508 | } | ||
509 | if (portaudiostream!=NULL) { | ||
510 | return true; | ||
511 | } | ||
512 | if (portaudio_initialized!=0) { | ||
513 | return true; | ||
514 | } | ||
515 | return false;} {} | ||
516 | } | ||
517 | Function {portaudio_process(const void *inputBuffer, void *outputBuffer, __uint32 nframes, const PaStreamCallbackTimeInfo* timeinfo,PaStreamCallbackFlags, void *userData)} {open private return_type {static int} | ||
518 | } { | ||
519 | code {RecorderControl* recordercontrol=(RecorderControl*)userData; | ||
520 | |||
521 | if (recordercontrol==NULL) { | ||
522 | cout << "no control" << endl; | ||
523 | return 0; | ||
524 | } | ||
525 | AudioSystem* audio=recordercontrol->audio; | ||
526 | if (audio==NULL) | ||
527 | { | ||
528 | cout << "no audiosys" << endl; | ||
529 | return 0; | ||
530 | } | ||
531 | if (audio->portaudio==NULL) | ||
532 | { | ||
533 | cout << "no portaudio" << endl; | ||
534 | return 0; | ||
535 | } | ||
536 | if (!(audio->portaudio->libloaded)) | ||
537 | { | ||
538 | cout << "no palib" << endl; | ||
539 | return 0; | ||
540 | } | ||
541 | if (!audio->havestreamtime) | ||
542 | { | ||
543 | audio->streamtime=0; | ||
544 | audio->havestreamtime=true; | ||
545 | } | ||
546 | |||
547 | float samleft=0; | ||
548 | float samright=0; | ||
549 | |||
550 | //hd24fs* myfs=mythis->currenthd24; | ||
551 | |||
552 | PaStream* curr_pa_stream=audio->portaudiostream; | ||
553 | |||
554 | if (curr_pa_stream==NULL) | ||
555 | { | ||
556 | cout << "no stream" << endl; | ||
557 | return paContinue; | ||
558 | } | ||
559 | if ((audio->mtsample)==NULL) | ||
560 | { | ||
561 | cout << "no sample" << endl; | ||
562 | return paContinue; | ||
563 | } | ||
564 | |||
565 | // TODO: connect audio system to mixer | ||
566 | MixerControl* mixer=audio->mixer(); | ||
567 | if (mixer==NULL) | ||
568 | { | ||
569 | cout << "no mixer" << endl; | ||
570 | return paContinue; | ||
571 | } | ||
572 | |||
573 | if (audio->mustloop()) | ||
574 | { | ||
575 | cout << "must loop" << endl; | ||
576 | return paContinue; | ||
577 | } | ||
578 | |||
579 | hd24song* mysong=recordercontrol->song(); | ||
580 | if (mysong == NULL) | ||
581 | { | ||
582 | cout << "no song" << endl; | ||
583 | return 0;//nothing to do! | ||
584 | } | ||
585 | |||
586 | unsigned int tottracks=(unsigned int)mysong->logical_channels(); | ||
587 | |||
588 | /* frame time indicates how long the stream has been playing | ||
589 | and is reset to 0 after pressing stop/play. | ||
590 | To compensate for this, we must add our portaudio-offset, | ||
591 | the offset of the songcursor when we pressed 'play'. | ||
592 | We then record the absolute stream time in pa_streamtime. */ | ||
593 | __sint64 frame_time = audio->streamtime; | ||
594 | frame_time+=audio->portaudiooffset; | ||
595 | //audio->streamtime=frame_time; | ||
596 | audio->streamtime+=nframes; | ||
597 | MixerChannelControl* mixerchannel[24]; | ||
598 | |||
599 | unsigned int i; | ||
600 | __sint64 intsamval=0; | ||
601 | |||
602 | mysong->golocatepos(frame_time); | ||
603 | int loopmode=recordercontrol->loopmode(); | ||
604 | int jumpedloop=0; | ||
605 | |||
606 | __sint64 frpos=frame_time; | ||
607 | __sint64 posoffset=0; | ||
608 | for (i=0;i<nframes;i++) | ||
609 | { | ||
610 | if ( loopmode==1 ) | ||
611 | { | ||
612 | posoffset++; | ||
613 | if ((frpos+i)==(__sint64)(mysong->getlocatepos(hd24song::LOCATEPOS_LOOPEND))) | ||
614 | { | ||
615 | frpos=mysong->getlocatepos(hd24song::LOCATEPOS_LOOPSTART); | ||
616 | mysong->golocatepos(frpos); | ||
617 | posoffset=0; | ||
618 | jumpedloop=1; | ||
619 | } | ||
620 | } | ||
621 | |||
622 | mysong->getmultitracksample( | ||
623 | (long*)((&audio->mtsample[i*25])), | ||
624 | hd24song::READMODE_REALTIME | ||
625 | ); | ||
626 | // if sample rate is high speed, skip next sample. | ||
627 | if ((mysong->physical_channels()/mysong->logical_channels())==2) | ||
628 | { | ||
629 | mysong->getmultitracksample( | ||
630 | (long*)((&audio->mtsample[i*25])), | ||
631 | hd24song::READMODE_REALTIME | ||
632 | ); | ||
633 | } | ||
634 | } | ||
635 | if (jumpedloop==1) | ||
636 | { | ||
637 | audio->as_looppos=frpos+posoffset; | ||
638 | audio->mustloop(true); | ||
639 | } | ||
640 | |||
641 | |||
642 | |||
643 | for (unsigned int tracknum=0;tracknum<MAXCHANNELS;tracknum++) | ||
644 | { | ||
645 | mixerchannel[tracknum]=mixer->parentui()->mixerchannel[tracknum]->control; | ||
646 | } | ||
647 | |||
648 | for (unsigned int tracknum=0;tracknum<tottracks;tracknum++) | ||
649 | { | ||
650 | recordercontrol->data->trackpeak[tracknum]=0; | ||
651 | } | ||
652 | |||
653 | |||
654 | for (i=0;i<nframes;i++) | ||
655 | { | ||
656 | double samvaltot=0; | ||
657 | if (inputBuffer!=NULL) { | ||
658 | samleft=((float*)inputBuffer)[i*2]; | ||
659 | samright=((float*)inputBuffer)[i*2+1]; | ||
660 | } else { | ||
661 | samleft=0; | ||
662 | samright=0; | ||
663 | } | ||
664 | // depending on input mode, mix these to mono, set right to be equal to | ||
665 | // left, swap them or set left to be equal to right. | ||
666 | float subsamval; | ||
667 | for (unsigned int tracknum=0;tracknum<tottracks;tracknum++) | ||
668 | { | ||
669 | long* xb=(long*)(&(audio->mtsample[i*25+tracknum])); | ||
670 | intsamval=xb[0]; | ||
671 | intsamval=((intsamval>>16)+((intsamval%256)<<16)+(intsamval & 0xff00)); | ||
672 | if (intsamval>=(1<<23)) { | ||
673 | intsamval-=(1<<24); | ||
674 | } | ||
675 | |||
676 | |||
677 | if (mysong->istrackmonitoringinput(tracknum+1)) | ||
678 | { | ||
679 | subsamval=((tracknum%2)==0)?(samleft):(samright); | ||
680 | } | ||
681 | else | ||
682 | { | ||
683 | subsamval=(intsamval/(double)0x800000); | ||
684 | } | ||
685 | samvaltot+=subsamval; | ||
686 | if (fabs(subsamval) > recordercontrol->data->trackpeak[tracknum]) { | ||
687 | recordercontrol->data->trackpeak[tracknum]=fabs(subsamval); | ||
688 | } | ||
689 | |||
690 | mixerchannel[tracknum]->sample(i,subsamval); | ||
691 | |||
692 | } | ||
693 | if (tottracks<24) { | ||
694 | for (unsigned int tracknum=tottracks;tracknum<MAXCHANNELS;tracknum++) { | ||
695 | mixerchannel[tracknum]->sample(i,0); | ||
696 | } | ||
697 | } | ||
698 | /* | ||
699 | if (outputBuffer!=NULL) { | ||
700 | ((float*)outputBuffer)[i*2] = samval; // left | ||
701 | ((float*)outputBuffer)[i*2+1] = samval; // right | ||
702 | }*/ | ||
703 | |||
704 | } | ||
705 | mixer->mix(nframes); | ||
706 | |||
707 | if (outputBuffer!=NULL) { | ||
708 | |||
709 | for (i=0;i<nframes;i++) | ||
710 | { | ||
711 | ((float*)outputBuffer)[i*2] = mixer->masterout(0,i); // left | ||
712 | ((float*)outputBuffer)[i*2+1] = mixer->masterout(1,i); // right | ||
713 | } | ||
714 | } | ||
715 | |||
716 | // cout << mythis->trackpeak[0] << endl; | ||
717 | |||
718 | return 0;} {} | ||
719 | } | ||
720 | Function {portaudio_transport_start()} {open private return_type void | ||
721 | } { | ||
722 | code {if (!(portaudio->libloaded)) { | ||
723 | return; | ||
724 | } | ||
725 | |||
726 | \#if (RECORDERDEBUG==1) | ||
727 | cout << "portaudio transport start" << endl; | ||
728 | \#endif | ||
729 | if (!isportaudioinitialized()) | ||
730 | { | ||
731 | PaError err=(*(portaudio->Pa_Initialize))(); | ||
732 | if (err != paNoError) | ||
733 | { | ||
734 | \#if (RECORDERDEBUG==1) | ||
735 | cout << "Cannot initialize portaudio- exiting." << endl; | ||
736 | \#endif | ||
737 | |||
738 | } | ||
739 | } | ||
740 | if (isportaudioinitialized() && (portaudiostream!=NULL)) { | ||
741 | \#if (RECORDERDEBUG==1) | ||
742 | cout << "already have stream- done starting" << endl; | ||
743 | \#endif | ||
744 | return; | ||
745 | } | ||
746 | this->mustloop(false); | ||
747 | |||
748 | this->as_looppos=0; | ||
749 | PaDeviceIndex indev=(*(portaudio->Pa_GetDefaultInputDevice))(); | ||
750 | PaDeviceIndex outdev=(*(portaudio->Pa_GetDefaultOutputDevice))(); | ||
751 | cout << "default input device="<<indev<< endl; | ||
752 | cout << "default output device="<<outdev<<endl; | ||
753 | |||
754 | if (inputParameters!=NULL) | ||
755 | { | ||
756 | memset(inputParameters,'\\0',sizeof(*inputParameters)); | ||
757 | } | ||
758 | |||
759 | inputParameters->channelCount=2; | ||
760 | inputParameters->sampleFormat=paFloat32; | ||
761 | inputParameters->device=indev; | ||
762 | inputParameters->suggestedLatency = (*(portaudio->Pa_GetDeviceInfo))( inputParameters->device )->defaultLowInputLatency; | ||
763 | inputParameters->hostApiSpecificStreamInfo = NULL; | ||
764 | \#if (RECORDERDEBUG==1) | ||
765 | cout << "Input params set" << endl; | ||
766 | cout << "Device=" << indev << endl; | ||
767 | cout << "Channelcount=" << inputParameters->channelCount << endl; | ||
768 | cout << "sampleFormat=" << inputParameters->sampleFormat << endl; | ||
769 | cout << "suggestedlatency=" << inputParameters->suggestedLatency << endl; | ||
770 | |||
771 | \#endif | ||
772 | if (outputParameters!=NULL) | ||
773 | { | ||
774 | memset(outputParameters,'\\0',sizeof(*outputParameters)); | ||
775 | } | ||
776 | |||
777 | outputParameters->channelCount=2; | ||
778 | outputParameters->sampleFormat=paFloat32; | ||
779 | outputParameters->device=outdev; | ||
780 | outputParameters->suggestedLatency = (*(portaudio->Pa_GetDeviceInfo))( outputParameters->device )->defaultLowOutputLatency; | ||
781 | outputParameters->hostApiSpecificStreamInfo = NULL; | ||
782 | \#if (RECORDERDEBUG==1) | ||
783 | cout << "Output params set" << endl; | ||
784 | \#endif | ||
785 | cout << "Device=" << outdev << endl; | ||
786 | cout << "Channelcount=" << outputParameters->channelCount << endl; | ||
787 | cout << "sampleFormat=" << outputParameters->sampleFormat << endl; | ||
788 | cout << "suggestedlatency=" << outputParameters->suggestedLatency << endl; | ||
789 | |||
790 | if (mtsample==NULL) | ||
791 | { | ||
792 | mtsample=(long *)memutils::mymalloc("portaudio_transport_start",512000,sizeof(long)); | ||
793 | } | ||
794 | |||
795 | double playbackrate=this->samplerate(); | ||
796 | cout << "trying samrate="<<samrate<<endl; | ||
797 | cout << "framesperbuf=" << PA_FRAMESPERBUF << endl; | ||
798 | |||
799 | PaError err=(*(portaudio->Pa_OpenStream))( | ||
800 | &portaudiostream, | ||
801 | NULL,/*this->inputParameters,*/ | ||
802 | this->outputParameters, | ||
803 | playbackrate, | ||
804 | PA_FRAMESPERBUF, /* frames per buffer */ | ||
805 | paClipOff | paDitherOff, | ||
806 | portaudio_process, | ||
807 | (void*)recorder); | ||
808 | this->havestreamtime=false; | ||
809 | this->streamtime=0; | ||
810 | |||
811 | if (err!=paNoError) { | ||
812 | \#if (RECORDERDEBUG==1) | ||
813 | cout << "Error opening stream" << endl; | ||
814 | cout << portaudio->Pa_GetErrorText(err) << endl; | ||
815 | cout << "playbackrate=" << playbackrate << endl; | ||
816 | \#endif | ||
817 | (*(portaudio->Pa_Terminate))(); | ||
818 | return; | ||
819 | } | ||
820 | \#if (RECORDERDEBUG==1) | ||
821 | cout << "Stream opened, going to start it now..." << endl; | ||
822 | \#endif | ||
823 | err=(*(portaudio->Pa_StartStream))(portaudiostream); | ||
824 | if (err!=paNoError) { | ||
825 | \#if (RECORDERDEBUG==1) | ||
826 | cout << "Error starting stream" << endl; | ||
827 | cout << portaudio->Pa_GetErrorText(err) << endl; | ||
828 | \#endif | ||
829 | (*(portaudio->Pa_Terminate))(); | ||
830 | return; | ||
831 | } | ||
832 | \#if (RECORDERDEBUG==1) | ||
833 | cout << "Stream started" << endl; | ||
834 | \#endif | ||
835 | |||
836 | |||
837 | return;} {} | ||
838 | } | ||
839 | Function {stopPAstream()} {open private return_type void | ||
840 | } { | ||
841 | code {// only to be called by portaudio_transport_stop | ||
842 | if (portaudiostream==NULL) return; | ||
843 | PaStream* pstream=portaudiostream; | ||
844 | portaudiostream=NULL; | ||
845 | |||
846 | PaError err = (*(portaudio->Pa_StopStream))( pstream ); | ||
847 | |||
848 | if (err!=paNoError) { | ||
849 | cout << portaudio->Pa_GetErrorText(err) << endl; | ||
850 | } | ||
851 | |||
852 | err = (*(portaudio->Pa_CloseStream))( pstream ); | ||
853 | |||
854 | if (err!=paNoError) { | ||
855 | cout << portaudio->Pa_GetErrorText(err) << endl; | ||
856 | } | ||
857 | |||
858 | (*(portaudio->Pa_Terminate))();} {} | ||
859 | } | ||
860 | Function {portaudio_transport_stop()} {open private return_type void | ||
861 | } { | ||
862 | code {if (portaudio==NULL) return; | ||
863 | if (!(portaudio->libloaded)) return; | ||
864 | |||
865 | \#if (RECORDERDEBUG==1) | ||
866 | cout << "portaudio transport stop" << endl; | ||
867 | \#endif | ||
868 | // TODO: only stop stream if not monitoring input. | ||
869 | stopPAstream(); | ||
870 | portaudio_initialized=0; | ||
871 | portaudiostream=NULL; | ||
872 | portaudiooffset+=streamtime; | ||
873 | cout << "portaudiooffset at stop=" << portaudiooffset << endl; | ||
874 | if (mtsample!=NULL) | ||
875 | { | ||
876 | memutils::myfree("portaudio_transport_stop",mtsample); | ||
877 | mtsample=NULL; | ||
878 | }} {} | ||
879 | } | ||
880 | Function {hd24_transport_goloc(__uint32 frames)} {open return_type void | ||
881 | } { | ||
882 | code {if (libjack!=NULL) | ||
883 | { | ||
884 | if (libjack->libloaded) { | ||
885 | if (portaudio_initialized!=1) { | ||
886 | |||
887 | jackinit(); | ||
888 | if (jackclient!=NULL) { | ||
889 | hd24_transport_locate((__sint64)frames); | ||
890 | return; | ||
891 | } | ||
892 | } | ||
893 | } | ||
894 | } | ||
895 | |||
896 | if (portaudio!=NULL) | ||
897 | { | ||
898 | if (portaudio->libloaded) | ||
899 | { | ||
900 | hd24_transport_locate((__sint64)frames); | ||
901 | return; | ||
902 | } | ||
903 | }} {} | ||
904 | } | ||
905 | Function {hd24_transport_locate(__sint64 i)} {open return_type void | ||
906 | } { | ||
907 | code {cout << "Request to transport locate to " << i << endl; | ||
908 | if (i<0) i=0; | ||
909 | if (libjack!=NULL) | ||
910 | { | ||
911 | if (libjack->libloaded) { | ||
912 | cout << "try jackinit" << endl; | ||
913 | jackinit(); | ||
914 | if (jackclient!=NULL) { | ||
915 | libjack->jack_transport_locate(jackclient,i); | ||
916 | return; | ||
917 | } | ||
918 | } | ||
919 | cout << "Jack locate attempt inconclusive, will try portaudio if available" << endl; | ||
920 | } | ||
921 | |||
922 | if (portaudio!=NULL) | ||
923 | { | ||
924 | if (portaudio->libloaded) { | ||
925 | cout << "will have to do portaudio locate." << endl; | ||
926 | bool streamwasinitialized=true; | ||
927 | if (!(isportaudioinitialized())) | ||
928 | { | ||
929 | cout << "No previous stream, init a new one "<< endl; | ||
930 | streamwasinitialized=false; | ||
931 | if (tape==NULL) | ||
932 | { | ||
933 | return; | ||
934 | } | ||
935 | |||
936 | tape->currentlocation((i < 0) ? 0 : i); | ||
937 | cout << "set location to " << i << endl; | ||
938 | portaudiooffset=i; // still ok even without active stream | ||
939 | streamtime=i; | ||
940 | cout << "set portaudiooffset, streamtime to " << i << endl; | ||
941 | return; // <-- see if this does the trick- no previous | ||
942 | // stream, no new one. | ||
943 | } | ||
944 | |||
945 | PaError err; | ||
946 | if (portaudiostream!=NULL) | ||
947 | { | ||
948 | cout << "Still have a stream that needs stopping first." << endl; | ||
949 | err = (*(portaudio->Pa_StopStream))( portaudiostream ); | ||
950 | if (err!=paNoError) | ||
951 | { | ||
952 | // maybe another program owns the stream. | ||
953 | cout << portaudio->Pa_GetErrorText(err) << endl; | ||
954 | } | ||
955 | |||
956 | PaStream* oldportaudiostream=portaudiostream; | ||
957 | portaudiostream=NULL; | ||
958 | err = (*(portaudio->Pa_CloseStream))( oldportaudiostream ); | ||
959 | } | ||
960 | |||
961 | portaudiooffset=i; // still ok even without active stream | ||
962 | streamtime=i; // old portaudio V18 legacy | ||
963 | |||
964 | bool streamnolongerinitialized=false; | ||
965 | if (!(isportaudioinitialized())) | ||
966 | { | ||
967 | if (streamwasinitialized) | ||
968 | { | ||
969 | streamnolongerinitialized=true; | ||
970 | } | ||
971 | } | ||
972 | |||
973 | if (streamnolongerinitialized) | ||
974 | { | ||
975 | /* if closing stream means no longer initialized, | ||
976 | do not open another because we are not playing back | ||
977 | anything at the moment. */ | ||
978 | return; | ||
979 | } | ||
980 | cout << "open a fresh stream" << endl; | ||
981 | |||
982 | PaDeviceIndex indev=(*(portaudio->Pa_GetDefaultInputDevice))(); | ||
983 | PaDeviceIndex outdev=(*(portaudio->Pa_GetDefaultOutputDevice))(); | ||
984 | if (inputParameters!=NULL) | ||
985 | { | ||
986 | memset(inputParameters,'\\0',sizeof(*inputParameters)); | ||
987 | |||
988 | this->inputParameters->device=indev; | ||
989 | this->inputParameters->channelCount=2; | ||
990 | this->inputParameters->sampleFormat=paFloat32; | ||
991 | void* devinfo=(void*)(*(portaudio->Pa_GetDeviceInfo))( inputParameters->device ); | ||
992 | if (devinfo!=NULL) | ||
993 | { | ||
994 | this->inputParameters->suggestedLatency = (*(portaudio->Pa_GetDeviceInfo))( inputParameters->device )->defaultLowInputLatency; | ||
995 | } | ||
996 | this->inputParameters->hostApiSpecificStreamInfo = NULL; | ||
997 | } | ||
998 | if (outputParameters!=NULL) | ||
999 | { | ||
1000 | memset(outputParameters,'\\0',sizeof(*outputParameters)); | ||
1001 | this->outputParameters->device=outdev; | ||
1002 | this->outputParameters->channelCount=2; | ||
1003 | this->outputParameters->sampleFormat=paFloat32; | ||
1004 | void* devinfo=(void*)(*(portaudio->Pa_GetDeviceInfo))( outputParameters->device ); | ||
1005 | if (devinfo!=NULL) | ||
1006 | { | ||
1007 | this->outputParameters->suggestedLatency = (*(portaudio->Pa_GetDeviceInfo))( outputParameters->device )->defaultLowOutputLatency; | ||
1008 | } | ||
1009 | this->outputParameters->hostApiSpecificStreamInfo = NULL; | ||
1010 | } | ||
1011 | |||
1012 | double samrate=this->samplerate(); | ||
1013 | cout << " sample rate for new stream is " << samrate << endl; | ||
1014 | if (samrate==0) | ||
1015 | { | ||
1016 | return; | ||
1017 | } | ||
1018 | |||
1019 | err=(*(portaudio->Pa_OpenStream))( | ||
1020 | &portaudiostream, | ||
1021 | NULL,/*this->inputParameters,*/ | ||
1022 | this->outputParameters, | ||
1023 | samrate, | ||
1024 | PA_FRAMESPERBUF, /* frames per buffer */ | ||
1025 | paClipOff | paDitherOff, | ||
1026 | portaudio_process, | ||
1027 | this->recorder); | ||
1028 | this->havestreamtime=false; | ||
1029 | this->streamtime=0; | ||
1030 | |||
1031 | if (err!=paNoError) { | ||
1032 | cout << portaudio->Pa_GetErrorText(err) << endl; | ||
1033 | } | ||
1034 | if (err!=paNoError) { (*( portaudio->Pa_Terminate))(); return; } | ||
1035 | |||
1036 | |||
1037 | err=(*(portaudio->Pa_StartStream))(portaudiostream); | ||
1038 | if (err!=paNoError) { | ||
1039 | cout << portaudio->Pa_GetErrorText(err) << endl; | ||
1040 | } | ||
1041 | cout << "stream appears to have started successfully" << endl; | ||
1042 | |||
1043 | return; | ||
1044 | } | ||
1045 | }} {} | ||
1046 | } | ||
1047 | Function {hd24_transport_locate(__uint32 i)} {open return_type void | ||
1048 | } { | ||
1049 | code {this->hd24_transport_locate((__sint64)i);} {} | ||
1050 | } | ||
1051 | Function {hd24_transport_start()} {open return_type void | ||
1052 | } { | ||
1053 | code {if (libjack!=NULL) | ||
1054 | { | ||
1055 | if (libjack->libloaded) { | ||
1056 | jackinit(); | ||
1057 | if (jackclient!=NULL) { | ||
1058 | libjack->jack_transport_start(jackclient); | ||
1059 | return; | ||
1060 | } | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1064 | if (portaudio!=NULL) | ||
1065 | { | ||
1066 | if (portaudio->libloaded) | ||
1067 | { | ||
1068 | if (!(isportaudioinitialized())) | ||
1069 | { | ||
1070 | portaudioinit(); | ||
1071 | } | ||
1072 | if (isportaudioinitialized()) | ||
1073 | { | ||
1074 | portaudio_transport_start(); | ||
1075 | return; | ||
1076 | } | ||
1077 | } | ||
1078 | }} {} | ||
1079 | } | ||
1080 | Function {hd24_transport_stop()} {open return_type void | ||
1081 | } { | ||
1082 | code {if (recorder!=NULL) | ||
1083 | { | ||
1084 | recorder->resetpeaks(); | ||
1085 | } | ||
1086 | |||
1087 | if (libjack!=NULL) | ||
1088 | { | ||
1089 | if (libjack->libloaded) | ||
1090 | { | ||
1091 | jackinit(); | ||
1092 | if (jackclient!=NULL) | ||
1093 | { | ||
1094 | libjack->jack_transport_stop(jackclient); | ||
1095 | return; | ||
1096 | } | ||
1097 | } | ||
1098 | } | ||
1099 | |||
1100 | if (portaudio!=NULL) | ||
1101 | { | ||
1102 | if (portaudio->libloaded) | ||
1103 | { | ||
1104 | if (!(isportaudioinitialized())) | ||
1105 | { | ||
1106 | portaudioinit(); | ||
1107 | } | ||
1108 | if (isportaudioinitialized()) | ||
1109 | { | ||
1110 | portaudio_transport_stop(); | ||
1111 | return; | ||
1112 | } | ||
1113 | } | ||
1114 | }} {} | ||
1115 | } | ||
1116 | Function {hd24_transport_ffwd(long int frames)} {open return_type void | ||
1117 | } { | ||
1118 | code {if (portaudio_initialized!=1) | ||
1119 | { | ||
1120 | if (libjack!=NULL) | ||
1121 | { | ||
1122 | if (libjack->libloaded) | ||
1123 | { | ||
1124 | jackinit(); | ||
1125 | if (jackclient!=NULL) | ||
1126 | { | ||
1127 | __sint64 frame_time = /* currentlocation() */ | ||
1128 | (__sint64)(libjack->jack_get_current_transport_frame(jackclient)); | ||
1129 | hd24_transport_locate((__sint64)(frame_time+frames)); | ||
1130 | return; | ||
1131 | } | ||
1132 | } | ||
1133 | } | ||
1134 | } | ||
1135 | |||
1136 | if (portaudio!=NULL) | ||
1137 | { | ||
1138 | if (portaudio->libloaded) | ||
1139 | { | ||
1140 | __sint64 frame_time=currentlocation(); | ||
1141 | hd24_transport_locate((__sint64)(frame_time+frames)); | ||
1142 | |||
1143 | //string* dur=currsong->display_cursor(); | ||
1144 | //setstatus(*dur); | ||
1145 | //delete (dur); | ||
1146 | |||
1147 | return; | ||
1148 | } | ||
1149 | }} {} | ||
1150 | } | ||
1151 | Function {hd24_transport_rew(long int frames)} {open return_type void | ||
1152 | } { | ||
1153 | code {if (libjack!=NULL) | ||
1154 | { | ||
1155 | if (libjack->libloaded) | ||
1156 | { | ||
1157 | if (portaudio_initialized!=1) | ||
1158 | { | ||
1159 | jackinit(); | ||
1160 | if (jackclient!=NULL) | ||
1161 | { | ||
1162 | __sint64 frame_time = | ||
1163 | (__sint64)(libjack->jack_get_current_transport_frame(jackclient)); | ||
1164 | if (frames>frame_time) { | ||
1165 | hd24_transport_locate((__sint64)0); | ||
1166 | } else { | ||
1167 | hd24_transport_locate((__sint64)(frame_time-frames)); | ||
1168 | } | ||
1169 | return; | ||
1170 | } | ||
1171 | } | ||
1172 | } | ||
1173 | } | ||
1174 | |||
1175 | if (portaudio!=NULL) | ||
1176 | { | ||
1177 | if (portaudio->libloaded) { | ||
1178 | |||
1179 | __sint64 frame_time=currentlocation(); | ||
1180 | if (frames>frame_time) { | ||
1181 | hd24_transport_locate((__sint64)0); | ||
1182 | } else { | ||
1183 | hd24_transport_locate((__sint64)(frame_time-frames)); | ||
1184 | } | ||
1185 | |||
1186 | hd24_transport_locate((__sint64)(frame_time-frames)); | ||
1187 | |||
1188 | return; | ||
1189 | } | ||
1190 | }} {} | ||
1191 | } | ||
1192 | Function {isinitialized()} {return_type bool | ||
1193 | } { | ||
1194 | code {if (this->isportaudioinitialized()) | ||
1195 | { | ||
1196 | return true; | ||
1197 | } | ||
1198 | if (this->isjackinitialized()) | ||
1199 | { | ||
1200 | return true; | ||
1201 | } | ||
1202 | return false;} {} | ||
1203 | } | ||
1204 | Function {mustloop()} {return_type bool | ||
1205 | } { | ||
1206 | code {return this->as_mustloop;} {} | ||
1207 | } | ||
1208 | Function {mustloop(bool yesno)} {return_type void | ||
1209 | } { | ||
1210 | code {this->as_mustloop=yesno;} {} | ||
1211 | } | ||
1212 | Function {samplerate()} {return_type __uint32 | ||
1213 | } { | ||
1214 | code {return this->samrate; | ||
1215 | /*(double)(currsong->samplerate()/(currsong->physical_channels()/currsong->logical_channels())); */} {} | ||
1216 | } | ||
1217 | Function {samplerate(__uint32 newrate)} {return_type void | ||
1218 | } { | ||
1219 | code {this->samrate=newrate;} {} | ||
1220 | } | ||
1221 | Function {looppos()} {return_type __uint32 | ||
1222 | } { | ||
1223 | code {return this->as_looppos;} {} | ||
1224 | } | ||
1225 | Function {looppos(__uint32 newpos)} {return_type void | ||
1226 | } { | ||
1227 | code {this->as_looppos=newpos;} {} | ||
1228 | } | ||
1229 | Function {locatepoint(int locpointnum,__uint32 locatepos)} {return_type void | ||
1230 | } { | ||
1231 | code {if (tape==NULL) return; | ||
1232 | tape->setlocatepos(locpointnum,locatepos);} {} | ||
1233 | } | ||
1234 | Function {locatepoint(int locpointnum)} {return_type __uint32 | ||
1235 | } { | ||
1236 | code {if (tape==NULL) return 0; | ||
1237 | return tape->getlocatepos(locpointnum);} {} | ||
1238 | } | ||
1239 | Function {audiolib(int whichlib,void* libptr)} {open return_type void | ||
1240 | } { | ||
1241 | code {if (whichlib==AUDIOLIB_PORTAUDIO) | ||
1242 | { | ||
1243 | this->portaudio=(PortAudioWrapper*)libptr; | ||
1244 | \#if (RECORDERDEBUG==1) | ||
1245 | cout << "set portaudio lib to " << libptr << endl; | ||
1246 | \#endif | ||
1247 | return; | ||
1248 | } | ||
1249 | if (whichlib==AUDIOLIB_JACK) | ||
1250 | { | ||
1251 | this->libjack=(JackWrapper*)libptr; | ||
1252 | \#if (RECORDERDEBUG==1) | ||
1253 | cout << "set jack lib to " << libptr << endl; | ||
1254 | \#endif | ||
1255 | return; | ||
1256 | } | ||
1257 | if (whichlib==AUDIOLIB_SNDFILE) | ||
1258 | { | ||
1259 | this->soundfile=(SoundFileWrapper*)libptr; | ||
1260 | \#if (RECORDERDEBUG==1) | ||
1261 | cout << "set soundfile lib to " << libptr << endl; | ||
1262 | \#endif | ||
1263 | }} {} | ||
1264 | } | ||
1265 | Function {audiolib(int whichlib)} {open return_type {void*} | ||
1266 | } { | ||
1267 | code {if (whichlib==AUDIOLIB_PORTAUDIO) | ||
1268 | { | ||
1269 | return (void*)portaudio; | ||
1270 | } | ||
1271 | if (whichlib==AUDIOLIB_JACK) | ||
1272 | { | ||
1273 | return (void*)libjack; | ||
1274 | } | ||
1275 | if (whichlib==AUDIOLIB_SNDFILE) | ||
1276 | { | ||
1277 | return (void*)soundfile; | ||
1278 | } | ||
1279 | return NULL;} {} | ||
1280 | } | ||
1281 | Function {~AudioSystem()} {open | ||
1282 | } { | ||
1283 | code {if (inputParameters!=NULL) | ||
1284 | { | ||
1285 | delete inputParameters; | ||
1286 | inputParameters=NULL; | ||
1287 | } | ||
1288 | if (outputParameters!=NULL) | ||
1289 | { | ||
1290 | delete outputParameters; | ||
1291 | outputParameters=NULL; | ||
1292 | } | ||
1293 | \#if (RECORDERDEBUG==1) | ||
1294 | cout << "AudioSystem::~AudioSystem()" << endl; | ||
1295 | \#endif} {} | ||
1296 | } | ||
1297 | Function {audiostore(AudioStorage* store)} {open return_type void | ||
1298 | } { | ||
1299 | code {this->tape=store; | ||
1300 | if (store!=NULL) | ||
1301 | { | ||
1302 | this->samrate=store->samplerate(); | ||
1303 | }} {} | ||
1304 | } | ||
1305 | Function {audiostore()} {open return_type {AudioStorage*} | ||
1306 | } { | ||
1307 | code {return tape;} {} | ||
1308 | } | ||
1309 | Function {mixer(MixerControl* p_mixer)} {open return_type void | ||
1310 | } { | ||
1311 | code {this->mixercontrol=p_mixer;} {} | ||
1312 | } | ||
1313 | Function {mixer()} {open return_type {MixerControl*} | ||
1314 | } { | ||
1315 | code {return this->mixercontrol;} {} | ||
1316 | } | ||
1317 | } | ||
1318 | |||
1319 | class RecorderData {open | ||
1320 | } { | ||
1321 | decl {int loopmode;} {public | ||
1322 | } | ||
1323 | decl {float trackpeak[24];} {public | ||
1324 | } | ||
1325 | } | ||
1326 | |||
1327 | class RecorderControl {open | ||
1328 | } { | ||
1329 | decl {RecorderData* data;} {public | ||
1330 | } | ||
1331 | decl {RecorderUI* ui;} {public | ||
1332 | } | ||
1333 | decl {AudioSystem* audio;} {public | ||
1334 | } | ||
1335 | Function {RecorderControl()} {open | ||
1336 | } { | ||
1337 | code {this->data=new RecorderData(); | ||
1338 | init();} {} | ||
1339 | } | ||
1340 | Function {~RecorderControl()} {open | ||
1341 | } { | ||
1342 | code {if (this->data!=NULL) | ||
1343 | { | ||
1344 | delete this->data; | ||
1345 | }} {} | ||
1346 | } | ||
1347 | Function {init()} {open return_type void | ||
1348 | } { | ||
1349 | code {this->ui=NULL; | ||
1350 | this->audio=new AudioSystem(this); | ||
1351 | data->loopmode=0;} {} | ||
1352 | } | ||
1353 | Function {ready()} {open return_type int | ||
1354 | } { | ||
1355 | code {return 1;} {} | ||
1356 | } | ||
1357 | Function {parentui()} {open return_type {RecorderUI*} | ||
1358 | } { | ||
1359 | code {return this->ui;} {} | ||
1360 | } | ||
1361 | Function {parentui(RecorderUI* p_ui)} {open return_type void | ||
1362 | } { | ||
1363 | code {this->ui=p_ui;} {} | ||
1364 | } | ||
1365 | Function {loopmode()} {open return_type int | ||
1366 | } { | ||
1367 | code {return data->loopmode;} {} | ||
1368 | } | ||
1369 | Function {loopmode(int p_loopmode)} {return_type void | ||
1370 | } { | ||
1371 | code {data->loopmode=p_loopmode; | ||
1372 | if (ui!=NULL) | ||
1373 | { | ||
1374 | ui->button_loopmode->value(p_loopmode); | ||
1375 | ui->button_loopmode->redraw(); | ||
1376 | }} {} | ||
1377 | } | ||
1378 | Function {button_scrub_call(int amount,RecorderControl* mycontrol)} {open return_type {static void} | ||
1379 | } { | ||
1380 | code {if (mycontrol->audio==NULL) return; | ||
1381 | // we could get the current transport pos here; .... | ||
1382 | if (amount>0) { | ||
1383 | mycontrol->audio->hd24_transport_ffwd((__uint32)(300*amount)); | ||
1384 | } else { | ||
1385 | mycontrol->audio->hd24_transport_rew((__uint32)(-300*amount)); | ||
1386 | } | ||
1387 | // ... then the new transport pos here; read the snippet | ||
1388 | // of audio that is spanned by the difference, stretch | ||
1389 | // it to the audio buffer size, then play it. | ||
1390 | // Alternatively, a visual-only representation could be fine.} {} | ||
1391 | } | ||
1392 | Function {button_rew_call()} {open return_type void | ||
1393 | } { | ||
1394 | code {if (this->audio==NULL) return; | ||
1395 | this->audio->hd24_transport_rew(5*this->audio->samplerate());} {} | ||
1396 | } | ||
1397 | Function {button_ffwd_call()} {open return_type void | ||
1398 | } { | ||
1399 | code {if (this->audio==NULL) return; | ||
1400 | this->audio->hd24_transport_ffwd(5*this->audio->samplerate());} {} | ||
1401 | } | ||
1402 | Function {button_stop_call()} {open return_type void | ||
1403 | } { | ||
1404 | code {if (this->audio==NULL) return; | ||
1405 | //this->currenthd24->settransportstatus(hd24fs::TRANSPORTSTATUS_STOP); | ||
1406 | //TODO: The above is for monitoring purposes | ||
1407 | this->audio->hd24_transport_stop(); | ||
1408 | if (ui==NULL) return; | ||
1409 | |||
1410 | ui->button_light((void*)(ui->button_stop),1); | ||
1411 | //button_stop->up_image(button_stop_uplit->image()); | ||
1412 | ui->button_up((void*)(ui->button_play)); | ||
1413 | ui->button_up((void*)(ui->button_rec));} {} | ||
1414 | } | ||
1415 | Function {button_play_call()} {open return_type void | ||
1416 | } { | ||
1417 | code {if (this->audio==NULL) return; | ||
1418 | //if (button_rec->value()==1) { | ||
1419 | // this->currenthd24->settransportstatus(hd24fs::TRANSPORTSTATUS_REC); | ||
1420 | // TODO: The above is for monitoring purposes | ||
1421 | //} else { | ||
1422 | // this->currenthd24->settransportstatus(hd24fs::TRANSPORTSTATUS_PLAY); | ||
1423 | // TODO: The above is for monitoring purposes | ||
1424 | //} | ||
1425 | this->audio->hd24_transport_start(); | ||
1426 | |||
1427 | ui->button_light(ui->button_stop,0); | ||
1428 | |||
1429 | if (ui->button_play->value()==1) | ||
1430 | { | ||
1431 | ui->button_up(ui->button_rec); | ||
1432 | } | ||
1433 | ui->button_down(ui->button_play);} {} | ||
1434 | } | ||
1435 | Function {button_rec_call()} {open return_type void | ||
1436 | } { | ||
1437 | code {/* ui->button_rec->redraw(); | ||
1438 | if (currsong==NULL) return; | ||
1439 | if (currenthd24==NULL) return; | ||
1440 | |||
1441 | if (this->currenthd24->gettransportstatus()==hd24fs::TRANSPORTSTATUS_STOP) { | ||
1442 | return; | ||
1443 | } | ||
1444 | |||
1445 | if (ui->button_rec->value()==1) { | ||
1446 | this->currenthd24->settransportstatus(hd24fs::TRANSPORTSTATUS_REC); | ||
1447 | } else { | ||
1448 | this->currenthd24->settransportstatus(hd24fs::TRANSPORTSTATUS_PLAY); | ||
1449 | } | ||
1450 | |||
1451 | this->audio->hd24_transport_stop(); | ||
1452 | //button_play->value(0); */} {} | ||
1453 | } | ||
1454 | Function {solo(int channel,int val)} {} { | ||
1455 | code {// set solo status of channel to value | ||
1456 | //mixer->mixerchannel[channel]->control->solo(val);} {} | ||
1457 | } | ||
1458 | Function {mute(int channel,int val)} {} { | ||
1459 | code {// set mute status of channel to value | ||
1460 | //mixer->mixerchannel[channel]->control->mute(val);} {} | ||
1461 | } | ||
1462 | Function {resetpeaks()} {open return_type void | ||
1463 | } { | ||
1464 | code {for (int i=0;i<24;i++) | ||
1465 | { | ||
1466 | data->trackpeak[i]=0; | ||
1467 | }} {} | ||
1468 | } | ||
1469 | Function {highlight_setbuttons(int value)} {open return_type void | ||
1470 | } { | ||
1471 | code {ui->highlight_setbuttons(value);} {} | ||
1472 | } | ||
1473 | Function {hd24_transport_goloc(__uint32 frames)} {open return_type void | ||
1474 | } { | ||
1475 | code {if (audio==NULL) | ||
1476 | { | ||
1477 | return; | ||
1478 | } | ||
1479 | audio->hd24_transport_goloc(frames);} {} | ||
1480 | } | ||
1481 | Function {button_rehearse_call()} {return_type void | ||
1482 | } { | ||
1483 | code {return;} {} | ||
1484 | } | ||
1485 | Function {handlelocatebutton(__uint32 locpoint)} {return_type void | ||
1486 | } { | ||
1487 | code {// either set or jumpto locate point | ||
1488 | |||
1489 | if (ui->button_setlocate->value()==1) | ||
1490 | { | ||
1491 | // set locate point | ||
1492 | ui->button_setlocate->value(0); | ||
1493 | highlight_setbuttons(ui->button_setlocate->value()); | ||
1494 | // set loop start to current song cursor | ||
1495 | if (audio==NULL) return; | ||
1496 | audio->locatepoint(locpoint,audio->currentlocation()); | ||
1497 | // ui->populate_locatepoints(currsong,ui->locatepoints); | ||
1498 | } else { | ||
1499 | // jump to locate point | ||
1500 | if (audio==NULL) return; | ||
1501 | audio->hd24_transport_locate((__sint64)(audio->locatepoint(locpoint))); | ||
1502 | }} {} | ||
1503 | } | ||
1504 | Function {disable()} {} { | ||
1505 | code {/* Disable the recorder */ | ||
1506 | //fl_message("TODO: recordercontrol::disable()"); | ||
1507 | if ((this->ui)==NULL) return; | ||
1508 | this->ui->deactivate();} {} | ||
1509 | } | ||
1510 | Function {enable()} {} { | ||
1511 | code {/* Disable the recorder */ | ||
1512 | //fl_message("TODO: recordercontrol::enable()"); | ||
1513 | if ((this->ui)==NULL) return; | ||
1514 | this->ui->activate();} {} | ||
1515 | } | ||
1516 | decl {int dispwritecountdown;} {public | ||
1517 | } | ||
1518 | Function {dispwrite(unsigned int line,const char* message)} {return_type void | ||
1519 | } { | ||
1520 | code {ui->dispwrite(line,message);} {} | ||
1521 | } | ||
1522 | Function {dispwrite(unsigned int line,const char* message,__uint32 timeout_msec)} {return_type void | ||
1523 | } { | ||
1524 | code {ui->dispwrite(line,message,timeout_msec);} {} | ||
1525 | } | ||
1526 | Function {audiolib(int whichlib,void* libptr)} {open return_type void | ||
1527 | } { | ||
1528 | code {if (audio==NULL) return; | ||
1529 | audio->audiolib(whichlib,libptr);} {} | ||
1530 | } | ||
1531 | Function {song(hd24song* store)} {open return_type void | ||
1532 | } { | ||
1533 | code {audio->audiostore((AudioStorage*)store); | ||
1534 | if (store!=NULL) | ||
1535 | { | ||
1536 | this->enable(); | ||
1537 | } else { | ||
1538 | this->disable(); | ||
1539 | } | ||
1540 | if (store==NULL) | ||
1541 | { | ||
1542 | string* disp=new string(" No Song " | ||
1543 | " Selected "); | ||
1544 | dispwrite(0,disp->c_str()); | ||
1545 | delete disp; | ||
1546 | } | ||
1547 | else | ||
1548 | { | ||
1549 | |||
1550 | string disp="S"; | ||
1551 | string* idstr=Convert::int2str(store->songid(),2,"0"); | ||
1552 | disp+=*idstr; | ||
1553 | delete idstr; | ||
1554 | disp+=":\\""; | ||
1555 | string* dummy=store->songname(); | ||
1556 | //transfersource->value(dummy->c_str()); | ||
1557 | string* dummy2=Convert::readstring((unsigned char*)dummy->c_str(),0,10); | ||
1558 | string* dummy3=Convert::readstring((unsigned char*)dummy->c_str(),0,11); | ||
1559 | |||
1560 | disp+=*dummy2; | ||
1561 | delete dummy; | ||
1562 | delete dummy2; | ||
1563 | if (dummy3->length()>10) | ||
1564 | { | ||
1565 | disp+="\\4"; // arrow right | ||
1566 | } else { | ||
1567 | disp+="\\""; | ||
1568 | } | ||
1569 | delete dummy3; | ||
1570 | string* disp2=Convert::padright(disp,16," "); | ||
1571 | |||
1572 | string* dur=store->display_duration(); | ||
1573 | |||
1574 | *disp2+=dur->substr(0,8); | ||
1575 | *disp2+=":"; | ||
1576 | *disp2+=dur->substr(9,2); | ||
1577 | *disp2+=" "; | ||
1578 | delete dur; | ||
1579 | |||
1580 | if (store->iswriteprotected()) | ||
1581 | { | ||
1582 | *disp2+="\\1"; | ||
1583 | } else { | ||
1584 | *disp2+="\\2"; | ||
1585 | } | ||
1586 | string* strtracksb=Convert::int2str(store->logical_channels(),2,"0"); | ||
1587 | *disp2+=*strtracksb; | ||
1588 | delete strtracksb; | ||
1589 | *disp2+="t"; | ||
1590 | |||
1591 | dispwrite(0,disp2->c_str()); | ||
1592 | delete disp2; | ||
1593 | |||
1594 | }} {selected | ||
1595 | } | ||
1596 | } | ||
1597 | Function {song()} {open return_type {hd24song*} | ||
1598 | } { | ||
1599 | code {return (hd24song*)audio->audiostore();} {} | ||
1600 | } | ||
1601 | Function {toggletrackarmed(__uint32 base1tracknum)} {open return_type void | ||
1602 | } { | ||
1603 | code {AudioStorage* astore=(hd24song*)(this->audio->audiostore()); | ||
1604 | astore->trackarmed(base1tracknum,!astore->trackarmed(base1tracknum));} {} | ||
1605 | } | ||
1606 | } | ||
1607 | |||
1608 | class RecorderUI {: {public Fl_Group} | ||
1609 | } { | ||
1610 | decl {RecorderControl* control;} {public | ||
1611 | } | ||
1612 | Function {RecorderUI(int a,int b,int c,int d):Fl_Group(a,b,c,d,NULL)} {open | ||
1613 | } { | ||
1614 | code {this->control=new RecorderControl(); | ||
1615 | control->parentui(this); | ||
1616 | this->window=(Fl_Window*)(this->make_window()); | ||
1617 | this->init_gui();} {} | ||
1618 | } | ||
1619 | Function {~RecorderUI()} {open | ||
1620 | } { | ||
1621 | code {delete control;} {} | ||
1622 | } | ||
1623 | Function {init_gui()} {open | ||
1624 | } { | ||
1625 | code {// position vu meters on recorder tab | ||
1626 | int startx=trackchan[0]->x(); | ||
1627 | int starty=trackchan[0]->y(); | ||
1628 | for (unsigned int i=1; i<=MAXCHANNELS; i++) { | ||
1629 | int coloff=((i-((i-1)%8))-1)/8; | ||
1630 | trackchan[i-1]->setui(this); | ||
1631 | trackchan[i-1]->position(7+(18*coloff)+(startx)+((i-1)*23),starty+10); | ||
1632 | trackchan[i-1]->setchnum(i); | ||
1633 | |||
1634 | solobutton[i-1]->position(8+(15*coloff)+(startx)+((i-1)*23),solobutton[i-1]->y()); | ||
1635 | solobutton[i-1]->size(solobutton[0]->w(),solobutton[0]->h()); | ||
1636 | solobutton[i-1]->up_image(solobutton[0]->up_image()); | ||
1637 | solobutton[i-1]->down_image(solobutton[0]->down_image()); | ||
1638 | mutebutton[i-1]->up_image(mutebutton[0]->up_image()); | ||
1639 | mutebutton[i-1]->down_image(mutebutton[0]->down_image()); | ||
1640 | mutebutton[i-1]->position(solobutton[i-1]->x(),mutebutton[i-1]->y()); | ||
1641 | mutebutton[i-1]->size(mutebutton[0]->w(),mutebutton[0]->h()); | ||
1642 | |||
1643 | armbutton[i-1]->position(solobutton[i-1]->x(),armbutton[i-1]->y()); | ||
1644 | if (i!=1) { | ||
1645 | armbutton[i-1]->size(armbutton[0]->w(),armbutton[0]->h()); | ||
1646 | armbutton[i-1]->up_image(armbutton[0]->up_image()); | ||
1647 | armbutton[i-1]->down_image(armbutton[0]->down_image()); | ||
1648 | } | ||
1649 | |||
1650 | } | ||
1651 | |||
1652 | |||
1653 | trackinfo[0]->position(8*23+15,starty+10); | ||
1654 | trackinfo[1]->position(16*23+33,starty+10);} {} | ||
1655 | } | ||
1656 | Function {set_ui(HD24UserInterface* p_ui)} {open return_type void | ||
1657 | } { | ||
1658 | code {this->ui=p_ui;} {} | ||
1659 | } | ||
1660 | decl {bool mustdisplaytimer;} {public | ||
1661 | } | ||
1662 | decl {int loopmode;} {public | ||
1663 | } | ||
1664 | decl {RecorderChannelUI* recorderchannel[24];} {public | ||
1665 | } | ||
1666 | decl {/* ==== RECORDER UI STUFF ====================*/} {} | ||
1667 | decl {HD24UserInterface* ui;} {} | ||
1668 | decl {//hd24fs* currenthd24;} {public | ||
1669 | } | ||
1670 | decl {//hd24song* currsong;} {public | ||
1671 | } | ||
1672 | decl {Fl_Window* window} {} | ||
1673 | decl {int currpeakmode;} {public | ||
1674 | } | ||
1675 | decl {Fl_Box* dispcell[16][2];} {public | ||
1676 | } | ||
1677 | decl {Fl_Box* i7seg[10];} {public | ||
1678 | } | ||
1679 | decl {Fl_Box* dispfont[256];} {public | ||
1680 | } | ||
1681 | decl {int slidermoved;} {public | ||
1682 | } | ||
1683 | decl {Fl_Image_Button* armbutton[24];} {public | ||
1684 | } | ||
1685 | decl {Fl_Image_Toggle_Button* mutebutton[24];} {public | ||
1686 | } | ||
1687 | decl {Fl_Image_Toggle_Button* solobutton[24];} {public | ||
1688 | } | ||
1689 | decl {int blinkcounter; /* For blinking record enable leds of level meters etc */} {public | ||
1690 | } | ||
1691 | decl {HD24TrackChannel* trackchan[24];} {public | ||
1692 | } | ||
1693 | decl {TrackInfo* trackinfo[24];} {public | ||
1694 | } | ||
1695 | decl {char olddisp[32];} {} | ||
1696 | Function {dispwrite_raw(unsigned int line,const char* message,bool savedisp)} {private return_type void | ||
1697 | } { | ||
1698 | code {unsigned int max=strlen(message); | ||
1699 | // allowed lines on display: 0 and 1 | ||
1700 | if (line>1) { return; } | ||
1701 | |||
1702 | if (max>(16*(2-line))) { | ||
1703 | // maximum 16 chars if we start on line 1 (second line) | ||
1704 | // 32 chars if we start on line 0 (first line). | ||
1705 | max=(16*(2-line)); | ||
1706 | } | ||
1707 | |||
1708 | for (unsigned int i=0;i<max;i++) { | ||
1709 | if (i==16) { line++; } | ||
1710 | unsigned int currchar=(unsigned int)((unsigned char)(message[i])); | ||
1711 | if (savedisp) | ||
1712 | { | ||
1713 | olddisp[(i%16)+(16*line)]=currchar; | ||
1714 | } | ||
1715 | this->dispcell[i%16][line]->image(dispfont[currchar]->image()); | ||
1716 | this->dispcell[i%16][line]->redraw(); | ||
1717 | |||
1718 | } | ||
1719 | fl_check();} {} | ||
1720 | } | ||
1721 | decl {int dispwritecountdown;} {public | ||
1722 | } | ||
1723 | Function {dispwrite(unsigned int line,const char* message)} {return_type void | ||
1724 | } { | ||
1725 | code {dispwrite_raw(line,message,true); | ||
1726 | dispwritecountdown=0;} {} | ||
1727 | } | ||
1728 | Function {disprestore()} {return_type void | ||
1729 | } { | ||
1730 | code {dispwrite_raw(0,&olddisp[0],false); | ||
1731 | dispwritecountdown=0;} {} | ||
1732 | } | ||
1733 | Function {dispwrite(unsigned int line,const char* message,__uint32 timeout_msec)} {return_type void | ||
1734 | } { | ||
1735 | code {dispwrite_raw(line,message,false); | ||
1736 | dispwritecountdown=(int)(1000*TIMEOUT);} {} | ||
1737 | } | ||
1738 | Function {readmixer()} {open return_type void | ||
1739 | } { | ||
1740 | code {// set solo status of channel to value | ||
1741 | /* | ||
1742 | for (unsigned int i=0;i<MAXCHANNELS;i++) { | ||
1743 | solobutton[i]->value(mixer->mixerchannel[i]->control->solo()); | ||
1744 | solobutton[i]->redraw(); | ||
1745 | mutebutton[i]->value(mixer->mixerchannel[i]->control->mute()); | ||
1746 | mutebutton[i]->redraw(); | ||
1747 | } | ||
1748 | */} {} | ||
1749 | } | ||
1750 | Function {make_window() /*<-----------------------------------*/} {open | ||
1751 | } { | ||
1752 | Fl_Window recordergroup {open | ||
1753 | xywh {378 259 615 440} type Double | ||
1754 | code0 {o->position(this->x(),this->y());} | ||
1755 | class Fl_Group visible | ||
1756 | } { | ||
1757 | Fl_Group resources {open | ||
1758 | xywh {25 62 560 423} hide deactivate | ||
1759 | } { | ||
1760 | Fl_Button button_play_up { | ||
1761 | tooltip Play image {images/button_play.gif} xywh {25 75 50 30} labelsize 11 align 16 deactivate | ||
1762 | } | ||
1763 | Fl_Button button_play_dn { | ||
1764 | tooltip Play image {images/button_play_dn.gif} xywh {75 75 50 30} labelsize 11 align 16 deactivate | ||
1765 | } | ||
1766 | Fl_Button button_stop_dn { | ||
1767 | tooltip Play image {images/button_stop_dn.gif} xywh {295 445 50 30} labelsize 11 align 16 deactivate | ||
1768 | } | ||
1769 | Fl_Button button_stop_up { | ||
1770 | tooltip Play image {images/button_stop.gif} xywh {345 445 50 30} labelsize 11 align 16 deactivate | ||
1771 | } | ||
1772 | Fl_Button button_stop_uplit { | ||
1773 | tooltip Play image {images/button_stop_uplit.gif} xywh {355 455 50 30} labelsize 11 align 16 deactivate | ||
1774 | } | ||
1775 | Fl_Button button_small_up { | ||
1776 | tooltip arm image {images/button_small.gif} xywh {565 195 20 15} deactivate | ||
1777 | } | ||
1778 | Fl_Button button_small_dn { | ||
1779 | tooltip arm image {images/button_small_dn.gif} xywh {60 215 20 15} deactivate | ||
1780 | } | ||
1781 | Fl_Button button_rew_up { | ||
1782 | tooltip Play image {images/button_rew.gif} xywh {35 85 50 30} labelsize 11 align 16 deactivate | ||
1783 | } | ||
1784 | Fl_Button button_rew_dn { | ||
1785 | tooltip Play image {images/button_rew_dn.gif} xywh {85 85 50 30} labelsize 11 align 16 deactivate | ||
1786 | } | ||
1787 | Fl_Button button_ffwd_up { | ||
1788 | tooltip Play image {images/button_ffwd.gif} xywh {45 95 50 30} labelsize 11 align 16 deactivate | ||
1789 | } | ||
1790 | Fl_Button button_ffwd_dn { | ||
1791 | tooltip Play image {images/button_ffwd_dn.gif} xywh {95 95 50 30} labelsize 11 align 16 deactivate | ||
1792 | } | ||
1793 | Fl_Button button_rec_up { | ||
1794 | tooltip Play image {images/button_rec.gif} xywh {55 105 50 30} labelsize 11 align 16 deactivate | ||
1795 | } | ||
1796 | Fl_Button button_rec_dn { | ||
1797 | tooltip Play image {images/button_rec_dn.gif} xywh {105 105 50 30} labelsize 11 align 16 deactivate | ||
1798 | } | ||
1799 | Fl_Button button_mute_up { | ||
1800 | tooltip Play image {images/button_mute.gif} xywh {65 115 50 30} labelsize 11 align 16 deactivate | ||
1801 | } | ||
1802 | Fl_Button button_mute_dn { | ||
1803 | tooltip Play image {images/button_mute_dn.gif} xywh {115 115 50 30} labelsize 11 align 16 deactivate | ||
1804 | } | ||
1805 | Fl_Button button_solo_up { | ||
1806 | tooltip Play image {images/button_solo.gif} xywh {75 125 50 30} labelsize 11 align 16 deactivate | ||
1807 | } | ||
1808 | Fl_Button button_solo_dn { | ||
1809 | tooltip Play image {images/button_solo_dn.gif} xywh {125 125 50 30} labelsize 11 align 16 deactivate | ||
1810 | } | ||
1811 | Fl_Button button_lrc_led_up { | ||
1812 | tooltip Play image {images/button_lrc_led.gif} xywh {85 135 50 30} labelsize 11 align 16 deactivate | ||
1813 | } | ||
1814 | Fl_Button button_lrc_led_dn { | ||
1815 | tooltip Play image {images/button_lrc_led_dn.gif} xywh {135 135 50 30} labelsize 11 align 16 deactivate | ||
1816 | } | ||
1817 | Fl_Button button_lrc_led_on_up { | ||
1818 | tooltip Play image {images/button_lrc_led_on.gif} xywh {85 135 50 30} labelsize 11 align 16 deactivate | ||
1819 | } | ||
1820 | Fl_Button button_lrc_led_on_dn { | ||
1821 | tooltip Play image {images/button_lrc_led_on_dn.gif} xywh {135 135 50 30} labelsize 11 align 16 deactivate | ||
1822 | } | ||
1823 | Fl_Button button_lrc_up { | ||
1824 | tooltip Play image {images/button_lrc.gif} xywh {85 135 50 30} labelsize 11 align 16 deactivate | ||
1825 | } | ||
1826 | Fl_Button button_lrc_dn { | ||
1827 | tooltip Play image {images/button_lrc_dn.gif} xywh {135 135 50 30} labelsize 11 align 16 deactivate | ||
1828 | } | ||
1829 | Fl_Box i7seg0 { | ||
1830 | image {images/7seg_0.gif} xywh {325 276 20 34} hide | ||
1831 | code0 {i7seg[0]=o;} | ||
1832 | } | ||
1833 | Fl_Box i7seg1 { | ||
1834 | image {images/7seg_1.gif} xywh {325 276 20 34} hide | ||
1835 | code0 {i7seg[1]=o;} | ||
1836 | } | ||
1837 | Fl_Box i7seg2 { | ||
1838 | image {images/7seg_2.gif} xywh {325 276 20 34} hide | ||
1839 | code0 {i7seg[2]=o;} | ||
1840 | } | ||
1841 | Fl_Box i7seg3 { | ||
1842 | image {images/7seg_3.gif} xywh {325 276 20 34} hide | ||
1843 | code0 {i7seg[3]=o;} | ||
1844 | } | ||
1845 | Fl_Box i7seg4 { | ||
1846 | image {images/7seg_4.gif} xywh {325 276 20 34} hide | ||
1847 | code0 {i7seg[4]=o;} | ||
1848 | } | ||
1849 | Fl_Box i7seg5 { | ||
1850 | image {images/7seg_5.gif} xywh {325 276 20 34} hide | ||
1851 | code0 {i7seg[5]=o;} | ||
1852 | } | ||
1853 | Fl_Box i7seg6 { | ||
1854 | image {images/7seg_6.gif} xywh {325 276 20 34} hide | ||
1855 | code0 {i7seg[6]=o;} | ||
1856 | } | ||
1857 | Fl_Box i7seg7 { | ||
1858 | image {images/7seg_7.gif} xywh {325 276 20 34} hide | ||
1859 | code0 {i7seg[7]=o;} | ||
1860 | } | ||
1861 | Fl_Box i7seg8 { | ||
1862 | image {images/7seg_8.gif} xywh {325 276 20 34} hide | ||
1863 | code0 {i7seg[8]=o;} | ||
1864 | } | ||
1865 | Fl_Box i7seg9 { | ||
1866 | image {images/7seg_9.gif} xywh {325 276 20 34} hide | ||
1867 | code0 {i7seg[9]=o;} | ||
1868 | } | ||
1869 | Fl_Group dispfontgroup { | ||
1870 | label font open | ||
1871 | xywh {565 28 70 52} hide deactivate | ||
1872 | } { | ||
1873 | Fl_Box {} { | ||
1874 | label label | ||
1875 | image {images/HD24_matrix_32.gif} xywh {580 43 35 17} hide | ||
1876 | code0 {this->dispfont[32]=o;} | ||
1877 | } | ||
1878 | Fl_Box {} { | ||
1879 | label label | ||
1880 | image {images/HD24_matrix_33.gif} xywh {580 43 35 17} hide | ||
1881 | code0 {this->dispfont[33]=o;} | ||
1882 | } | ||
1883 | Fl_Box {} { | ||
1884 | label label | ||
1885 | image {images/HD24_matrix_34.gif} xywh {580 43 35 17} hide | ||
1886 | code0 {this->dispfont[34]=o;} | ||
1887 | } | ||
1888 | Fl_Box {} { | ||
1889 | label label | ||
1890 | image {images/HD24_matrix_35.gif} xywh {580 43 35 17} hide | ||
1891 | code0 {this->dispfont[35]=o;} | ||
1892 | } | ||
1893 | Fl_Box {} { | ||
1894 | label label | ||
1895 | image {images/HD24_matrix_36.gif} xywh {580 43 35 17} hide | ||
1896 | code0 {this->dispfont[36]=o;} | ||
1897 | } | ||
1898 | Fl_Box {} { | ||
1899 | label label | ||
1900 | image {images/HD24_matrix_37.gif} xywh {580 43 35 17} hide | ||
1901 | code0 {this->dispfont[37]=o;} | ||
1902 | } | ||
1903 | Fl_Box {} { | ||
1904 | label label | ||
1905 | image {images/HD24_matrix_38.gif} xywh {580 43 35 17} hide | ||
1906 | code0 {this->dispfont[38]=o;} | ||
1907 | } | ||
1908 | Fl_Box {} { | ||
1909 | label label | ||
1910 | image {images/HD24_matrix_39.gif} xywh {580 43 35 17} hide | ||
1911 | code0 {this->dispfont[39]=o;} | ||
1912 | } | ||
1913 | Fl_Box {} { | ||
1914 | label label | ||
1915 | image {images/HD24_matrix_40.gif} xywh {580 43 35 17} hide | ||
1916 | code0 {this->dispfont[40]=o;} | ||
1917 | } | ||
1918 | Fl_Box {} { | ||
1919 | label label | ||
1920 | image {images/HD24_matrix_41.gif} xywh {580 43 35 17} hide | ||
1921 | code0 {this->dispfont[41]=o;} | ||
1922 | } | ||
1923 | Fl_Box {} { | ||
1924 | label label | ||
1925 | image {images/HD24_matrix_42.gif} xywh {580 43 35 17} hide | ||
1926 | code0 {this->dispfont[42]=o;} | ||
1927 | } | ||
1928 | Fl_Box {} { | ||
1929 | label label | ||
1930 | image {images/HD24_matrix_43.gif} xywh {580 43 35 17} hide | ||
1931 | code0 {this->dispfont[43]=o;} | ||
1932 | } | ||
1933 | Fl_Box {} { | ||
1934 | label label | ||
1935 | image {images/HD24_matrix_44.gif} xywh {580 43 35 17} hide | ||
1936 | code0 {this->dispfont[44]=o;} | ||
1937 | } | ||
1938 | Fl_Box {} { | ||
1939 | label label | ||
1940 | image {images/HD24_matrix_45.gif} xywh {580 43 35 17} hide | ||
1941 | code0 {this->dispfont[45]=o;} | ||
1942 | } | ||
1943 | Fl_Box {} { | ||
1944 | label label | ||
1945 | image {images/HD24_matrix_46.gif} xywh {580 43 35 17} hide | ||
1946 | code0 {this->dispfont[46]=o;} | ||
1947 | } | ||
1948 | Fl_Box {} { | ||
1949 | label label | ||
1950 | image {images/HD24_matrix_47.gif} xywh {580 43 35 17} hide | ||
1951 | code0 {this->dispfont[47]=o;} | ||
1952 | } | ||
1953 | Fl_Box {} { | ||
1954 | label label | ||
1955 | image {images/HD24_matrix_48.gif} xywh {580 43 35 17} hide | ||
1956 | code0 {this->dispfont[48]=o;} | ||
1957 | } | ||
1958 | Fl_Box {} { | ||
1959 | label label | ||
1960 | image {images/HD24_matrix_49.gif} xywh {580 43 35 17} hide | ||
1961 | code0 {this->dispfont[49]=o;} | ||
1962 | } | ||
1963 | Fl_Box {} { | ||
1964 | label label | ||
1965 | image {images/HD24_matrix_50.gif} xywh {580 43 35 17} hide | ||
1966 | code0 {this->dispfont[50]=o;} | ||
1967 | } | ||
1968 | Fl_Box {} { | ||
1969 | label label | ||
1970 | image {images/HD24_matrix_51.gif} xywh {580 43 35 17} hide | ||
1971 | code0 {this->dispfont[51]=o;} | ||
1972 | } | ||
1973 | Fl_Box {} { | ||
1974 | label label | ||
1975 | image {images/HD24_matrix_52.gif} xywh {580 43 35 17} hide | ||
1976 | code0 {this->dispfont[52]=o;} | ||
1977 | } | ||
1978 | Fl_Box {} { | ||
1979 | label label | ||
1980 | image {images/HD24_matrix_53.gif} xywh {580 43 35 17} hide | ||
1981 | code0 {this->dispfont[53]=o;} | ||
1982 | } | ||
1983 | Fl_Box {} { | ||
1984 | label label | ||
1985 | image {images/HD24_matrix_54.gif} xywh {580 43 35 17} hide | ||
1986 | code0 {this->dispfont[54]=o;} | ||
1987 | } | ||
1988 | Fl_Box {} { | ||
1989 | label label | ||
1990 | image {images/HD24_matrix_55.gif} xywh {580 43 35 17} hide | ||
1991 | code0 {this->dispfont[55]=o;} | ||
1992 | } | ||
1993 | Fl_Box {} { | ||
1994 | label label | ||
1995 | image {images/HD24_matrix_56.gif} xywh {580 43 35 17} hide | ||
1996 | code0 {this->dispfont[56]=o;} | ||
1997 | } | ||
1998 | Fl_Box {} { | ||
1999 | label label | ||
2000 | image {images/HD24_matrix_57.gif} xywh {580 43 35 17} hide | ||
2001 | code0 {this->dispfont[57]=o;} | ||
2002 | } | ||
2003 | Fl_Box {} { | ||
2004 | label label | ||
2005 | image {images/HD24_matrix_58.gif} xywh {580 43 35 17} hide | ||
2006 | code0 {this->dispfont[58]=o;} | ||
2007 | } | ||
2008 | Fl_Box {} { | ||
2009 | label label | ||
2010 | image {images/HD24_matrix_59.gif} xywh {580 43 35 17} hide | ||
2011 | code0 {this->dispfont[59]=o;} | ||
2012 | } | ||
2013 | Fl_Box {} { | ||
2014 | label label | ||
2015 | image {images/HD24_matrix_60.gif} xywh {580 43 35 17} hide | ||
2016 | code0 {this->dispfont[60]=o;} | ||
2017 | } | ||
2018 | Fl_Box {} { | ||
2019 | label label | ||
2020 | image {images/HD24_matrix_61.gif} xywh {580 43 35 17} hide | ||
2021 | code0 {this->dispfont[61]=o;} | ||
2022 | } | ||
2023 | Fl_Box {} { | ||
2024 | label label | ||
2025 | image {images/HD24_matrix_62.gif} xywh {580 43 35 17} hide | ||
2026 | code0 {this->dispfont[62]=o;} | ||
2027 | } | ||
2028 | Fl_Box {} { | ||
2029 | label label | ||
2030 | image {images/HD24_matrix_63.gif} xywh {580 43 35 17} hide | ||
2031 | code0 {this->dispfont[63]=o;} | ||
2032 | } | ||
2033 | Fl_Box {} { | ||
2034 | label label | ||
2035 | image {images/HD24_matrix_64.gif} xywh {580 43 35 17} hide | ||
2036 | code0 {this->dispfont[64]=o;} | ||
2037 | } | ||
2038 | Fl_Box {} { | ||
2039 | label A | ||
2040 | image {images/HD24_matrix_65.gif} xywh {580 43 35 17} hide | ||
2041 | code0 {this->dispfont[65]=o;} | ||
2042 | } | ||
2043 | Fl_Box {} { | ||
2044 | label B | ||
2045 | image {images/HD24_matrix_66.gif} xywh {580 43 35 17} hide | ||
2046 | code0 {this->dispfont[66]=o;} | ||
2047 | } | ||
2048 | Fl_Box {} { | ||
2049 | label C | ||
2050 | image {images/HD24_matrix_67.gif} xywh {580 43 35 17} hide | ||
2051 | code0 {this->dispfont[67]=o;} | ||
2052 | } | ||
2053 | Fl_Box {} { | ||
2054 | label D | ||
2055 | image {images/HD24_matrix_68.gif} xywh {580 43 35 17} hide | ||
2056 | code0 {this->dispfont[68]=o;} | ||
2057 | } | ||
2058 | Fl_Box {} { | ||
2059 | label E | ||
2060 | image {images/HD24_matrix_69.gif} xywh {580 43 35 17} hide | ||
2061 | code0 {this->dispfont[69]=o;} | ||
2062 | } | ||
2063 | Fl_Box {} { | ||
2064 | label F | ||
2065 | image {images/HD24_matrix_70.gif} xywh {580 43 35 17} hide | ||
2066 | code0 {this->dispfont[70]=o;} | ||
2067 | } | ||
2068 | Fl_Box {} { | ||
2069 | label G | ||
2070 | image {images/HD24_matrix_71.gif} xywh {580 43 35 17} hide | ||
2071 | code0 {this->dispfont[71]=o;} | ||
2072 | } | ||
2073 | Fl_Box {} { | ||
2074 | label H | ||
2075 | image {images/HD24_matrix_72.gif} xywh {580 43 35 17} hide | ||
2076 | code0 {this->dispfont[72]=o;} | ||
2077 | } | ||
2078 | Fl_Box {} { | ||
2079 | label I | ||
2080 | image {images/HD24_matrix_73.gif} xywh {580 43 35 17} hide | ||
2081 | code0 {this->dispfont[73]=o;} | ||
2082 | } | ||
2083 | Fl_Box {} { | ||
2084 | label J | ||
2085 | image {images/HD24_matrix_74.gif} xywh {580 43 35 17} hide | ||
2086 | code0 {this->dispfont[74]=o;} | ||
2087 | } | ||
2088 | Fl_Box {} { | ||
2089 | label K | ||
2090 | image {images/HD24_matrix_75.gif} xywh {580 43 35 17} hide | ||
2091 | code0 {this->dispfont[75]=o;} | ||
2092 | } | ||
2093 | Fl_Box {} { | ||
2094 | label L | ||
2095 | image {images/HD24_matrix_76.gif} xywh {580 43 35 17} hide | ||
2096 | code0 {this->dispfont[76]=o;} | ||
2097 | } | ||
2098 | Fl_Box {} { | ||
2099 | label M | ||
2100 | image {images/HD24_matrix_77.gif} xywh {580 43 35 17} hide | ||
2101 | code0 {this->dispfont[77]=o;} | ||
2102 | } | ||
2103 | Fl_Box {} { | ||
2104 | label N | ||
2105 | image {images/HD24_matrix_78.gif} xywh {580 43 35 17} hide | ||
2106 | code0 {this->dispfont[78]=o;} | ||
2107 | } | ||
2108 | Fl_Box {} { | ||
2109 | label O | ||
2110 | image {images/HD24_matrix_79.gif} xywh {580 43 35 17} hide | ||
2111 | code0 {this->dispfont[79]=o;} | ||
2112 | } | ||
2113 | Fl_Box {} { | ||
2114 | label P | ||
2115 | image {images/HD24_matrix_80.gif} xywh {580 43 35 17} hide | ||
2116 | code0 {this->dispfont[80]=o;} | ||
2117 | } | ||
2118 | Fl_Box {} { | ||
2119 | label Q | ||
2120 | image {images/HD24_matrix_81.gif} xywh {580 43 35 17} hide | ||
2121 | code0 {this->dispfont[81]=o;} | ||
2122 | } | ||
2123 | Fl_Box {} { | ||
2124 | label R | ||
2125 | image {images/HD24_matrix_82.gif} xywh {580 43 35 17} hide | ||
2126 | code0 {this->dispfont[82]=o;} | ||
2127 | } | ||
2128 | Fl_Box {} { | ||
2129 | label S | ||
2130 | image {images/HD24_matrix_83.gif} xywh {580 43 35 17} hide | ||
2131 | code0 {this->dispfont[83]=o;} | ||
2132 | } | ||
2133 | Fl_Box {} { | ||
2134 | label T | ||
2135 | image {images/HD24_matrix_84.gif} xywh {580 43 35 17} hide | ||
2136 | code0 {this->dispfont[84]=o;} | ||
2137 | } | ||
2138 | Fl_Box {} { | ||
2139 | label U | ||
2140 | image {images/HD24_matrix_85.gif} xywh {580 43 35 17} hide | ||
2141 | code0 {this->dispfont[85]=o;} | ||
2142 | } | ||
2143 | Fl_Box {} { | ||
2144 | label V | ||
2145 | image {images/HD24_matrix_86.gif} xywh {580 43 35 17} hide | ||
2146 | code0 {this->dispfont[86]=o;} | ||
2147 | } | ||
2148 | Fl_Box {} { | ||
2149 | label W | ||
2150 | image {images/HD24_matrix_87.gif} xywh {580 43 35 17} hide | ||
2151 | code0 {this->dispfont[87]=o;} | ||
2152 | } | ||
2153 | Fl_Box {} { | ||
2154 | label X | ||
2155 | image {images/HD24_matrix_88.gif} xywh {580 43 35 17} hide | ||
2156 | code0 {this->dispfont[88]=o;} | ||
2157 | } | ||
2158 | Fl_Box {} { | ||
2159 | label Y | ||
2160 | image {images/HD24_matrix_89.gif} xywh {580 43 35 17} hide | ||
2161 | code0 {this->dispfont[89]=o;} | ||
2162 | } | ||
2163 | Fl_Box {} { | ||
2164 | label Z | ||
2165 | image {images/HD24_matrix_90.gif} xywh {580 43 35 17} hide | ||
2166 | code0 {this->dispfont[90]=o;} | ||
2167 | } | ||
2168 | Fl_Box {} { | ||
2169 | label label | ||
2170 | image {images/HD24_matrix_91.gif} xywh {580 43 35 17} hide | ||
2171 | code0 {this->dispfont[91]=o;} | ||
2172 | } | ||
2173 | Fl_Box {} { | ||
2174 | label label | ||
2175 | image {images/HD24_matrix_92.gif} xywh {580 43 35 17} hide | ||
2176 | code0 {this->dispfont[92]=o;} | ||
2177 | } | ||
2178 | Fl_Box {} { | ||
2179 | label label | ||
2180 | image {images/HD24_matrix_93.gif} xywh {580 43 35 17} hide | ||
2181 | code0 {this->dispfont[93]=o;} | ||
2182 | } | ||
2183 | Fl_Box {} { | ||
2184 | label label | ||
2185 | image {images/HD24_matrix_94.gif} xywh {580 43 35 17} hide | ||
2186 | code0 {this->dispfont[94]=o;} | ||
2187 | } | ||
2188 | Fl_Box {} { | ||
2189 | label label | ||
2190 | image {images/HD24_matrix_95.gif} xywh {580 43 35 17} hide | ||
2191 | code0 {this->dispfont[95]=o;} | ||
2192 | } | ||
2193 | Fl_Box {} { | ||
2194 | label label | ||
2195 | image {images/HD24_matrix_96.gif} xywh {580 43 35 17} hide | ||
2196 | code0 {this->dispfont[96]=o;} | ||
2197 | } | ||
2198 | Fl_Box {} { | ||
2199 | label label | ||
2200 | image {images/HD24_matrix_97.gif} xywh {580 43 35 17} hide | ||
2201 | code0 {this->dispfont[97]=o;} | ||
2202 | } | ||
2203 | Fl_Box {} { | ||
2204 | label label | ||
2205 | image {images/HD24_matrix_98.gif} xywh {580 43 35 17} hide | ||
2206 | code0 {this->dispfont[98]=o;} | ||
2207 | } | ||
2208 | Fl_Box {} { | ||
2209 | label label | ||
2210 | image {images/HD24_matrix_99.gif} xywh {580 43 35 17} hide | ||
2211 | code0 {this->dispfont[99]=o;} | ||
2212 | } | ||
2213 | Fl_Box {} { | ||
2214 | label label | ||
2215 | image {images/HD24_matrix_100.gif} xywh {580 43 35 17} hide | ||
2216 | code0 {this->dispfont[100]=o;} | ||
2217 | } | ||
2218 | Fl_Box {} { | ||
2219 | label label | ||
2220 | image {images/HD24_matrix_101.gif} xywh {580 43 35 17} hide | ||
2221 | code0 {this->dispfont[101]=o;} | ||
2222 | } | ||
2223 | Fl_Box {} { | ||
2224 | label label | ||
2225 | image {images/HD24_matrix_102.gif} xywh {580 43 35 17} hide | ||
2226 | code0 {this->dispfont[102]=o;} | ||
2227 | } | ||
2228 | Fl_Box {} { | ||
2229 | label label | ||
2230 | image {images/HD24_matrix_103.gif} xywh {580 43 35 17} hide | ||
2231 | code0 {this->dispfont[103]=o;} | ||
2232 | } | ||
2233 | Fl_Box {} { | ||
2234 | label label | ||
2235 | image {images/HD24_matrix_104.gif} xywh {580 43 35 17} hide | ||
2236 | code0 {this->dispfont[104]=o;} | ||
2237 | } | ||
2238 | Fl_Box {} { | ||
2239 | label label | ||
2240 | image {images/HD24_matrix_105.gif} xywh {580 43 35 17} hide | ||
2241 | code0 {this->dispfont[105]=o;} | ||
2242 | } | ||
2243 | Fl_Box {} { | ||
2244 | label label | ||
2245 | image {images/HD24_matrix_106.gif} xywh {580 43 35 17} hide | ||
2246 | code0 {this->dispfont[106]=o;} | ||
2247 | } | ||
2248 | Fl_Box {} { | ||
2249 | label label | ||
2250 | image {images/HD24_matrix_107.gif} xywh {580 43 35 17} hide | ||
2251 | code0 {this->dispfont[107]=o;} | ||
2252 | } | ||
2253 | Fl_Box {} { | ||
2254 | label label | ||
2255 | image {images/HD24_matrix_108.gif} xywh {580 43 35 17} hide | ||
2256 | code0 {this->dispfont[108]=o;} | ||
2257 | } | ||
2258 | Fl_Box {} { | ||
2259 | label label | ||
2260 | image {images/HD24_matrix_109.gif} xywh {580 43 35 17} hide | ||
2261 | code0 {this->dispfont[109]=o;} | ||
2262 | } | ||
2263 | Fl_Box {} { | ||
2264 | label label | ||
2265 | image {images/HD24_matrix_110.gif} xywh {580 43 35 17} hide | ||
2266 | code0 {this->dispfont[110]=o;} | ||
2267 | } | ||
2268 | Fl_Box {} { | ||
2269 | label label | ||
2270 | image {images/HD24_matrix_111.gif} xywh {580 43 35 17} hide | ||
2271 | code0 {this->dispfont[111]=o;} | ||
2272 | } | ||
2273 | Fl_Box {} { | ||
2274 | label label | ||
2275 | image {images/HD24_matrix_112.gif} xywh {580 43 35 17} hide | ||
2276 | code0 {this->dispfont[112]=o;} | ||
2277 | } | ||
2278 | Fl_Box {} { | ||
2279 | label label | ||
2280 | image {images/HD24_matrix_113.gif} xywh {580 43 35 17} hide | ||
2281 | code0 {this->dispfont[113]=o;} | ||
2282 | } | ||
2283 | Fl_Box {} { | ||
2284 | label label | ||
2285 | image {images/HD24_matrix_114.gif} xywh {580 43 35 17} hide | ||
2286 | code0 {this->dispfont[114]=o;} | ||
2287 | } | ||
2288 | Fl_Box {} { | ||
2289 | label label | ||
2290 | image {images/HD24_matrix_115.gif} xywh {580 43 35 17} hide | ||
2291 | code0 {this->dispfont[115]=o;} | ||
2292 | } | ||
2293 | Fl_Box {} { | ||
2294 | label label | ||
2295 | image {images/HD24_matrix_116.gif} xywh {580 43 35 17} hide | ||
2296 | code0 {this->dispfont[116]=o;} | ||
2297 | } | ||
2298 | Fl_Box {} { | ||
2299 | label label | ||
2300 | image {images/HD24_matrix_117.gif} xywh {580 43 35 17} hide | ||
2301 | code0 {this->dispfont[117]=o;} | ||
2302 | } | ||
2303 | Fl_Box {} { | ||
2304 | label label | ||
2305 | image {images/HD24_matrix_118.gif} xywh {580 43 35 17} hide | ||
2306 | code0 {this->dispfont[118]=o;} | ||
2307 | } | ||
2308 | Fl_Box {} { | ||
2309 | label label | ||
2310 | image {images/HD24_matrix_119.gif} xywh {580 43 35 17} hide | ||
2311 | code0 {this->dispfont[119]=o;} | ||
2312 | } | ||
2313 | Fl_Box {} { | ||
2314 | label label | ||
2315 | image {images/HD24_matrix_120.gif} xywh {580 43 35 17} hide | ||
2316 | code0 {this->dispfont[120]=o;} | ||
2317 | } | ||
2318 | Fl_Box {} { | ||
2319 | label label | ||
2320 | image {images/HD24_matrix_121.gif} xywh {580 43 35 17} hide | ||
2321 | code0 {this->dispfont[121]=o;} | ||
2322 | } | ||
2323 | Fl_Box {} { | ||
2324 | label label | ||
2325 | image {images/HD24_matrix_122.gif} xywh {580 43 35 17} hide | ||
2326 | code0 {this->dispfont[122]=o;} | ||
2327 | } | ||
2328 | Fl_Box {} { | ||
2329 | label label | ||
2330 | image {images/HD24_matrix_123.gif} xywh {580 43 35 17} hide | ||
2331 | code0 {this->dispfont[123]=o;} | ||
2332 | } | ||
2333 | Fl_Box {} { | ||
2334 | label label | ||
2335 | image {images/HD24_matrix_124.gif} xywh {580 43 35 17} hide | ||
2336 | code0 {this->dispfont[124]=o;} | ||
2337 | } | ||
2338 | Fl_Box {} { | ||
2339 | label label | ||
2340 | image {images/HD24_matrix_125.gif} xywh {580 43 35 17} hide | ||
2341 | code0 {this->dispfont[125]=o;} | ||
2342 | } | ||
2343 | Fl_Box {} { | ||
2344 | label label | ||
2345 | image {images/HD24_matrix_126.gif} xywh {580 43 35 17} hide | ||
2346 | code0 {this->dispfont[126]=o;} | ||
2347 | } | ||
2348 | Fl_Box {} { | ||
2349 | label label | ||
2350 | image {images/HD24_matrix_127.gif} xywh {580 43 35 17} hide | ||
2351 | code0 {this->dispfont[127]=o;} | ||
2352 | } | ||
2353 | Fl_Box {} { | ||
2354 | label writeprotect | ||
2355 | image {images/HD24_matrix_writeprotected.gif} xywh {590 53 35 17} hide | ||
2356 | code0 {this->dispfont[1]=o;} | ||
2357 | } | ||
2358 | Fl_Box {} { | ||
2359 | label writeenable | ||
2360 | image {images/HD24_matrix_writeenabled.gif} xywh {600 63 35 17} hide | ||
2361 | code0 {this->dispfont[2]=o;} | ||
2362 | } | ||
2363 | Fl_Box {} { | ||
2364 | label {arrow left} | ||
2365 | image {images/HD24_matrix_arrowleft.gif} xywh {600 63 35 17} hide | ||
2366 | code0 {this->dispfont[3]=o;} | ||
2367 | } | ||
2368 | Fl_Box {} { | ||
2369 | label {arrow right} | ||
2370 | image {images/HD24_matrix_arrowright.gif} xywh {610 73 35 17} hide | ||
2371 | code0 {this->dispfont[4]=o;} | ||
2372 | } | ||
2373 | } | ||
2374 | } | ||
2375 | Fl_Slider locationslider { | ||
2376 | callback {hd24song* currsong=(hd24song*)(this->control->song()); | ||
2377 | if (currsong==NULL) return; | ||
2378 | this->slidermoved=3; | ||
2379 | long long newpos=(long long)currsong->songlength_in_samples(); | ||
2380 | newpos*=(int)(o->value()); | ||
2381 | newpos=(__uint32)(newpos/1000); | ||
2382 | control->hd24_transport_goloc(newpos);} | ||
2383 | xywh {10 208 595 17} type Horizontal selection_color 41 labelsize 12 align 4 maximum 1000 step 1 | ||
2384 | code0 {this->slidermoved=0;} | ||
2385 | } | ||
2386 | Fl_Box {} { | ||
2387 | xywh {305 226 300 149} box DOWN_BOX color 8 | ||
2388 | } | ||
2389 | Fl_Button button_setlocate { | ||
2390 | label {SET LOC} | ||
2391 | callback {control->highlight_setbuttons(o->value());} | ||
2392 | tooltip {Set Locate} xywh {420 290 50 20} type Toggle box FLAT_BOX down_box FLAT_BOX color 16 selection_color 18 labelfont 1 labelsize 9 labelcolor 7 align 5 | ||
2393 | code0 {o->up_image(button_lrc_up->image()); o->down_image(button_lrc_dn->image());} | ||
2394 | class Fl_Image_Toggle_Button | ||
2395 | } | ||
2396 | Fl_Button button_loopmode { | ||
2397 | label {AUTO LOOP} | ||
2398 | callback {control->loopmode(button_loopmode->value());} | ||
2399 | tooltip {Auto Loop} xywh {310 250 50 20} type Toggle box FLAT_BOX down_box FLAT_BOX color 16 selection_color 18 labelfont 1 labelsize 9 labelcolor 7 align 5 | ||
2400 | code0 {o->up_image(button_lrc_up->image()); o->down_image(button_lrc_dn->image());} | ||
2401 | class Fl_Image_Toggle_Button | ||
2402 | } | ||
2403 | Fl_Repeat_Button button_rew { | ||
2404 | callback {control->button_rew_call();} | ||
2405 | tooltip Rewind image {images/button_rew.gif} xywh {310 330 50 30} box FLAT_BOX labelsize 11 align 16 | ||
2406 | code0 {o->up_image(o->image()); o->down_image(button_rew_dn->image()); o->image(NULL);} | ||
2407 | class Fl_Image_Repeat_Button | ||
2408 | } | ||
2409 | Fl_Repeat_Button button_ffwd { | ||
2410 | callback {control->button_ffwd_call();} | ||
2411 | tooltip {F Fwd} image {images/button_ffwd.gif} xywh {370 330 50 30} box FLAT_BOX labelsize 11 align 16 | ||
2412 | code0 {o->up_image(o->image()); o->down_image(button_ffwd_dn->image()); o->image(NULL);} | ||
2413 | class Fl_Image_Repeat_Button | ||
2414 | } | ||
2415 | Fl_Button button_stop { | ||
2416 | callback {if (control!=NULL) control->button_stop_call();} | ||
2417 | tooltip Stop image {images/button_stop_uplit.gif} xywh {430 330 50 30} box FLAT_BOX labelsize 11 align 16 | ||
2418 | code0 {//o->up_image(button_stop_uplit->image()); o->down_image(button_stop_dn->image());} | ||
2419 | code1 {o->up_image(o->image()); o->down_image(button_stop_dn->image()); o->image(NULL);} | ||
2420 | class Fl_Image_Button | ||
2421 | } | ||
2422 | Fl_Button button_play { | ||
2423 | callback {control->button_play_call();} | ||
2424 | tooltip Play image {images/button_play.gif} xywh {490 330 50 30} box FLAT_BOX labelsize 11 align 16 | ||
2425 | code0 {o->up_image(o->image()); o->down_image(button_play_dn->image()); o->image(NULL);} | ||
2426 | class Fl_Image_Button | ||
2427 | } | ||
2428 | Fl_Box {} { | ||
2429 | xywh {475 231 127 84} box BORDER_BOX color 0 | ||
2430 | } | ||
2431 | Fl_Button button_loopstart { | ||
2432 | label {LOOP START} | ||
2433 | callback {control->handlelocatebutton(hd24song::LOCATEPOS_LOOPSTART);} | ||
2434 | tooltip {Loop Start} xywh {485 250 50 20} box FLAT_BOX down_box FLAT_BOX color 16 selection_color 18 labelfont 1 labelsize 9 labelcolor 7 align 1 | ||
2435 | code0 {hlbuttons_defaultcolor=o->color(); o->up_image(button_lrc_led_up->image()); o->down_image(button_lrc_led_dn->image());} | ||
2436 | class Fl_Image_Button | ||
2437 | } | ||
2438 | Fl_Button button_loopend { | ||
2439 | label {LOOP END} | ||
2440 | callback {control->handlelocatebutton(hd24song::LOCATEPOS_LOOPEND);} | ||
2441 | tooltip {Loop End} xywh {550 250 50 20} box FLAT_BOX down_box FLAT_BOX color 16 selection_color 18 labelfont 1 labelsize 9 labelcolor 7 align 9 | ||
2442 | code0 {o->up_image(button_lrc_led_up->image()); o->down_image(button_lrc_led_dn->image());} | ||
2443 | class Fl_Image_Button | ||
2444 | } | ||
2445 | Fl_Button button_locate0 { | ||
2446 | label {LOC 0} | ||
2447 | callback {control->audio->hd24_transport_locate((__sint64)0);} | ||
2448 | tooltip {Locate 0} xywh {420 250 50 20} box FLAT_BOX color 16 selection_color 18 labelfont 1 labelsize 9 labelcolor 7 align 5 | ||
2449 | code0 {o->up_image(button_lrc_up->image()); o->down_image(button_lrc_dn->image());} | ||
2450 | class Fl_Image_Button | ||
2451 | } | ||
2452 | Fl_Button button_rec { | ||
2453 | callback {control->button_rec_call();} | ||
2454 | tooltip Record image {images/button_rec.gif} xywh {550 330 50 30} type Toggle box FLAT_BOX labelsize 11 | ||
2455 | code0 {o->up_image(o->image()); o->down_image(button_rec_dn->image()); o->image(NULL);} | ||
2456 | class Fl_Image_Toggle_Button | ||
2457 | } | ||
2458 | Fl_Group channelcanvas {open | ||
2459 | xywh {10 15 595 140} box DOWN_BOX color 0 | ||
2460 | } { | ||
2461 | Fl_Group tc1 {open | ||
2462 | xywh {15 15 15 135} | ||
2463 | code0 {trackchan[0]=o;} | ||
2464 | class HD24TrackChannel | ||
2465 | } {} | ||
2466 | Fl_Group tc2 {open | ||
2467 | xywh {15 15 15 135} | ||
2468 | code0 {trackchan[1]=o;} | ||
2469 | class HD24TrackChannel | ||
2470 | } {} | ||
2471 | Fl_Group tc3 {open | ||
2472 | xywh {15 15 15 135} | ||
2473 | code0 {trackchan[2]=o;} | ||
2474 | class HD24TrackChannel | ||
2475 | } {} | ||
2476 | Fl_Group tc4 {open | ||
2477 | xywh {15 15 15 135} | ||
2478 | code0 {trackchan[3]=o;} | ||
2479 | class HD24TrackChannel | ||
2480 | } {} | ||
2481 | Fl_Group tc5 {open | ||
2482 | xywh {15 15 15 135} | ||
2483 | code0 {trackchan[4]=o;} | ||
2484 | class HD24TrackChannel | ||
2485 | } {} | ||
2486 | Fl_Group tc6 {open | ||
2487 | xywh {15 15 15 135} | ||
2488 | code0 {trackchan[5]=o;} | ||
2489 | class HD24TrackChannel | ||
2490 | } {} | ||
2491 | Fl_Group tc7 {open | ||
2492 | xywh {15 15 15 135} | ||
2493 | code0 {trackchan[6]=o;} | ||
2494 | class HD24TrackChannel | ||
2495 | } {} | ||
2496 | Fl_Group tc8 {open | ||
2497 | xywh {15 15 15 135} | ||
2498 | code0 {trackchan[7]=o;} | ||
2499 | class HD24TrackChannel | ||
2500 | } {} | ||
2501 | Fl_Group trackinfo1 {open | ||
2502 | xywh {15 15 15 135} | ||
2503 | code0 {trackinfo[0]=trackinfo1;} | ||
2504 | class TrackInfo | ||
2505 | } {} | ||
2506 | Fl_Group tc9 {open | ||
2507 | xywh {15 15 15 135} | ||
2508 | code0 {trackchan[8]=o;} | ||
2509 | class HD24TrackChannel | ||
2510 | } {} | ||
2511 | Fl_Group tc10 {open | ||
2512 | xywh {15 15 15 135} | ||
2513 | code0 {trackchan[9]=o;} | ||
2514 | class HD24TrackChannel | ||
2515 | } {} | ||
2516 | Fl_Group tc11 {open | ||
2517 | xywh {15 15 15 135} | ||
2518 | code0 {trackchan[10]=o;} | ||
2519 | class HD24TrackChannel | ||
2520 | } {} | ||
2521 | Fl_Group tc12 {open | ||
2522 | xywh {15 15 15 135} | ||
2523 | code0 {trackchan[11]=o;} | ||
2524 | class HD24TrackChannel | ||
2525 | } {} | ||
2526 | Fl_Group tc13 {open | ||
2527 | xywh {15 15 15 135} | ||
2528 | code0 {trackchan[12]=o;} | ||
2529 | class HD24TrackChannel | ||
2530 | } {} | ||
2531 | Fl_Group tc14 {open | ||
2532 | xywh {15 15 15 135} | ||
2533 | code0 {trackchan[13]=o;} | ||
2534 | class HD24TrackChannel | ||
2535 | } {} | ||
2536 | Fl_Group tc15 {open | ||
2537 | xywh {15 15 15 135} | ||
2538 | code0 {trackchan[14]=o;} | ||
2539 | class HD24TrackChannel | ||
2540 | } {} | ||
2541 | Fl_Group tc16 {open | ||
2542 | xywh {15 15 15 135} | ||
2543 | code0 {trackchan[15]=o;} | ||
2544 | class HD24TrackChannel | ||
2545 | } {} | ||
2546 | Fl_Group trackinfo2 {open | ||
2547 | xywh {15 15 15 135} | ||
2548 | code0 {trackinfo[1]=trackinfo2;} | ||
2549 | class TrackInfo | ||
2550 | } {} | ||
2551 | Fl_Group tc17 {open | ||
2552 | xywh {15 15 15 135} | ||
2553 | code0 {trackchan[16]=o;} | ||
2554 | class HD24TrackChannel | ||
2555 | } {} | ||
2556 | Fl_Group tc18 {open | ||
2557 | xywh {15 15 15 135} | ||
2558 | code0 {trackchan[17]=o;} | ||
2559 | class HD24TrackChannel | ||
2560 | } {} | ||
2561 | Fl_Group tc19 {open | ||
2562 | xywh {15 15 15 135} | ||
2563 | code0 {trackchan[18]=o;} | ||
2564 | class HD24TrackChannel | ||
2565 | } {} | ||
2566 | Fl_Group tc20 {open | ||
2567 | xywh {15 15 15 135} | ||
2568 | code0 {trackchan[19]=o;} | ||
2569 | class HD24TrackChannel | ||
2570 | } {} | ||
2571 | Fl_Group tc21 {open | ||
2572 | xywh {15 15 15 135} | ||
2573 | code0 {trackchan[20]=o;} | ||
2574 | class HD24TrackChannel | ||
2575 | } {} | ||
2576 | Fl_Group tc22 {open | ||
2577 | xywh {15 15 15 135} | ||
2578 | code0 {trackchan[21]=o;} | ||
2579 | class HD24TrackChannel | ||
2580 | } {} | ||
2581 | Fl_Group tc23 {open | ||
2582 | xywh {15 15 15 135} | ||
2583 | code0 {trackchan[22]=o;} | ||
2584 | class HD24TrackChannel | ||
2585 | } {} | ||
2586 | Fl_Group tc24 {open | ||
2587 | xywh {15 15 15 135} | ||
2588 | code0 {trackchan[23]=o;} | ||
2589 | class HD24TrackChannel | ||
2590 | } {} | ||
2591 | Fl_Group {} {open | ||
2592 | xywh {35 40 15 15} | ||
2593 | } {} | ||
2594 | } | ||
2595 | Fl_Button arm1 { | ||
2596 | callback {this->control->toggletrackarmed(1);} | ||
2597 | tooltip arm xywh {40 155 20 15} labelsize 8 labelcolor 7 | ||
2598 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[0]=o;} | ||
2599 | class Fl_Image_Button | ||
2600 | } | ||
2601 | Fl_Button arm2 { | ||
2602 | callback {this->control->toggletrackarmed(2);} | ||
2603 | tooltip arm xywh {60 155 15 15} | ||
2604 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[1]=o;} | ||
2605 | class Fl_Image_Button | ||
2606 | } | ||
2607 | Fl_Button arm3 { | ||
2608 | callback {this->control->toggletrackarmed(3);} | ||
2609 | tooltip arm xywh {75 155 15 15} | ||
2610 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[2]=o;} | ||
2611 | class Fl_Image_Button | ||
2612 | } | ||
2613 | Fl_Button arm4 { | ||
2614 | callback {this->control->toggletrackarmed(4);} | ||
2615 | tooltip arm xywh {90 155 15 15} | ||
2616 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[3]=o;} | ||
2617 | class Fl_Image_Button | ||
2618 | } | ||
2619 | Fl_Button arm5 { | ||
2620 | callback {this->control->toggletrackarmed(5);} | ||
2621 | tooltip arm xywh {105 155 15 15} | ||
2622 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[4]=o;} | ||
2623 | class Fl_Image_Button | ||
2624 | } | ||
2625 | Fl_Button arm6 { | ||
2626 | callback {this->control->toggletrackarmed(6);} | ||
2627 | tooltip arm xywh {120 155 15 15} | ||
2628 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[5]=o;} | ||
2629 | class Fl_Image_Button | ||
2630 | } | ||
2631 | Fl_Button arm7 { | ||
2632 | callback {this->control->toggletrackarmed(7);} | ||
2633 | tooltip arm xywh {135 155 15 15} | ||
2634 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[6]=o;} | ||
2635 | class Fl_Image_Button | ||
2636 | } | ||
2637 | Fl_Button arm8 { | ||
2638 | callback {this->control->toggletrackarmed(8);} | ||
2639 | tooltip arm xywh {150 155 15 15} | ||
2640 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[7]=o;} | ||
2641 | class Fl_Image_Button | ||
2642 | } | ||
2643 | Fl_Button arm9 { | ||
2644 | callback {this->control->toggletrackarmed(9);} | ||
2645 | tooltip arm xywh {235 155 15 15} | ||
2646 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[8]=o;} | ||
2647 | class Fl_Image_Button | ||
2648 | } | ||
2649 | Fl_Button arm10 { | ||
2650 | callback {this->control->toggletrackarmed(10);} | ||
2651 | tooltip arm xywh {250 155 15 15} | ||
2652 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[9]=o;} | ||
2653 | class Fl_Image_Button | ||
2654 | } | ||
2655 | Fl_Button arm11 { | ||
2656 | callback {this->control->toggletrackarmed(11);} | ||
2657 | tooltip arm xywh {265 155 15 15} | ||
2658 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[10]=o;} | ||
2659 | class Fl_Image_Button | ||
2660 | } | ||
2661 | Fl_Button arm12 { | ||
2662 | callback {this->control->toggletrackarmed(12);} | ||
2663 | tooltip arm xywh {280 155 15 15} | ||
2664 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[11]=o;} | ||
2665 | class Fl_Image_Button | ||
2666 | } | ||
2667 | Fl_Button arm13 { | ||
2668 | callback {this->control->toggletrackarmed(13);} | ||
2669 | tooltip arm xywh {295 155 15 15} | ||
2670 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[12]=o;} | ||
2671 | class Fl_Image_Button | ||
2672 | } | ||
2673 | Fl_Button arm14 { | ||
2674 | callback {this->control->toggletrackarmed(14);} | ||
2675 | tooltip arm xywh {310 155 15 15} | ||
2676 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[13]=o;} | ||
2677 | class Fl_Image_Button | ||
2678 | } | ||
2679 | Fl_Button arm15 { | ||
2680 | callback {this->control->toggletrackarmed(15);} | ||
2681 | tooltip arm xywh {325 155 15 15} | ||
2682 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[14]=o;} | ||
2683 | class Fl_Image_Button | ||
2684 | } | ||
2685 | Fl_Button arm16 { | ||
2686 | callback {this->control->toggletrackarmed(16);} | ||
2687 | tooltip arm xywh {340 155 15 15} | ||
2688 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[15]=o;} | ||
2689 | class Fl_Image_Button | ||
2690 | } | ||
2691 | Fl_Button arm17 { | ||
2692 | callback {this->control->toggletrackarmed(17);} | ||
2693 | tooltip arm xywh {430 155 15 15} | ||
2694 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[16]=o;} | ||
2695 | class Fl_Image_Button | ||
2696 | } | ||
2697 | Fl_Button arm18 { | ||
2698 | callback {this->control->toggletrackarmed(18);} | ||
2699 | tooltip arm xywh {445 155 15 15} | ||
2700 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[17]=o;} | ||
2701 | class Fl_Image_Button | ||
2702 | } | ||
2703 | Fl_Button arm19 { | ||
2704 | callback {this->control->toggletrackarmed(19);} | ||
2705 | tooltip arm xywh {460 155 15 15} | ||
2706 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[18]=o;} | ||
2707 | class Fl_Image_Button | ||
2708 | } | ||
2709 | Fl_Button arm20 { | ||
2710 | callback {this->control->toggletrackarmed(20);} | ||
2711 | tooltip arm xywh {475 155 15 15} | ||
2712 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[19]=o;} | ||
2713 | class Fl_Image_Button | ||
2714 | } | ||
2715 | Fl_Button arm21 { | ||
2716 | callback {this->control->toggletrackarmed(21);} | ||
2717 | tooltip arm xywh {490 155 15 15} | ||
2718 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[20]=o;} | ||
2719 | class Fl_Image_Button | ||
2720 | } | ||
2721 | Fl_Button arm22 { | ||
2722 | callback {this->control->toggletrackarmed(22);} | ||
2723 | tooltip arm xywh {505 155 15 15} | ||
2724 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[21]=o;} | ||
2725 | class Fl_Image_Button | ||
2726 | } | ||
2727 | Fl_Button arm23 { | ||
2728 | callback {this->control->toggletrackarmed(23);} | ||
2729 | tooltip arm xywh {520 155 15 15} | ||
2730 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[22]=o;} | ||
2731 | class Fl_Image_Button | ||
2732 | } | ||
2733 | Fl_Button arm24 { | ||
2734 | callback {this->control->toggletrackarmed(24);} | ||
2735 | tooltip arm xywh {535 155 15 15} | ||
2736 | code0 {o->up_image(button_small_up->image()); o->down_image(button_small_dn->image()); armbutton[23]=o;} | ||
2737 | class Fl_Image_Button | ||
2738 | } | ||
2739 | Fl_Button solo1 { | ||
2740 | callback {control->solo(0,o->value());} | ||
2741 | xywh {40 175 20 15} selection_color 2 | ||
2742 | code0 {o->up_image(button_solo_up->image()); o->down_image(button_solo_dn->image()); solobutton[0]=o;} | ||
2743 | class Fl_Image_Toggle_Button | ||
2744 | } | ||
2745 | Fl_Button solo2 { | ||
2746 | callback {control->solo(1,o->value());} | ||
2747 | xywh {60 175 15 15} selection_color 2 | ||
2748 | code0 {solobutton[1]=o;} | ||
2749 | class Fl_Image_Toggle_Button | ||
2750 | } | ||
2751 | Fl_Button solo3 { | ||
2752 | callback {control->solo(2,o->value());} | ||
2753 | xywh {75 175 15 15} selection_color 2 | ||
2754 | code0 {solobutton[2]=o;} | ||
2755 | class Fl_Image_Toggle_Button | ||
2756 | } | ||
2757 | Fl_Button solo4 { | ||
2758 | callback {control->solo(3,o->value());} | ||
2759 | xywh {90 175 15 15} selection_color 2 | ||
2760 | code0 {solobutton[3]=o;} | ||
2761 | class Fl_Image_Toggle_Button | ||
2762 | } | ||
2763 | Fl_Button solo5 { | ||
2764 | callback {control->solo(4,o->value());} | ||
2765 | xywh {105 175 15 15} selection_color 2 | ||
2766 | code0 {solobutton[4]=o;} | ||
2767 | class Fl_Image_Toggle_Button | ||
2768 | } | ||
2769 | Fl_Button solo6 { | ||
2770 | callback {control->solo(5,o->value());} | ||
2771 | xywh {120 175 15 15} selection_color 2 | ||
2772 | code0 {solobutton[5]=o;} | ||
2773 | class Fl_Image_Toggle_Button | ||
2774 | } | ||
2775 | Fl_Button solo7 { | ||
2776 | callback {control->solo(6,o->value());} | ||
2777 | xywh {135 175 15 15} selection_color 2 | ||
2778 | code0 {solobutton[6]=o;} | ||
2779 | class Fl_Image_Toggle_Button | ||
2780 | } | ||
2781 | Fl_Button solo8 { | ||
2782 | callback {control->solo(7,o->value());} | ||
2783 | xywh {150 175 15 15} selection_color 2 | ||
2784 | code0 {solobutton[7]=o;} | ||
2785 | class Fl_Image_Toggle_Button | ||
2786 | } | ||
2787 | Fl_Button solo9 { | ||
2788 | callback {control->solo(8,o->value());} | ||
2789 | xywh {235 175 15 15} selection_color 2 | ||
2790 | code0 {solobutton[8]=o;} | ||
2791 | class Fl_Image_Toggle_Button | ||
2792 | } | ||
2793 | Fl_Button solo10 { | ||
2794 | callback {control->solo(9,o->value());} | ||
2795 | xywh {250 175 15 15} selection_color 2 | ||
2796 | code0 {solobutton[9]=o;} | ||
2797 | class Fl_Image_Toggle_Button | ||
2798 | } | ||
2799 | Fl_Button solo11 { | ||
2800 | callback {control->solo(10,o->value());} | ||
2801 | xywh {265 175 15 15} selection_color 2 | ||
2802 | code0 {solobutton[10]=o;} | ||
2803 | class Fl_Image_Toggle_Button | ||
2804 | } | ||
2805 | Fl_Button solo12 { | ||
2806 | callback {control->solo(11,o->value());} | ||
2807 | xywh {280 175 15 15} selection_color 2 | ||
2808 | code0 {solobutton[11]=o;} | ||
2809 | class Fl_Image_Toggle_Button | ||
2810 | } | ||
2811 | Fl_Button solo13 { | ||
2812 | callback {control->solo(12,o->value());} | ||
2813 | xywh {295 175 15 15} selection_color 2 | ||
2814 | code0 {solobutton[12]=o;} | ||
2815 | class Fl_Image_Toggle_Button | ||
2816 | } | ||
2817 | Fl_Button solo14 { | ||
2818 | callback {control->solo(13,o->value());} | ||
2819 | xywh {310 175 15 15} selection_color 2 | ||
2820 | code0 {solobutton[13]=o;} | ||
2821 | class Fl_Image_Toggle_Button | ||
2822 | } | ||
2823 | Fl_Button solo15 { | ||
2824 | callback {control->solo(14,o->value());} | ||
2825 | xywh {325 175 15 15} selection_color 2 | ||
2826 | code0 {solobutton[14]=o;} | ||
2827 | class Fl_Image_Toggle_Button | ||
2828 | } | ||
2829 | Fl_Button solo16 { | ||
2830 | callback {control->solo(15,o->value());} | ||
2831 | xywh {340 175 15 15} selection_color 2 | ||
2832 | code0 {solobutton[15]=o;} | ||
2833 | class Fl_Image_Toggle_Button | ||
2834 | } | ||
2835 | Fl_Button solo17 { | ||
2836 | callback {control->solo(16,o->value());} | ||
2837 | xywh {430 175 15 15} selection_color 2 | ||
2838 | code0 {solobutton[16]=o;} | ||
2839 | class Fl_Image_Toggle_Button | ||
2840 | } | ||
2841 | Fl_Button solo18 { | ||
2842 | callback {control->solo(17,o->value());} | ||
2843 | xywh {445 175 15 15} selection_color 2 | ||
2844 | code0 {solobutton[17]=o;} | ||
2845 | class Fl_Image_Toggle_Button | ||
2846 | } | ||
2847 | Fl_Button solo19 { | ||
2848 | callback {control->solo(18,o->value());} | ||
2849 | xywh {460 175 15 15} selection_color 2 | ||
2850 | code0 {solobutton[18]=o;} | ||
2851 | class Fl_Image_Toggle_Button | ||
2852 | } | ||
2853 | Fl_Button solo20 { | ||
2854 | callback {control->solo(19,o->value());} | ||
2855 | xywh {475 175 15 15} selection_color 2 | ||
2856 | code0 {solobutton[19]=o;} | ||
2857 | class Fl_Image_Toggle_Button | ||
2858 | } | ||
2859 | Fl_Button solo21 { | ||
2860 | callback {control->solo(20,o->value());} | ||
2861 | xywh {490 175 15 15} selection_color 2 | ||
2862 | code0 {solobutton[20]=o;} | ||
2863 | class Fl_Image_Toggle_Button | ||
2864 | } | ||
2865 | Fl_Button solo22 { | ||
2866 | callback {control->solo(21,o->value());} | ||
2867 | xywh {505 175 15 15} selection_color 2 | ||
2868 | code0 {solobutton[21]=o;} | ||
2869 | class Fl_Image_Toggle_Button | ||
2870 | } | ||
2871 | Fl_Button solo23 { | ||
2872 | callback {control->solo(22,o->value());} | ||
2873 | xywh {520 175 15 15} selection_color 2 | ||
2874 | code0 {solobutton[22]=o;} | ||
2875 | class Fl_Image_Toggle_Button | ||
2876 | } | ||
2877 | Fl_Button solo24 { | ||
2878 | callback {control->solo(23,o->value());} | ||
2879 | xywh {535 175 15 15} selection_color 2 | ||
2880 | code0 {solobutton[23]=o;} | ||
2881 | class Fl_Image_Toggle_Button | ||
2882 | } | ||
2883 | Fl_Button mute1 { | ||
2884 | callback {control->mute(0,o->value());} | ||
2885 | xywh {40 192 20 15} selection_color 1 | ||
2886 | code0 {o->up_image(button_mute_up->image()); o->down_image(button_mute_dn->image()); mutebutton[0]=o;} | ||
2887 | class Fl_Image_Toggle_Button | ||
2888 | } | ||
2889 | Fl_Button mute2 { | ||
2890 | callback {control->mute(1,o->value());} | ||
2891 | xywh {60 192 15 15} selection_color 1 | ||
2892 | code0 {mutebutton[1]=o;} | ||
2893 | class Fl_Image_Toggle_Button | ||
2894 | } | ||
2895 | Fl_Button mute3 { | ||
2896 | callback {control->mute(2,o->value());} | ||
2897 | xywh {75 192 15 15} selection_color 1 | ||
2898 | code0 {mutebutton[2]=o;} | ||
2899 | class Fl_Image_Toggle_Button | ||
2900 | } | ||
2901 | Fl_Button mute4 { | ||
2902 | callback {control->mute(3,o->value());} | ||
2903 | xywh {90 192 15 15} selection_color 1 | ||
2904 | code0 {mutebutton[3]=o;} | ||
2905 | class Fl_Image_Toggle_Button | ||
2906 | } | ||
2907 | Fl_Button mute5 { | ||
2908 | callback {control->mute(4,o->value());} | ||
2909 | xywh {105 192 15 15} selection_color 1 | ||
2910 | code0 {mutebutton[4]=o;} | ||
2911 | class Fl_Image_Toggle_Button | ||
2912 | } | ||
2913 | Fl_Button mute6 { | ||
2914 | callback {control->mute(5,o->value());} | ||
2915 | xywh {120 192 15 15} selection_color 1 | ||
2916 | code0 {mutebutton[5]=o;} | ||
2917 | class Fl_Image_Toggle_Button | ||
2918 | } | ||
2919 | Fl_Button mute7 { | ||
2920 | callback {control->mute(6,o->value());} | ||
2921 | xywh {135 192 15 15} selection_color 1 | ||
2922 | code0 {mutebutton[6]=o;} | ||
2923 | class Fl_Image_Toggle_Button | ||
2924 | } | ||
2925 | Fl_Button mute8 { | ||
2926 | callback {control->mute(7,o->value());} | ||
2927 | xywh {150 192 15 15} selection_color 1 | ||
2928 | code0 {mutebutton[7]=o;} | ||
2929 | class Fl_Image_Toggle_Button | ||
2930 | } | ||
2931 | Fl_Button mute9 { | ||
2932 | callback {control->mute(8,o->value());} | ||
2933 | xywh {235 192 15 15} selection_color 1 | ||
2934 | code0 {mutebutton[8]=o;} | ||
2935 | class Fl_Image_Toggle_Button | ||
2936 | } | ||
2937 | Fl_Button mute10 { | ||
2938 | callback {control->mute(9,o->value());} | ||
2939 | xywh {250 192 15 15} selection_color 1 | ||
2940 | code0 {mutebutton[9]=o;} | ||
2941 | class Fl_Image_Toggle_Button | ||
2942 | } | ||
2943 | Fl_Button mute11 { | ||
2944 | callback {control->mute(10,o->value());} | ||
2945 | xywh {265 192 15 15} selection_color 1 | ||
2946 | code0 {mutebutton[10]=o;} | ||
2947 | class Fl_Image_Toggle_Button | ||
2948 | } | ||
2949 | Fl_Button mute12 { | ||
2950 | callback {control->mute(11,o->value());} | ||
2951 | xywh {280 192 15 15} selection_color 1 | ||
2952 | code0 {mutebutton[11]=o;} | ||
2953 | class Fl_Image_Toggle_Button | ||
2954 | } | ||
2955 | Fl_Button mute13 { | ||
2956 | callback {control->mute(12,o->value());} | ||
2957 | xywh {295 192 15 15} selection_color 1 | ||
2958 | code0 {mutebutton[12]=o;} | ||
2959 | class Fl_Image_Toggle_Button | ||
2960 | } | ||
2961 | Fl_Button mute14 { | ||
2962 | callback {control->mute(13,o->value());} | ||
2963 | xywh {310 192 15 15} selection_color 1 | ||
2964 | code0 {mutebutton[13]=o;} | ||
2965 | class Fl_Image_Toggle_Button | ||
2966 | } | ||
2967 | Fl_Button mute15 { | ||
2968 | callback {control->mute(14,o->value());} | ||
2969 | xywh {325 192 15 15} selection_color 1 | ||
2970 | code0 {mutebutton[14]=o;} | ||
2971 | class Fl_Image_Toggle_Button | ||
2972 | } | ||
2973 | Fl_Button mute16 { | ||
2974 | callback {control->mute(15,o->value());} | ||
2975 | xywh {340 192 15 15} selection_color 1 | ||
2976 | code0 {mutebutton[15]=o;} | ||
2977 | class Fl_Image_Toggle_Button | ||
2978 | } | ||
2979 | Fl_Button mute17 { | ||
2980 | callback {control->mute(16,o->value());} | ||
2981 | xywh {430 192 15 15} selection_color 1 | ||
2982 | code0 {mutebutton[16]=o;} | ||
2983 | class Fl_Image_Toggle_Button | ||
2984 | } | ||
2985 | Fl_Button mute18 { | ||
2986 | callback {control->mute(17,o->value());} | ||
2987 | xywh {445 192 15 15} selection_color 1 | ||
2988 | code0 {mutebutton[17]=o;} | ||
2989 | class Fl_Image_Toggle_Button | ||
2990 | } | ||
2991 | Fl_Button mute19 { | ||
2992 | callback {control->mute(18,o->value());} | ||
2993 | xywh {460 192 15 15} selection_color 1 | ||
2994 | code0 {mutebutton[18]=o;} | ||
2995 | class Fl_Image_Toggle_Button | ||
2996 | } | ||
2997 | Fl_Button mute20 { | ||
2998 | callback {control->mute(19,o->value());} | ||
2999 | xywh {475 192 15 15} selection_color 1 | ||
3000 | code0 {mutebutton[19]=o;} | ||
3001 | class Fl_Image_Toggle_Button | ||
3002 | } | ||
3003 | Fl_Button mute21 { | ||
3004 | callback {control->mute(20,o->value());} | ||
3005 | xywh {490 192 15 15} selection_color 1 | ||
3006 | code0 {mutebutton[20]=o;} | ||
3007 | class Fl_Image_Toggle_Button | ||
3008 | } | ||
3009 | Fl_Button mute22 { | ||
3010 | callback {control->mute(21,o->value());} | ||
3011 | xywh {505 192 15 15} selection_color 1 | ||
3012 | code0 {mutebutton[21]=o;} | ||
3013 | class Fl_Image_Toggle_Button | ||
3014 | } | ||
3015 | Fl_Button mute23 { | ||
3016 | callback {control->mute(22,o->value());} | ||
3017 | xywh {520 192 15 15} selection_color 1 | ||
3018 | code0 {mutebutton[22]=o;} | ||
3019 | class Fl_Image_Toggle_Button | ||
3020 | } | ||
3021 | Fl_Button mute24 { | ||
3022 | callback {control->mute(23,o->value());} | ||
3023 | xywh {535 192 15 15} selection_color 1 | ||
3024 | code0 {mutebutton[23]=o;} | ||
3025 | class Fl_Image_Toggle_Button | ||
3026 | } | ||
3027 | Fl_Box arm_unarm_all { | ||
3028 | callback {hd24song* currsong=this->control->song(); | ||
3029 | if (currsong==NULL) return; | ||
3030 | |||
3031 | bool alltracksarmed=true; | ||
3032 | for (unsigned int i=1;i<=currsong->logical_channels();i++) { | ||
3033 | if (!currsong->trackarmed(i)) { | ||
3034 | alltracksarmed=false; | ||
3035 | break; | ||
3036 | } | ||
3037 | } | ||
3038 | bool mustarm=false; | ||
3039 | if (!alltracksarmed) { | ||
3040 | mustarm=true; | ||
3041 | } | ||
3042 | for (unsigned int i=1;i<=currsong->logical_channels();i++) { | ||
3043 | currsong->trackarmed(i,mustarm); | ||
3044 | }} | ||
3045 | tooltip {Arm tracks} xywh {10 156 10 10} box OVAL_BOX color 1 selection_color 1 | ||
3046 | class Fl_Button | ||
3047 | } | ||
3048 | Fl_Box {} { | ||
3049 | label S | ||
3050 | tooltip Solo xywh {10 176 15 14} color 1 selection_color 1 labelfont 1 labelsize 12 | ||
3051 | } | ||
3052 | Fl_Box {} { | ||
3053 | label M | ||
3054 | tooltip Mute xywh {10 191 15 14} color 1 selection_color 1 labelfont 1 labelsize 12 | ||
3055 | } | ||
3056 | Fl_Group infodisplay {open | ||
3057 | xywh {10 225 295 150} box DOWN_BOX color 0 | ||
3058 | } { | ||
3059 | Fl_Box ho1 { | ||
3060 | image {images/7seg_8.gif} xywh {12 234 16 26} | ||
3061 | code0 {o->image(i7seg0->image()); o->redraw();} | ||
3062 | } | ||
3063 | Fl_Box ho2 { | ||
3064 | image {images/7seg_8.gif} xywh {27 234 16 26} | ||
3065 | code0 {o->image(i7seg0->image()); o->redraw();} | ||
3066 | } | ||
3067 | Fl_Box mi1 { | ||
3068 | image {images/7seg_8.gif} xywh {55 234 16 26} | ||
3069 | code0 {o->image(i7seg0->image()); o->redraw();} | ||
3070 | } | ||
3071 | Fl_Box mi2 { | ||
3072 | image {images/7seg_8.gif} xywh {70 234 16 26} | ||
3073 | code0 {o->image(i7seg0->image()); o->redraw();} | ||
3074 | } | ||
3075 | Fl_Box se1 { | ||
3076 | image {images/7seg_8.gif} xywh {98 234 16 26} | ||
3077 | code0 {o->image(i7seg0->image()); o->redraw();} | ||
3078 | } | ||
3079 | Fl_Box se2 { | ||
3080 | image {images/7seg_8.gif} xywh {113 234 16 26} | ||
3081 | code0 {o->image(i7seg0->image()); o->redraw();} | ||
3082 | } | ||
3083 | Fl_Box fr1 { | ||
3084 | image {images/7seg_8.gif} xywh {141 234 16 26} | ||
3085 | code0 {o->image(i7seg0->image()); o->redraw();} | ||
3086 | } | ||
3087 | Fl_Box fr2 { | ||
3088 | image {images/7seg_8.gif} xywh {156 234 16 26} | ||
3089 | code0 {o->image(i7seg0->image()); o->redraw();} | ||
3090 | } | ||
3091 | Fl_Box {} { | ||
3092 | label H | ||
3093 | xywh {42 247 12 14} labelfont 3 labelsize 11 labelcolor 6 | ||
3094 | } | ||
3095 | Fl_Box {} { | ||
3096 | label M | ||
3097 | xywh {85 247 12 14} labelfont 3 labelsize 11 labelcolor 6 | ||
3098 | } | ||
3099 | Fl_Box {} { | ||
3100 | label S | ||
3101 | xywh {128 247 12 14} labelfont 3 labelsize 11 labelcolor 6 | ||
3102 | } | ||
3103 | Fl_Box {} { | ||
3104 | label F | ||
3105 | xywh {171 247 12 14} labelfont 3 labelsize 11 labelcolor 6 | ||
3106 | } | ||
3107 | Fl_Box l1c0 { | ||
3108 | image {images/HD24_matrix_realsize.gif} xywh {13 274 20 26} | ||
3109 | code0 {this->dispcell[0][0]=o;} | ||
3110 | } | ||
3111 | Fl_Box l1c1 { | ||
3112 | image {images/HD24_matrix_realsize.gif} xywh {31 274 20 26} | ||
3113 | code0 {this->dispcell[1][0]=o;} | ||
3114 | } | ||
3115 | Fl_Box l1c2 { | ||
3116 | image {images/HD24_matrix_realsize.gif} xywh {49 274 20 26} | ||
3117 | code0 {this->dispcell[2][0]=o;} | ||
3118 | } | ||
3119 | Fl_Box l1c3 { | ||
3120 | image {images/HD24_matrix_realsize.gif} xywh {67 274 20 26} | ||
3121 | code0 {this->dispcell[3][0]=o;} | ||
3122 | } | ||
3123 | Fl_Box l1c4 { | ||
3124 | image {images/HD24_matrix_realsize.gif} xywh {85 274 20 26} | ||
3125 | code0 {this->dispcell[4][0]=o;} | ||
3126 | } | ||
3127 | Fl_Box l1c5 { | ||
3128 | image {images/HD24_matrix_realsize.gif} xywh {103 274 20 26} | ||
3129 | code0 {this->dispcell[5][0]=o;} | ||
3130 | } | ||
3131 | Fl_Box l1c6 { | ||
3132 | image {images/HD24_matrix_realsize.gif} xywh {121 274 20 26} | ||
3133 | code0 {this->dispcell[6][0]=o;} | ||
3134 | } | ||
3135 | Fl_Box l1c7 { | ||
3136 | image {images/HD24_matrix_realsize.gif} xywh {139 274 20 26} | ||
3137 | code0 {this->dispcell[7][0]=o;} | ||
3138 | } | ||
3139 | Fl_Box l1c8 { | ||
3140 | image {images/HD24_matrix_realsize.gif} xywh {157 274 20 26} | ||
3141 | code0 {this->dispcell[8][0]=o;} | ||
3142 | } | ||
3143 | Fl_Box l1c9 { | ||
3144 | image {images/HD24_matrix_realsize.gif} xywh {175 274 20 26} | ||
3145 | code0 {this->dispcell[9][0]=o;} | ||
3146 | } | ||
3147 | Fl_Box l1ca { | ||
3148 | image {images/HD24_matrix_realsize.gif} xywh {193 274 20 26} | ||
3149 | code0 {this->dispcell[10][0]=o;} | ||
3150 | } | ||
3151 | Fl_Box l1cb { | ||
3152 | image {images/HD24_matrix_realsize.gif} xywh {211 274 20 26} | ||
3153 | code0 {this->dispcell[11][0]=o;} | ||
3154 | } | ||
3155 | Fl_Box l1cc { | ||
3156 | image {images/HD24_matrix_realsize.gif} xywh {229 274 20 26} | ||
3157 | code0 {this->dispcell[12][0]=o;} | ||
3158 | } | ||
3159 | Fl_Box l1cd { | ||
3160 | image {images/HD24_matrix_realsize.gif} xywh {247 274 20 26} | ||
3161 | code0 {this->dispcell[13][0]=o;} | ||
3162 | } | ||
3163 | Fl_Box l1ce { | ||
3164 | image {images/HD24_matrix_realsize.gif} xywh {265 274 20 26} | ||
3165 | code0 {this->dispcell[14][0]=o;} | ||
3166 | } | ||
3167 | Fl_Box l1cf { | ||
3168 | image {images/HD24_matrix_realsize.gif} xywh {283 274 20 26} | ||
3169 | code0 {this->dispcell[15][0]=o;} | ||
3170 | } | ||
3171 | Fl_Box l2c0 { | ||
3172 | image {images/HD24_matrix_realsize.gif} xywh {12 304 20 26} | ||
3173 | code0 {this->dispcell[0][1]=o;} | ||
3174 | } | ||
3175 | Fl_Box l2c1 { | ||
3176 | image {images/HD24_matrix_realsize.gif} xywh {30 304 20 26} | ||
3177 | code0 {this->dispcell[1][1]=o;} | ||
3178 | } | ||
3179 | Fl_Box l2c2 { | ||
3180 | image {images/HD24_matrix_realsize.gif} xywh {48 304 20 26} | ||
3181 | code0 {this->dispcell[2][1]=o;} | ||
3182 | } | ||
3183 | Fl_Box l2c3 { | ||
3184 | image {images/HD24_matrix_realsize.gif} xywh {66 304 20 26} | ||
3185 | code0 {this->dispcell[3][1]=o;} | ||
3186 | } | ||
3187 | Fl_Box l2c4 { | ||
3188 | image {images/HD24_matrix_realsize.gif} xywh {84 304 20 26} | ||
3189 | code0 {this->dispcell[4][1]=o;} | ||
3190 | } | ||
3191 | Fl_Box l2c5 { | ||
3192 | image {images/HD24_matrix_realsize.gif} xywh {102 304 20 26} | ||
3193 | code0 {this->dispcell[5][1]=o;} | ||
3194 | } | ||
3195 | Fl_Box l2c6 { | ||
3196 | image {images/HD24_matrix_realsize.gif} xywh {120 304 20 26} | ||
3197 | code0 {this->dispcell[6][1]=o;} | ||
3198 | } | ||
3199 | Fl_Box l2c7 { | ||
3200 | image {images/HD24_matrix_realsize.gif} xywh {138 304 20 26} | ||
3201 | code0 {this->dispcell[7][1]=o;} | ||
3202 | } | ||
3203 | Fl_Box l2c8 { | ||
3204 | image {images/HD24_matrix_realsize.gif} xywh {156 304 20 26} | ||
3205 | code0 {this->dispcell[8][1]=o;} | ||
3206 | } | ||
3207 | Fl_Box l2c9 { | ||
3208 | image {images/HD24_matrix_realsize.gif} xywh {174 304 20 26} | ||
3209 | code0 {this->dispcell[9][1]=o;} | ||
3210 | } | ||
3211 | Fl_Box l2ca { | ||
3212 | image {images/HD24_matrix_realsize.gif} xywh {192 304 20 26} | ||
3213 | code0 {this->dispcell[10][1]=o;} | ||
3214 | } | ||
3215 | Fl_Box l2cb { | ||
3216 | image {images/HD24_matrix_realsize.gif} xywh {210 304 20 26} | ||
3217 | code0 {this->dispcell[11][1]=o;} | ||
3218 | } | ||
3219 | Fl_Box l2cc { | ||
3220 | image {images/HD24_matrix_realsize.gif} xywh {228 304 20 26} | ||
3221 | code0 {this->dispcell[12][1]=o;} | ||
3222 | } | ||
3223 | Fl_Box l2cd { | ||
3224 | image {images/HD24_matrix_realsize.gif} xywh {246 304 20 26} | ||
3225 | code0 {this->dispcell[13][1]=o;} | ||
3226 | } | ||
3227 | Fl_Box l2ce { | ||
3228 | image {images/HD24_matrix_realsize.gif} xywh {264 304 20 26} | ||
3229 | code0 {this->dispcell[14][1]=o;} | ||
3230 | } | ||
3231 | Fl_Box l2cf { | ||
3232 | image {images/HD24_matrix_realsize.gif} xywh {282 304 20 26} | ||
3233 | code0 {this->dispcell[15][1]=o;} | ||
3234 | } | ||
3235 | Fl_Box autoanythingled { | ||
3236 | label AUTO | ||
3237 | xywh {193 233 65 8} box FLAT_BOX color 93 labelfont 1 labelsize 8 hide | ||
3238 | } | ||
3239 | Fl_Box autoplayled { | ||
3240 | label PLAY | ||
3241 | xywh {215 242 24 8} box FLAT_BOX color 93 labelfont 1 labelsize 8 hide | ||
3242 | } | ||
3243 | Fl_Box autortnled { | ||
3244 | label RTN | ||
3245 | xywh {240 242 18 8} box FLAT_BOX color 93 labelfont 1 labelsize 8 hide | ||
3246 | } | ||
3247 | Fl_Box autorecled { | ||
3248 | label REC | ||
3249 | xywh {193 242 21 8} box FLAT_BOX color 1 labelfont 1 labelsize 8 align 16 hide | ||
3250 | } | ||
3251 | Fl_Box rehearseled { | ||
3252 | label REHEARSE | ||
3253 | xywh {193 251 65 8} box FLAT_BOX color 1 labelfont 1 labelsize 8 | ||
3254 | } | ||
3255 | Fl_Box pitchled { | ||
3256 | label PITCH | ||
3257 | xywh {260 242 40 8} box FLAT_BOX color 6 labelfont 1 labelsize 8 hide | ||
3258 | } | ||
3259 | } | ||
3260 | Fl_Button button_rehearse { | ||
3261 | label REHEARSE | ||
3262 | callback {control->button_rehearse_call();} | ||
3263 | tooltip {Set Locate} xywh {310 290 50 20} type Toggle box FLAT_BOX down_box FLAT_BOX color 47 selection_color 18 labelfont 1 labelsize 9 labelcolor 7 align 5 deactivate | ||
3264 | code0 {o->up_image(button_lrc_up->image()); o->down_image(button_lrc_dn->image());} | ||
3265 | class Fl_Image_Toggle_Button | ||
3266 | } | ||
3267 | Fl_Button button_punchin { | ||
3268 | label {PUNCH IN} | ||
3269 | callback {control->handlelocatebutton(hd24song::LOCATEPOS_PUNCHIN);} | ||
3270 | tooltip {Set Locate} xywh {485 290 50 20} box FLAT_BOX down_box FLAT_BOX color 47 selection_color 18 labelfont 1 labelsize 9 labelcolor 7 align 1 | ||
3271 | code0 {o->up_image(button_lrc_led_up->image()); o->down_image(button_lrc_led_dn->image());} | ||
3272 | class Fl_Image_Button | ||
3273 | } | ||
3274 | Fl_Button button_punchout { | ||
3275 | label {PUNCH OUT} | ||
3276 | callback {control->handlelocatebutton(hd24song::LOCATEPOS_PUNCHOUT);} | ||
3277 | tooltip {Set Locate} xywh {550 290 50 20} box FLAT_BOX down_box FLAT_BOX color 47 selection_color 18 labelfont 1 labelsize 9 labelcolor 7 align 9 | ||
3278 | code0 {o->up_image(button_lrc_led_up->image()); o->down_image(button_lrc_led_dn->image());} | ||
3279 | class Fl_Image_Button | ||
3280 | } | ||
3281 | Fl_Button button_peakmode { | ||
3282 | label {Peak | ||
3283 | mode} | ||
3284 | callback {this->currpeakmode=((this->currpeakmode)+1)%3; | ||
3285 | |||
3286 | for (unsigned int i=0;i<MAXCHANNELS;i++) { | ||
3287 | this->trackchan[i]->peakmode(this->currpeakmode); | ||
3288 | } | ||
3289 | switch (this->currpeakmode) | ||
3290 | { | ||
3291 | case 0: // "No" "Peak Hold" | ||
3292 | dispwrite(0," No " | ||
3293 | " Peak Hold ",2000); | ||
3294 | break; | ||
3295 | case 1: // "Momentary" "Peak Hold" | ||
3296 | dispwrite(0," Momentary " | ||
3297 | " Peak Hold ",2000); | ||
3298 | break; | ||
3299 | case 2: // "Continuous" "Peak Hold" | ||
3300 | dispwrite(0," Continuous " | ||
3301 | " Peak Hold ",2000); | ||
3302 | break; | ||
3303 | default: | ||
3304 | // ??????? | ||
3305 | break; | ||
3306 | }} | ||
3307 | tooltip arm xywh {10 375 50 30} color 8 selection_color 8 labelfont 1 labelsize 10 labelcolor 7 | ||
3308 | code0 {o->clear_visible_focus();} | ||
3309 | class Fl_Button | ||
3310 | } | ||
3311 | Fl_Button button_peakclear { | ||
3312 | label {Peak | ||
3313 | clear} | ||
3314 | callback {this->currpeakmode=((this->currpeakmode)+1)%3; | ||
3315 | |||
3316 | for (unsigned int i=0;i<MAXCHANNELS;i++) { | ||
3317 | this->trackchan[i]->peakreset(); | ||
3318 | }} | ||
3319 | tooltip arm xywh {60 375 50 30} color 8 selection_color 8 labelfont 1 labelsize 10 labelcolor 7 | ||
3320 | code0 {o->clear_visible_focus();} | ||
3321 | class Fl_Button | ||
3322 | } | ||
3323 | Fl_Button button_autoinput { | ||
3324 | label {Auto | ||
3325 | input} | ||
3326 | callback {/* | ||
3327 | if (currenthd24==NULL) return; | ||
3328 | if (button_autoinput->value()==1) { | ||
3329 | currenthd24->setautoinput(true); | ||
3330 | } else { | ||
3331 | currenthd24->setautoinput(false); | ||
3332 | } | ||
3333 | */} | ||
3334 | tooltip arm xywh {110 375 45 30} type Toggle color 8 selection_color 59 labelfont 1 labelsize 10 labelcolor 7 | ||
3335 | code0 {o->clear_visible_focus();} | ||
3336 | class Fl_Button | ||
3337 | } | ||
3338 | Fl_Button button_allinput { | ||
3339 | label {All | ||
3340 | input} | ||
3341 | callback {/* | ||
3342 | if (currenthd24==NULL) return; | ||
3343 | if (button_allinput->value()==0) { | ||
3344 | currenthd24->setallinput(false); | ||
3345 | } else { | ||
3346 | currenthd24->setallinput(true); | ||
3347 | } | ||
3348 | */} | ||
3349 | tooltip arm xywh {155 375 45 30} type Toggle color 8 selection_color 59 labelfont 1 labelsize 10 labelcolor 7 | ||
3350 | code0 {o->clear_visible_focus();} | ||
3351 | class Fl_Button | ||
3352 | } | ||
3353 | Fl_Choice stereoinmap { | ||
3354 | label {Stereo input mapping} open | ||
3355 | xywh {463 390 140 20} down_box BORDER_BOX labelsize 12 align 5 textsize 12 deactivate | ||
3356 | } { | ||
3357 | MenuItem {} { | ||
3358 | label Normal | ||
3359 | xywh {5 5 36 21} labelsize 12 | ||
3360 | } | ||
3361 | MenuItem {} { | ||
3362 | label {Swap Left and Right} | ||
3363 | xywh {15 15 36 21} labelsize 12 | ||
3364 | } | ||
3365 | MenuItem {} { | ||
3366 | label {Mix to mono} | ||
3367 | xywh {15 15 36 21} labelsize 12 | ||
3368 | } | ||
3369 | MenuItem {} { | ||
3370 | label {Use Left only} | ||
3371 | xywh {25 25 36 21} labelsize 12 | ||
3372 | } | ||
3373 | MenuItem {} { | ||
3374 | label {Use Right only} | ||
3375 | xywh {35 35 36 21} labelsize 12 | ||
3376 | } | ||
3377 | } | ||
3378 | Fl_Roller {} { | ||
3379 | label {Drag to Jog} | ||
3380 | callback {// scrubwheel calls button_scrub_call()} | ||
3381 | xywh {310 390 110 20} type Horizontal labelsize 12 align 1 minimum -1 step 2 | ||
3382 | code0 {o->setui(this);} | ||
3383 | class ScrubWheel | ||
3384 | } | ||
3385 | } | ||
3386 | } | ||
3387 | decl {/* === Audio/transport ===================================================== */} {} | ||
3388 | decl {int hlbuttons_defaultcolor;} {public | ||
3389 | } | ||
3390 | Function {highlight_setbuttons(int value)} {open return_type void | ||
3391 | } { | ||
3392 | code {if (value==1) { | ||
3393 | if (button_loopstart!=NULL) { | ||
3394 | button_loopstart->up_image(button_lrc_led_on_up->image()); | ||
3395 | button_loopstart->down_image(button_lrc_led_on_dn->image()); | ||
3396 | } | ||
3397 | if (button_loopend!=NULL) { | ||
3398 | button_loopend->up_image(button_lrc_led_on_up->image()); | ||
3399 | button_loopend->down_image(button_lrc_led_on_dn->image()); | ||
3400 | } | ||
3401 | if (button_punchin!=NULL) { | ||
3402 | button_punchin->up_image(button_lrc_led_on_up->image()); | ||
3403 | button_punchin->down_image(button_lrc_led_on_dn->image()); | ||
3404 | } | ||
3405 | if (button_punchout!=NULL) { | ||
3406 | button_punchout->up_image(button_lrc_led_on_up->image()); | ||
3407 | button_punchout->down_image(button_lrc_led_on_dn->image()); | ||
3408 | } | ||
3409 | } else { | ||
3410 | button_loopstart->up_image(button_lrc_led_up->image()); | ||
3411 | button_loopstart->down_image(button_lrc_led_dn->image()); | ||
3412 | button_loopend->up_image(button_lrc_led_up->image()); | ||
3413 | button_loopend->down_image(button_lrc_led_dn->image()); | ||
3414 | button_punchin->up_image(button_lrc_led_up->image()); | ||
3415 | button_punchin->down_image(button_lrc_led_dn->image()); | ||
3416 | button_punchout->up_image(button_lrc_led_up->image()); | ||
3417 | button_punchout->down_image(button_lrc_led_dn->image()); | ||
3418 | } | ||
3419 | if (button_punchout!=NULL) { button_punchout->redraw(); } | ||
3420 | if (button_punchin!=NULL) { button_punchin->redraw(); } | ||
3421 | if (button_loopstart!=NULL) { button_loopstart->redraw(); } | ||
3422 | if (button_loopend!=NULL) { button_loopend->redraw();}} {} | ||
3423 | } | ||
3424 | Function {poll_callback(void* user)} {open return_type {static void} | ||
3425 | } { | ||
3426 | code {//HD24UserInterface* mythis=(HD24UserInterface*)user; | ||
3427 | RecorderUI* mythis=(RecorderUI*)user; | ||
3428 | int visible=0; | ||
3429 | if (mythis->recordergroup->visible()) | ||
3430 | { | ||
3431 | visible=1; | ||
3432 | } else { | ||
3433 | visible=0; | ||
3434 | } | ||
3435 | |||
3436 | |||
3437 | if (mythis->control->ready()!=1) { return; } | ||
3438 | |||
3439 | if (mythis->dispwritecountdown>0) | ||
3440 | { | ||
3441 | mythis->dispwritecountdown--; | ||
3442 | if (mythis->dispwritecountdown==0) { | ||
3443 | mythis->disprestore(); | ||
3444 | } | ||
3445 | } | ||
3446 | |||
3447 | if (mythis->busy!=1) { | ||
3448 | mythis->busy=1; | ||
3449 | mythis->blinkcounter=(mythis->blinkcounter+1)%BLINKRATE; | ||
3450 | |||
3451 | if (visible==1) { | ||
3452 | for (unsigned int i=0;i<MAXCHANNELS;i++) { | ||
3453 | mythis->trackchan[i]->setval(mythis->control->data->trackpeak[i]); | ||
3454 | } | ||
3455 | |||
3456 | Fl_Image* oldimg; | ||
3457 | Fl_Image* newimg=NULL; | ||
3458 | |||
3459 | string* dur=NULL; | ||
3460 | hd24song* mycurrsong=mythis->control->song(); | ||
3461 | if (mycurrsong!=NULL) { | ||
3462 | dur=mycurrsong->display_cursor(); | ||
3463 | } else { | ||
3464 | dur=new string("00:00:00.00"); | ||
3465 | } | ||
3466 | |||
3467 | |||
3468 | oldimg=mythis->ho1->image(); | ||
3469 | mythis->ho1->image(mythis->i7seg[dur->c_str()[0]-'0']->image()); | ||
3470 | if (newimg!=oldimg) mythis->ho1->redraw(); | ||
3471 | |||
3472 | oldimg=mythis->ho2->image(); | ||
3473 | mythis->ho2->image(mythis->i7seg[dur->c_str()[1]-'0']->image()); | ||
3474 | if (newimg!=oldimg) mythis->ho2->redraw(); | ||
3475 | |||
3476 | oldimg=mythis->mi1->image(); | ||
3477 | mythis->mi1->image(mythis->i7seg[dur->c_str()[3]-'0']->image()); | ||
3478 | if (newimg!=oldimg) mythis->mi1->redraw(); | ||
3479 | |||
3480 | oldimg=mythis->mi2->image(); | ||
3481 | mythis->mi2->image(mythis->i7seg[dur->c_str()[4]-'0']->image()); | ||
3482 | if (newimg!=oldimg) mythis->mi2->redraw(); | ||
3483 | |||
3484 | oldimg=mythis->se1->image(); | ||
3485 | mythis->se1->image(mythis->i7seg[dur->c_str()[6]-'0']->image()); | ||
3486 | if (newimg!=oldimg) mythis->se1->redraw(); | ||
3487 | |||
3488 | oldimg=mythis->se2->image(); | ||
3489 | mythis->se2->image(mythis->i7seg[dur->c_str()[7]-'0']->image()); | ||
3490 | if (newimg!=oldimg) mythis->se2->redraw(); | ||
3491 | oldimg=mythis->fr1->image(); | ||
3492 | mythis->fr1->image(mythis->i7seg[dur->c_str()[9]-'0']->image()); | ||
3493 | if (newimg!=oldimg) mythis->fr1->redraw(); | ||
3494 | |||
3495 | oldimg=mythis->fr2->image(); | ||
3496 | mythis->fr2->image(mythis->i7seg[dur->c_str()[10]-'0']->image()); | ||
3497 | if (newimg!=oldimg) mythis->fr2->redraw(); | ||
3498 | if ((mythis->mustdisplaytimer) && (mycurrsong !=NULL)) | ||
3499 | { | ||
3500 | |||
3501 | // mythis->setstatus(*dur); | ||
3502 | __uint32 currloc=mycurrsong->cursorpos(); | ||
3503 | if (mycurrsong->songlength_in_samples() >0) { | ||
3504 | currloc=mycurrsong->cursorpos()/(mycurrsong->songlength_in_samples()/1000); | ||
3505 | } else { | ||
3506 | currloc=0; | ||
3507 | } | ||
3508 | if (mythis->slidermoved!=0) { | ||
3509 | mythis->slidermoved--; | ||
3510 | } else { | ||
3511 | mythis->locationslider->value(currloc); | ||
3512 | } | ||
3513 | } | ||
3514 | delete (dur); | ||
3515 | } | ||
3516 | |||
3517 | } | ||
3518 | mythis->busy=0; | ||
3519 | //Fl::add_timeout(TIMEOUT,poll_callback,user); | ||
3520 | |||
3521 | AudioSystem* audio=mythis->control->audio; | ||
3522 | |||
3523 | if (!audio->isinitialized()) return; | ||
3524 | if (!audio->mustloop()) return; | ||
3525 | audio->hd24_transport_locate((__sint64)(audio->looppos())); | ||
3526 | audio->mustloop(false); | ||
3527 | audio->looppos(0);} {} | ||
3528 | } | ||
3529 | Function {fl_check()} {open return_type void | ||
3530 | } { | ||
3531 | code {Fl::check();} {} | ||
3532 | } | ||
3533 | decl {int busy;} {public | ||
3534 | } | ||
3535 | decl {friend class ScrubWheel;} {} | ||
3536 | decl {int uiredrawcount; /* to limit refreshing UI */} {public | ||
3537 | } | ||
3538 | Function {finish()} {open return_type void | ||
3539 | } { | ||
3540 | code {if (this==NULL) return; | ||
3541 | |||
3542 | this->control->button_stop_call();} {} | ||
3543 | } | ||
3544 | Function {button_light(void* button,bool lit)} {open return_type void | ||
3545 | } { | ||
3546 | code {if (button==NULL) return; | ||
3547 | if (((Fl_Image_Button*)button)==button_stop) | ||
3548 | { | ||
3549 | if (lit==1) | ||
3550 | { | ||
3551 | button_stop->up_image(button_stop_uplit->image()); | ||
3552 | button_stop->down_image(button_stop_dn->image()); | ||
3553 | } | ||
3554 | else | ||
3555 | { | ||
3556 | button_stop->up_image(button_stop_up->image()); | ||
3557 | button_stop->down_image(button_stop_dn->image()); | ||
3558 | } | ||
3559 | button_stop->redraw(); | ||
3560 | return; | ||
3561 | }} {} | ||
3562 | } | ||
3563 | Function {button_up(void* button)} {open return_type void | ||
3564 | } { | ||
3565 | code {if (button==NULL) | ||
3566 | { | ||
3567 | return; | ||
3568 | } | ||
3569 | |||
3570 | if ((void*)button==(void*)button_stop) | ||
3571 | { | ||
3572 | button_stop->value(0); | ||
3573 | button_stop->redraw(); | ||
3574 | return; | ||
3575 | } | ||
3576 | if ((void*)button==(void*)button_play) | ||
3577 | { | ||
3578 | button_play->value(0); | ||
3579 | button_play->redraw(); | ||
3580 | return; | ||
3581 | } | ||
3582 | if ((void*)button==(void*)button_rec) | ||
3583 | { | ||
3584 | button_rec->value(0); | ||
3585 | button_rec->redraw(); | ||
3586 | return; | ||
3587 | } | ||
3588 | if ((void*)button==(void*)button_rew) | ||
3589 | { | ||
3590 | button_rew->value(0); | ||
3591 | button_rew->redraw(); | ||
3592 | return; | ||
3593 | } | ||
3594 | if ((void*)button==(void*)button_ffwd) | ||
3595 | { | ||
3596 | button_ffwd->value(0); | ||
3597 | button_ffwd->redraw(); | ||
3598 | return; | ||
3599 | }} {} | ||
3600 | } | ||
3601 | Function {button_down(void* button)} {open return_type void | ||
3602 | } { | ||
3603 | code {if (button==NULL) | ||
3604 | { | ||
3605 | return; | ||
3606 | } | ||
3607 | |||
3608 | if ((void*)button==(void*)button_stop) | ||
3609 | { | ||
3610 | button_stop->value(1); | ||
3611 | button_stop->redraw(); | ||
3612 | return; | ||
3613 | } | ||
3614 | if ((void*)button==(void*)button_play) | ||
3615 | { | ||
3616 | button_play->value(1); | ||
3617 | button_play->redraw(); | ||
3618 | return; | ||
3619 | } | ||
3620 | if ((void*)button==(void*)button_rec) | ||
3621 | { | ||
3622 | button_rec->value(1); | ||
3623 | button_rec->redraw(); | ||
3624 | return; | ||
3625 | } | ||
3626 | if ((void*)button==(void*)button_rew) | ||
3627 | { | ||
3628 | button_rew->value(1); | ||
3629 | button_rew->redraw(); | ||
3630 | return; | ||
3631 | } | ||
3632 | if ((void*)button==(void*)button_ffwd) | ||
3633 | { | ||
3634 | button_ffwd->value(1); | ||
3635 | button_ffwd->redraw(); | ||
3636 | return; | ||
3637 | }} {} | ||
3638 | } | ||
3639 | } | ||
diff --git a/src/hd24hexview.cpp b/src/hd24hexview.cpp new file mode 100755 index 0000000..8ee4751 --- /dev/null +++ b/src/hd24hexview.cpp | |||
@@ -0,0 +1,923 @@ | |||
1 | #include <iostream> | ||
2 | #include <algorithm> | ||
3 | #include <cctype> | ||
4 | #include <string> | ||
5 | #include <sys/types.h> | ||
6 | #include <sys/stat.h> | ||
7 | #include <fcntl.h> | ||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include "config.h" | ||
11 | #include "hd24fs.h" | ||
12 | #include "convertlib.h" | ||
13 | |||
14 | #define VERSION "1.3 beta" | ||
15 | #define _LARGE_FILES | ||
16 | #define _FILE_OFFSET_BITS 64 | ||
17 | #define FILE_OFFSET_BITS 64 | ||
18 | #define LARGE_FILES | ||
19 | #define LARGEFILE64_SOURCE | ||
20 | #define SECTORSIZE 512 | ||
21 | #define ARGHEADER "--header=" | ||
22 | |||
23 | #ifdef DARWIN | ||
24 | # define open64 open | ||
25 | # define lseek64 lseek | ||
26 | # define pread64 pread | ||
27 | # define creat64 creat | ||
28 | # define pwrite64 pwrite | ||
29 | #endif | ||
30 | |||
31 | #ifndef WINDOWS | ||
32 | # include <unistd.h> | ||
33 | #endif | ||
34 | |||
35 | string device; | ||
36 | string headerfilename; | ||
37 | __uint64 writeoffset; | ||
38 | int force; | ||
39 | int expertmode; | ||
40 | int graphmode; | ||
41 | int enable_graphmode; | ||
42 | int disable_graphmode; | ||
43 | |||
44 | // Check if a file exists | ||
45 | bool fileexists (string* fname) | ||
46 | { | ||
47 | struct stat fi; | ||
48 | |||
49 | if ((stat(fname->c_str(), &fi) != -1) && ((fi.st_mode & S_IFDIR) == 0)) { | ||
50 | return true; | ||
51 | } | ||
52 | |||
53 | return false; | ||
54 | } | ||
55 | |||
56 | // Check if file handle is invalid | ||
57 | bool isinvalidhandle(FSHANDLE handle) | ||
58 | { | ||
59 | #ifdef WINDOWS | ||
60 | if (handle == FSHANDLE_INVALID) { | ||
61 | return true; | ||
62 | } | ||
63 | #else | ||
64 | if (handle == 0 || handle == FSHANDLE_INVALID) { | ||
65 | return true; | ||
66 | } | ||
67 | #endif | ||
68 | return false; | ||
69 | } | ||
70 | |||
71 | // Output a message for expert only features | ||
72 | void expertmodemessage(string feature) | ||
73 | { | ||
74 | cout << feature <<" is only allowed in expert mode." << endl; | ||
75 | } | ||
76 | |||
77 | // Seek to a position in the drive | ||
78 | void hd24seek(FSHANDLE devhd24, __uint64 seekpos) | ||
79 | { | ||
80 | #ifdef WINDOWS | ||
81 | LARGE_INTEGER li; | ||
82 | li.HighPart = seekpos >> 32; | ||
83 | li.LowPart = seekpos % ((__uint64) 1 << 32); | ||
84 | SetFilePointerEx(devhd24, li, NULL, FILE_BEGIN); | ||
85 | #else | ||
86 | lseek64(devhd24, seekpos, 0); | ||
87 | #endif | ||
88 | return; | ||
89 | } | ||
90 | |||
91 | // Calculate a 32-bit checksum for a block | ||
92 | long unsigned int calcblockchecksum(hd24raw* rawdevice, unsigned long firstsector, unsigned long endsector) | ||
93 | { | ||
94 | long unsigned int checksum32 = 0; | ||
95 | unsigned char origblock[5120]; | ||
96 | |||
97 | for (unsigned long k = firstsector; k < endsector; k++) | ||
98 | { | ||
99 | rawdevice->readsectors(k, origblock, 1); | ||
100 | |||
101 | for (unsigned long i = 0; i < SECTORSIZE; i += 4) | ||
102 | { | ||
103 | unsigned long num = Convert::getint32(origblock, i); | ||
104 | int byte1 = num % 256; | ||
105 | int byte2 = (num >> 8) % 256; | ||
106 | int byte3 = (num >> 16) % 256; | ||
107 | int byte4 = (num >> 24) % 256; | ||
108 | num = byte4 + (byte3 << 8) + (byte2 << 16) + (byte1 << 24); | ||
109 | checksum32 += num; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | return checksum32; | ||
114 | } | ||
115 | |||
116 | // Write to a sector | ||
117 | long writesectors(FSHANDLE devhd24, unsigned long sectornum, unsigned char * buffer, int sectors) | ||
118 | { | ||
119 | int WRITESIZE = SECTORSIZE * sectors; // allows searching across sector boundaries | ||
120 | hd24seek(devhd24, (__uint64) sectornum * 512); | ||
121 | |||
122 | #ifdef WINDOWS | ||
123 | DWORD dummy; | ||
124 | long bytes = 0; | ||
125 | |||
126 | if (WriteFile(devhd24, buffer, WRITESIZE, &dummy, NULL)) { | ||
127 | bytes = WRITESIZE; | ||
128 | }; | ||
129 | #else | ||
130 | long bytes = pwrite64(devhd24, buffer, WRITESIZE, (__uint64) sectornum * 512); | ||
131 | #endif | ||
132 | |||
133 | return bytes; | ||
134 | } | ||
135 | |||
136 | void writetofile(hd24raw* rawdevice,string filename, long firstsector,long endsector) | ||
137 | { | ||
138 | int i; | ||
139 | unsigned char bootblock[5120]; | ||
140 | #if defined(LINUX) || defined(DARWIN) | ||
141 | FSHANDLE handle=creat64(filename.c_str(),O_WRONLY); | ||
142 | #endif | ||
143 | #ifdef WINDOWS | ||
144 | FSHANDLE handle=CreateFile(filename.c_str(),GENERIC_WRITE|GENERIC_READ, | ||
145 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
146 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
147 | if (isinvalidhandle(handle)) { | ||
148 | handle=CreateFile(filename.c_str(),GENERIC_WRITE|GENERIC_READ, | ||
149 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
150 | NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); | ||
151 | } | ||
152 | |||
153 | #endif | ||
154 | if (isinvalidhandle(handle)) { | ||
155 | cout << "Cannot open file "<<filename <<" for writing. Access denied?" << endl; | ||
156 | return; | ||
157 | } | ||
158 | cout << "Write range from offset "<< *Convert::int64tohex((__uint64)firstsector*512)<< " to offset " << *Convert::int64tohex((__uint64)endsector*512-1) << endl; | ||
159 | for (i=firstsector;i<endsector;i++) { | ||
160 | rawdevice->readsectors(i,bootblock,1); | ||
161 | #if defined(LINUX) || defined(DARWIN) | ||
162 | __uint64 targetoff=i; | ||
163 | targetoff-=firstsector; | ||
164 | targetoff+=writeoffset; | ||
165 | targetoff*=512; | ||
166 | ssize_t byteswritten=pwrite64(handle,bootblock,512,targetoff); | ||
167 | #endif | ||
168 | #ifdef WINDOWS | ||
169 | //DWORD dummy; | ||
170 | //long bytes=0; | ||
171 | __uint64 targetoff=i; | ||
172 | targetoff-=firstsector; | ||
173 | targetoff+=writeoffset; | ||
174 | __uint64 byteswritten=writesectors(handle,targetoff,bootblock,1); | ||
175 | #endif | ||
176 | if (byteswritten==0) { | ||
177 | cout << "Wrote 0 bytes to file. Access denied?" << endl; | ||
178 | #if defined(LINUX) || defined(DARWIN) | ||
179 | close (handle); | ||
180 | #endif | ||
181 | #ifdef WNDOWS | ||
182 | CloseHandle(handle); | ||
183 | #endif | ||
184 | return; | ||
185 | } | ||
186 | if ((i%1000)==0) { | ||
187 | string* x=Convert::int64tohex((__uint64)i*0x200); | ||
188 | cout << "Write offset " << *x << "\r"; | ||
189 | if (x!=NULL) { delete x; x=NULL; } | ||
190 | } | ||
191 | } | ||
192 | #if defined(LINUX) || defined(DARWIN) | ||
193 | close (handle); | ||
194 | #endif | ||
195 | #ifdef WINDOWS | ||
196 | CloseHandle(handle); | ||
197 | #endif | ||
198 | return; | ||
199 | } | ||
200 | |||
201 | string getbinstr(string tofind) | ||
202 | { | ||
203 | if (tofind.substr(0,1)=="'") { | ||
204 | // find literal string | ||
205 | tofind=tofind.substr(1,tofind.length()-2); | ||
206 | cout << "Find string " << tofind << endl; | ||
207 | } else { | ||
208 | string binstr=""; | ||
209 | string tmp=""; | ||
210 | tofind+=" "; | ||
211 | unsigned int i; | ||
212 | for (i=0;i<tofind.length();i++) { | ||
213 | string onechar=tofind.substr(i,1); | ||
214 | if (onechar!=" ") { | ||
215 | if (!Convert::isnibble(onechar)) { | ||
216 | cout << "Error: not a valid hex string" << endl; | ||
217 | return ""; | ||
218 | } | ||
219 | tmp+=onechar; | ||
220 | } else { | ||
221 | if (tmp!="") { | ||
222 | binstr+=Convert::hex2byte(tmp); | ||
223 | } | ||
224 | tmp=""; | ||
225 | } | ||
226 | } | ||
227 | tofind=binstr; | ||
228 | cout << "looking for " << binstr << endl; | ||
229 | } | ||
230 | return *(new string(tofind)); | ||
231 | } | ||
232 | |||
233 | long movebytes(unsigned char* bootblock,string editstr) | ||
234 | { | ||
235 | string strfrompos=""; | ||
236 | string strmovelen=""; | ||
237 | string strtopos=""; | ||
238 | while ( | ||
239 | (editstr.substr(0,1)!=" ") | ||
240 | &&(editstr.substr(0,1)!="l") | ||
241 | &&(editstr.substr(0,1)!="L") | ||
242 | &&(editstr!="")) | ||
243 | { | ||
244 | strfrompos+=editstr.substr(0,1); | ||
245 | editstr=editstr.substr(1,editstr.length()-1); | ||
246 | } | ||
247 | if ( | ||
248 | (editstr.substr(0,1)=="l") | ||
249 | ||(editstr.substr(0,1)=="L")) | ||
250 | { | ||
251 | editstr=editstr.substr(1,editstr.length()-1); | ||
252 | |||
253 | while ( | ||
254 | (editstr.substr(0,1)!=" ") | ||
255 | &&(editstr!="")) | ||
256 | { | ||
257 | strmovelen+=editstr.substr(0,1); | ||
258 | editstr=editstr.substr(1,editstr.length()-1); | ||
259 | } | ||
260 | } else { | ||
261 | cout << "Syntax: m<from>L<len> <target>" << endl; | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | if ( | ||
266 | (editstr.substr(0,1)==" ") | ||
267 | ) | ||
268 | { | ||
269 | editstr=editstr.substr(1,editstr.length()-1); | ||
270 | |||
271 | while ( | ||
272 | (editstr.substr(0,1)!=" ") | ||
273 | &&(editstr!="")) | ||
274 | { | ||
275 | strtopos+=editstr.substr(0,1); | ||
276 | editstr=editstr.substr(1,editstr.length()-1); | ||
277 | } | ||
278 | } else { | ||
279 | cout << "Syntax: m<from>L<len> <target>" << endl; | ||
280 | return 0; | ||
281 | } | ||
282 | cout << " strfrompos=" << strfrompos << endl; | ||
283 | cout << " strmovelen=" << strmovelen << endl; | ||
284 | cout << " strtopos=" << strtopos << endl; | ||
285 | |||
286 | long frompos=(Convert::hex2long(strfrompos)%SECTORSIZE); | ||
287 | long movelen=(Convert::hex2long(strmovelen)%SECTORSIZE); | ||
288 | long topos=(Convert::hex2long(strtopos)%SECTORSIZE); | ||
289 | cout << " pos=" << frompos << endl; | ||
290 | cout << " movelen=" << movelen << endl; | ||
291 | cout << " movepos=" << topos << endl; | ||
292 | void* x=malloc(movelen); | ||
293 | memcpy(x,bootblock+frompos,movelen); | ||
294 | memcpy(bootblock+topos,x,movelen); | ||
295 | free (x); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | long editbytes(unsigned char* bootblock,string editstr) | ||
300 | { | ||
301 | string strpos=""; | ||
302 | while ((editstr.substr(0,1)!=" ") &&(editstr!="")) { | ||
303 | strpos+=editstr.substr(0,1); | ||
304 | editstr=editstr.substr(1,editstr.length()-1); | ||
305 | } | ||
306 | if (editstr!="") { | ||
307 | editstr=editstr.substr(1,editstr.length()-1); | ||
308 | } | ||
309 | string binstr=getbinstr(editstr); | ||
310 | long pos=(Convert::hex2long(strpos)%SECTORSIZE); | ||
311 | cout << "binstr=" << binstr << " " << pos << endl; | ||
312 | memcpy(bootblock+pos,binstr.c_str(),binstr.length()); | ||
313 | return 0; | ||
314 | } | ||
315 | |||
316 | void compareblock(hd24raw* rawdevice,unsigned long firstsector,unsigned long endsector,long current) | ||
317 | { | ||
318 | unsigned int i; | ||
319 | unsigned int j; | ||
320 | unsigned int k; | ||
321 | unsigned char origblock[5120]; | ||
322 | unsigned char destblock[5120]; | ||
323 | string* startoff=Convert::int64tohex((__uint64)firstsector*512); | ||
324 | string* endoff=Convert::int64tohex((__uint64)endsector*512-1); | ||
325 | cout << "Compare range from offset "<< *startoff << " to offset " << *endoff <<endl; | ||
326 | delete startoff; startoff=NULL; | ||
327 | delete endoff; endoff=NULL; | ||
328 | int anydifs=0; | ||
329 | for (k=firstsector; k<endsector; k++) | ||
330 | { | ||
331 | rawdevice->readsectors(k,origblock,1); | ||
332 | rawdevice->readsectors(k-firstsector+current,destblock,1); | ||
333 | for (i=0;i<SECTORSIZE;i+=16) { | ||
334 | string strline1=""; | ||
335 | string strline2=""; | ||
336 | int havedifs=0; | ||
337 | long offset=k*512; | ||
338 | string* result1=Convert::int32tohex(offset+i); | ||
339 | strline1+= *result1+" "; | ||
340 | offset=current*512; | ||
341 | delete result1; result1=NULL; | ||
342 | string* result2=Convert::int32tohex(offset+i); | ||
343 | strline2+= *result2+" "; | ||
344 | delete result2; result2=NULL; | ||
345 | for (j=0;j<16;j++) | ||
346 | { | ||
347 | if (origblock[i+j]!=destblock[i+j]) | ||
348 | { | ||
349 | string* result=Convert::byte2hex(origblock[i+j]); | ||
350 | strline1+= *result; | ||
351 | delete result; result=NULL; | ||
352 | havedifs=1; | ||
353 | } else { | ||
354 | strline1+=" "; | ||
355 | } | ||
356 | string *result= Convert::byte2hex(destblock[i+j]) ; | ||
357 | strline2+= *result; | ||
358 | delete result; result=NULL; | ||
359 | if (j==7) { | ||
360 | strline1+= "-" ; | ||
361 | strline2+= "-" ; | ||
362 | } else { | ||
363 | strline1+= " " ; | ||
364 | strline2+= " " ; | ||
365 | } | ||
366 | } | ||
367 | strline1+= " "; | ||
368 | strline2+= " "; | ||
369 | for (j=0;j<16;j++) { | ||
370 | strline1+= Convert::safebyte(origblock[i+j]); | ||
371 | if (origblock[i+j]!=destblock[i+j]) { | ||
372 | strline2+= Convert::safebyte(destblock[i+j]); | ||
373 | } else { | ||
374 | strline2+=" "; | ||
375 | } | ||
376 | } | ||
377 | if (havedifs==1) { | ||
378 | anydifs=1; | ||
379 | cout << strline1 << endl; | ||
380 | cout << strline2 << endl; | ||
381 | } | ||
382 | } | ||
383 | } | ||
384 | if (anydifs==0) { | ||
385 | cout << "Blocks are equal." << endl; | ||
386 | } | ||
387 | } | ||
388 | |||
389 | long scanforblock(hd24raw* rawdevice,string tofind,unsigned long firstsector,unsigned long endsector,long current) | ||
390 | { | ||
391 | unsigned int i; | ||
392 | unsigned char bootblock[5120]; | ||
393 | tofind=getbinstr(tofind); | ||
394 | if (tofind=="") return current; | ||
395 | |||
396 | /* Now that we know what to look for, let us try to find the string. | ||
397 | * Note that we can search across sector boundaries because we read | ||
398 | * 2 sectors at a time. | ||
399 | */ | ||
400 | string* startoff= Convert::int64tohex((__uint64)firstsector*512); | ||
401 | string* endoff=Convert::int64tohex((__uint64)endsector*512-1); | ||
402 | cout << "Scan range from offset "<< *startoff << " to offset " << *endoff << endl; | ||
403 | delete startoff; startoff=NULL; | ||
404 | delete endoff; endoff=NULL; | ||
405 | for (i=firstsector; i<endsector; i++) { | ||
406 | rawdevice->readsectors(i,bootblock,2); | ||
407 | if ((i%0x1000)==0) { | ||
408 | string* curroff=Convert::int64tohex((__uint64)i*0x200); | ||
409 | cout << "Scan offset " << *curroff << "\r"; | ||
410 | delete curroff; curroff=NULL; | ||
411 | } | ||
412 | /* check if string found. */ | ||
413 | int j=0; | ||
414 | for (j=0;j<512;j++) { | ||
415 | |||
416 | if (memcmp((const void *)&bootblock[j],(const void *)tofind.c_str(),(size_t)tofind.length())==0) { | ||
417 | string* foundoff=Convert::int64tohex((__uint64)i*512+j); | ||
418 | cout << endl << "Found on offset " << *foundoff << endl; | ||
419 | delete foundoff; foundoff=NULL; | ||
420 | return i; | ||
421 | } | ||
422 | } | ||
423 | } | ||
424 | cout << endl << "Not found." << endl; | ||
425 | return current; | ||
426 | } | ||
427 | |||
428 | void fstfix(unsigned char * bootblock,int fixsize) | ||
429 | { | ||
430 | for (int i=0;i<fixsize;i+=4) | ||
431 | { | ||
432 | unsigned char a=bootblock[i]; | ||
433 | unsigned char b=bootblock[i+1]; | ||
434 | unsigned char c=bootblock[i+2]; | ||
435 | unsigned char d=bootblock[i+3]; | ||
436 | bootblock[i]=d; | ||
437 | bootblock[i+1]=c; | ||
438 | bootblock[i+2]=b; | ||
439 | bootblock[i+3]=a; | ||
440 | } | ||
441 | } | ||
442 | |||
443 | int parsecommandline(int argc, char ** argv) | ||
444 | { | ||
445 | int invalid=0; | ||
446 | force=0; | ||
447 | expertmode=0; | ||
448 | device=""; | ||
449 | headerfilename=""; | ||
450 | for (int c=1;c<argc;c++) { | ||
451 | string arg=argv[c]; | ||
452 | if (arg.substr(0,2)!="--") { | ||
453 | if (fileexists(&arg)) { | ||
454 | device=arg; | ||
455 | force=1; | ||
456 | continue; | ||
457 | } | ||
458 | } | ||
459 | if (arg.substr(0,strlen("--dev="))=="--dev=") { | ||
460 | device=arg.substr(strlen("--dev=")); | ||
461 | continue; | ||
462 | } | ||
463 | if (arg.substr(0,strlen("--expert"))=="--expert") { | ||
464 | expertmode=1; | ||
465 | continue; | ||
466 | } | ||
467 | if (arg.substr(0,strlen(ARGHEADER))==ARGHEADER) { | ||
468 | headerfilename=arg.substr(strlen(ARGHEADER)); | ||
469 | continue; | ||
470 | } | ||
471 | |||
472 | if (arg.substr(0,strlen("--force"))=="--force") { | ||
473 | force=1; | ||
474 | continue; | ||
475 | } | ||
476 | cout << "Invalid argument: " << arg << endl; | ||
477 | invalid=1; | ||
478 | } | ||
479 | return invalid; | ||
480 | } | ||
481 | |||
482 | int main (int argc,char ** argv) | ||
483 | { | ||
484 | int invalid=parsecommandline(argc,argv); | ||
485 | if (invalid!=0) { | ||
486 | return invalid; | ||
487 | } | ||
488 | |||
489 | hd24fs* fsys = NULL; | ||
490 | if (device=="") { | ||
491 | fsys=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR); | ||
492 | } else { | ||
493 | cout << "Trying to use " << device << " as hd24 device." << endl; | ||
494 | fsys=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,&device,(force==1)); | ||
495 | } | ||
496 | |||
497 | hd24raw* rawdevice = NULL; | ||
498 | |||
499 | rawdevice=new hd24raw(fsys); //1==1 is true -> no translate | ||
500 | if (!fsys->isOpen()) { | ||
501 | cout << "Cannot open hd24 device." << endl; | ||
502 | delete fsys; fsys=NULL; | ||
503 | if (rawdevice!=NULL) | ||
504 | { | ||
505 | delete rawdevice; | ||
506 | rawdevice=NULL; | ||
507 | } | ||
508 | return 1; | ||
509 | } | ||
510 | if (headerfilename!="") | ||
511 | { | ||
512 | if (!(fsys->useheaderfile(headerfilename))) | ||
513 | { | ||
514 | cout << "Couldn't load header file "<<headerfilename << endl; | ||
515 | delete fsys; fsys=NULL; | ||
516 | return 1; | ||
517 | }; | ||
518 | } | ||
519 | //delete fsys; //not yet, rawdevice is using this | ||
520 | cout << "Using device " << *fsys->getdevicename() << endl; | ||
521 | /* Initialization */ | ||
522 | unsigned char bootblock[5120]; | ||
523 | unsigned long sectornum=0; | ||
524 | int nodump=0; | ||
525 | int noread=0; | ||
526 | int writesec=0; | ||
527 | unsigned long blockstart=0; | ||
528 | unsigned long blockend=0; | ||
529 | writeoffset=0; | ||
530 | unsigned long checksum=0; | ||
531 | string userinput; | ||
532 | string lastsearch=""; | ||
533 | if (expertmode==1) { | ||
534 | cout << "Expert mode enabled. " << endl; | ||
535 | cout << "Warning! Disk writes are enabled." << endl; | ||
536 | cout << "You now have the capability to destroy." << endl; | ||
537 | cout << "Proceed with extreme caution!" << endl; | ||
538 | } | ||
539 | |||
540 | try{ | ||
541 | /* try block is intended to make sure hd24 device is closed on exit*/ | ||
542 | string filename="outfile.dmp"; | ||
543 | |||
544 | do { | ||
545 | int i; | ||
546 | int j; | ||
547 | if (enable_graphmode==1) | ||
548 | { | ||
549 | cout << "Enabling graph mode." << endl; | ||
550 | graphmode=1; | ||
551 | enable_graphmode=0; | ||
552 | } | ||
553 | if (disable_graphmode==1) { | ||
554 | cout << "Disabling graph mode." << endl; | ||
555 | graphmode=0; | ||
556 | disable_graphmode=0; | ||
557 | } | ||
558 | if (writesec==1) { | ||
559 | rawdevice->writesectors(sectornum,bootblock,1); | ||
560 | writesec=0; | ||
561 | } | ||
562 | if (noread==0) { | ||
563 | rawdevice->readsectors(sectornum,bootblock,1); | ||
564 | } | ||
565 | noread=0; | ||
566 | long offset=sectornum*512; | ||
567 | if (nodump==0) { | ||
568 | cout << "Sector " << *Convert::int32tohex((long)sectornum) << endl; | ||
569 | |||
570 | for (i=0;i<SECTORSIZE;i+=16) { | ||
571 | string* dummy=Convert::int32tohex(offset+i); | ||
572 | cout << *dummy << " "; | ||
573 | delete dummy; dummy=NULL; | ||
574 | for (j=0;j<16;j++) { | ||
575 | string* dummy= Convert::byte2hex(bootblock[i+j]); | ||
576 | cout << *dummy; | ||
577 | if (j==7) { | ||
578 | cout << "-" ; | ||
579 | } else { | ||
580 | cout << " " ; | ||
581 | } | ||
582 | delete dummy; dummy=NULL; | ||
583 | } | ||
584 | cout << " "; | ||
585 | for (j=0;j<16;j++) { | ||
586 | cout << Convert::safebyte(bootblock[i+j]); | ||
587 | } | ||
588 | cout << "" << endl; | ||
589 | } | ||
590 | } | ||
591 | nodump=0; | ||
592 | cout << "-"; | ||
593 | char inputbuf[1025]; | ||
594 | cin.getline(inputbuf,1024); | ||
595 | userinput=""; | ||
596 | userinput+=inputbuf; | ||
597 | if (userinput=="") { | ||
598 | continue; | ||
599 | } | ||
600 | while ( | ||
601 | (userinput.substr(userinput.length()-1,1)==" ") | ||
602 | ||(userinput.substr(userinput.length()-1,1)=="\n") | ||
603 | ||(userinput.substr(userinput.length()-1,1)=="\r") | ||
604 | ) | ||
605 | { | ||
606 | userinput=userinput.substr(0,userinput.length()-1); | ||
607 | } | ||
608 | if (userinput=="+") { | ||
609 | sectornum++; | ||
610 | continue; | ||
611 | } | ||
612 | if (userinput=="gon") { | ||
613 | if (graphmode==0) { | ||
614 | enable_graphmode=1; | ||
615 | } | ||
616 | continue; | ||
617 | } | ||
618 | if ((userinput=="goff")||(userinput=="gof")) { | ||
619 | if (graphmode==1) { | ||
620 | disable_graphmode=1; | ||
621 | } | ||
622 | continue; | ||
623 | } | ||
624 | if (userinput=="wo") { | ||
625 | writeoffset=0; | ||
626 | cout << "Writeoffset cleared." << endl; | ||
627 | nodump=1; // inhibit viewing the sector after this command. | ||
628 | continue; | ||
629 | } | ||
630 | if (userinput.substr(0,2)=="wo") { | ||
631 | writeoffset=Convert::hex2long(userinput.substr(2,userinput.length()-2)); | ||
632 | string* convwrite=Convert::int32tohex(writeoffset); | ||
633 | cout << "Writeoffset set to " << *convwrite << " sectors." << endl; | ||
634 | delete convwrite; convwrite=NULL; | ||
635 | nodump=1; // inhibit viewing the sector after this command. | ||
636 | continue; | ||
637 | } | ||
638 | if (userinput.substr(0,1)=="+") { | ||
639 | long sectoadd=Convert::hex2long(userinput.substr(1,userinput.length()-1)); | ||
640 | sectornum+=sectoadd; | ||
641 | continue; | ||
642 | } | ||
643 | if (userinput=="-") { | ||
644 | if (sectornum>0) | ||
645 | { | ||
646 | sectornum--; | ||
647 | } else { | ||
648 | sectornum=0; | ||
649 | } | ||
650 | continue; | ||
651 | } | ||
652 | if (userinput.substr(0,1)=="-") { | ||
653 | long sectoadd=Convert::hex2long(userinput.substr(1,userinput.length()-1)); | ||
654 | if ((__uint32)sectoadd>(__uint32)sectornum) | ||
655 | { | ||
656 | sectornum=0; | ||
657 | } else { | ||
658 | sectornum-=sectoadd; | ||
659 | } | ||
660 | continue; | ||
661 | } | ||
662 | if (userinput==".") { | ||
663 | noread=1; | ||
664 | continue; | ||
665 | } | ||
666 | if ((userinput.substr(0,1)=="?")||(userinput=="help")) { | ||
667 | cout << "Help for hd24hexview " << VERSION << endl; | ||
668 | cout << "==============================" << endl; | ||
669 | cout << "General:" <<endl; | ||
670 | cout << " q quit" << endl; | ||
671 | cout << " ? shows this help" << endl; | ||
672 | cout << endl; | ||
673 | cout << "Navigation:" << endl; | ||
674 | cout << " + dump next sector" << endl; | ||
675 | cout << " +<n> increment n sectors, then dump sector"<<endl; | ||
676 | cout << " - dump prev sector" << endl; | ||
677 | cout << " -<n> decrement n sectors, then dump sector"<<endl; | ||
678 | cout << " . re-display current sector" << endl; | ||
679 | cout << " d<hex> dump sector <hex>" << endl; | ||
680 | cout << " d-<hex> dump sector totalnumberofsectors-<hex>" << endl; | ||
681 | cout << " d re-read current sector from disk" << endl; | ||
682 | cout << " m<from>l<hexlen> <to>" << endl; | ||
683 | cout << " move <hexlen> bytes from offset <from> to <to>" << endl; | ||
684 | cout << " o<hex> dump sector that contains offset <hex>" << endl; | ||
685 | cout << " s x y.. scan marked block for byte sequence x y ..." << endl; | ||
686 | cout << " s'...' scan marked block for exact string" << endl; | ||
687 | cout << " e<p> xx edit byte sequence at pos p to xxxx " << endl; | ||
688 | cout << " e<p> 'x' edit pos p to string 'x'" << endl; | ||
689 | cout << endl; | ||
690 | cout << "Block commands:" << endl; | ||
691 | cout << " bb mark start of sector as block beginning" << endl; | ||
692 | cout << " be mark end of sector as block end" << endl; | ||
693 | cout << " bc block clear" << endl; | ||
694 | cout << " diff compare marked block with current" << endl; | ||
695 | cout << " p paste first sector of marked block to current sector" << endl; | ||
696 | cout << endl; | ||
697 | cout << "File commands:" << endl; | ||
698 | cout << " n<xx> set filename to xx" << endl; | ||
699 | cout << " n clear filename" << endl; | ||
700 | cout << " w write marked block to named file/device" << endl; | ||
701 | cout << " wo clear sector write offset for file/device write" << endl; | ||
702 | cout << " wo<xx> set write offset to xx sectors" << endl; | ||
703 | cout << " ws write back current edited sector to disk" << endl; | ||
704 | cout << "HD24 specific features:" << endl; | ||
705 | cout << " fix reverse byte ordering of 32 bit words" << endl; | ||
706 | cout << " for better human readability" << endl; | ||
707 | cout << " cs Calc checksum of selected block" << endl; | ||
708 | cout << " scs Set zero checksum of selected block" << endl; | ||
709 | |||
710 | nodump=1; // inhibit viewing the sector after this command. | ||
711 | continue; | ||
712 | } | ||
713 | if (userinput.substr(0,2)=="bc") { | ||
714 | blockstart=0; | ||
715 | blockend=0; | ||
716 | cout << "Block selection cleared." << endl; | ||
717 | nodump=1; // inhibit viewing the sector after this command. | ||
718 | continue; | ||
719 | } | ||
720 | if (userinput.substr(0,2)=="bb") { | ||
721 | cout << "Block start set." << endl; | ||
722 | nodump=1; // inhibit viewing the sector after this command. | ||
723 | blockstart=sectornum; | ||
724 | continue; | ||
725 | } | ||
726 | if (userinput.substr(0,2)=="be") { | ||
727 | cout << "Block end set." << endl; | ||
728 | /* dump is startsector..endsector, | ||
729 | * excl. end sector. number of bytes to dump= | ||
730 | * (blockend-blockstart)*512 | ||
731 | */ | ||
732 | nodump=1; // inhibit viewing the sector after this command. | ||
733 | blockend=sectornum+1; | ||
734 | continue; | ||
735 | } | ||
736 | if (userinput.substr(0,2)=="cs") { | ||
737 | checksum=calcblockchecksum(rawdevice,blockstart,blockend); | ||
738 | cout << "Block checksum is " << checksum << endl; | ||
739 | nodump=1; | ||
740 | noread=1; | ||
741 | continue; | ||
742 | } | ||
743 | if (userinput.substr(0,3)=="scs") { | ||
744 | if (blockend-1!=sectornum) { | ||
745 | cout << "Current sector must be block end." << endl; | ||
746 | nodump=1; | ||
747 | noread=1; | ||
748 | continue; | ||
749 | } | ||
750 | unsigned long checksum=calcblockchecksum(rawdevice,blockstart,blockend); | ||
751 | unsigned long oldchecksum=0; | ||
752 | oldchecksum+=((unsigned char)(bootblock[511])); oldchecksum=oldchecksum <<8; | ||
753 | oldchecksum+=((unsigned char)(bootblock[510])); oldchecksum=oldchecksum <<8; | ||
754 | oldchecksum+=((unsigned char)(bootblock[509])); oldchecksum=oldchecksum <<8; | ||
755 | oldchecksum+=((unsigned char)(bootblock[508])); | ||
756 | oldchecksum-=checksum; | ||
757 | bootblock[508]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
758 | bootblock[509]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
759 | bootblock[510]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
760 | bootblock[511]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
761 | |||
762 | noread=1; | ||
763 | continue; | ||
764 | } | ||
765 | if (userinput.substr(0,4)=="diff") { | ||
766 | nodump=1; // inhibit viewing the sector after this command. | ||
767 | if (blockend==blockstart) { | ||
768 | cout << "Please set block start/end first." << endl; | ||
769 | continue; | ||
770 | } | ||
771 | compareblock(rawdevice,blockstart,blockend,sectornum); | ||
772 | continue; | ||
773 | } | ||
774 | if (userinput.substr(0,1)=="s") { | ||
775 | if (userinput=="s") { | ||
776 | userinput+=lastsearch; | ||
777 | } else { | ||
778 | lastsearch=userinput.substr(1,userinput.length()-1); | ||
779 | } | ||
780 | if (blockend==blockstart) { | ||
781 | sectornum=scanforblock(rawdevice,lastsearch,0,0xffffffff,sectornum); | ||
782 | } else { | ||
783 | sectornum=scanforblock(rawdevice,lastsearch,blockstart,blockend,sectornum); | ||
784 | } | ||
785 | continue; | ||
786 | } | ||
787 | if (userinput=="version") { | ||
788 | cout << VERSION << endl; | ||
789 | nodump=1; // inhibit viewing the sector after this command. | ||
790 | noread=1; | ||
791 | continue; | ||
792 | } | ||
793 | if (userinput.substr(0,1)=="p") { | ||
794 | //paste | ||
795 | if (blockend==blockstart) { | ||
796 | nodump=1; | ||
797 | cout << "Mark a block first." << endl; | ||
798 | continue; | ||
799 | } | ||
800 | rawdevice->readsectors(blockstart,bootblock,1); | ||
801 | noread=1; | ||
802 | continue; | ||
803 | } | ||
804 | if (userinput.substr(0,1)=="e") { | ||
805 | string editstr=userinput.substr(1,userinput.length()-1); | ||
806 | editbytes(bootblock,editstr); | ||
807 | noread=1; | ||
808 | continue; | ||
809 | } | ||
810 | if (userinput.substr(0,1)=="m") { | ||
811 | string editstr=userinput.substr(1,userinput.length()-1); | ||
812 | movebytes(bootblock,editstr); | ||
813 | noread=1; | ||
814 | continue; | ||
815 | } | ||
816 | if (userinput=="d") { | ||
817 | continue; | ||
818 | } | ||
819 | |||
820 | if (userinput.substr(0,2)=="d-") { | ||
821 | // if we have 10 sectors (0..9), last one is d-1=sector 9 | ||
822 | // so sector num is total number of secs - negnum | ||
823 | sectornum=rawdevice->getlastsectornum()-Convert::hex2long(userinput.substr(2,userinput.length()-2))+1; | ||
824 | continue; | ||
825 | } | ||
826 | |||
827 | if (userinput.substr(0,1)=="d") { | ||
828 | sectornum=Convert::hex2long(userinput.substr(1,userinput.length()-1)); | ||
829 | continue; | ||
830 | } | ||
831 | if (userinput.substr(0,1)=="o") { | ||
832 | long offset=Convert::hex2long(userinput.substr(1,userinput.length()-1)); | ||
833 | offset-=(offset%512); | ||
834 | sectornum=offset/512; | ||
835 | } | ||
836 | if (userinput=="fix") { | ||
837 | fstfix(bootblock,512); | ||
838 | noread=1; | ||
839 | continue; | ||
840 | } | ||
841 | if (userinput.substr(0,1)=="n") { | ||
842 | int dangerousname=0; | ||
843 | if (userinput.substr(1,4)=="\\\\.\\") { | ||
844 | dangerousname=1; | ||
845 | } | ||
846 | if (userinput.substr(1,5)=="/dev/") { | ||
847 | dangerousname=1; | ||
848 | } | ||
849 | if (userinput.substr(1,4)=="//./") { | ||
850 | dangerousname=1; | ||
851 | } | ||
852 | if (dangerousname==1) { | ||
853 | if (expertmode==0) { | ||
854 | expertmodemessage("Writing to devices"); | ||
855 | } else { | ||
856 | filename=userinput.substr(1,userinput.length()-1); | ||
857 | cout << "OK, setting output file to device " << filename << endl; | ||
858 | cout << "Please take your time to make sure this is really the correct drive."<<endl; | ||
859 | string strlower=filename; | ||
860 | int (*pf)(int)=tolower; | ||
861 | std::transform (strlower.begin(),strlower.end(),strlower.begin(),pf); | ||
862 | if ( | ||
863 | (strlower=="\\\\.\\physicaldrive0") | ||
864 | || (strlower=="/dev/hda")) | ||
865 | { | ||
866 | cout << "CAREFUL!!! " << strlower << " is probably your main system disk!" << endl; | ||
867 | cout << "If you continue you might mess up your computer!!!" << endl; | ||
868 | cout << "I will not stop you from doing this, so " << endl; | ||
869 | cout << "MAKE SURE THIS IS REALLY THE DRIVE YOU WANT TO WRITE TO!" << endl; | ||
870 | cout << "UNLESS ABSOLUTELY SURE, STOP WHAT YOU ARE DOING RIGHT NOW!" << endl; | ||
871 | } | ||
872 | } | ||
873 | } else { | ||
874 | filename=userinput.substr(1,userinput.length()-1); | ||
875 | } | ||
876 | nodump=1; // inhibit viewing the sector after this command. | ||
877 | if (filename=="") { | ||
878 | string filename="outfile.dmp"; | ||
879 | } | ||
880 | cout << "Current output filename is " << filename << endl; | ||
881 | |||
882 | continue; | ||
883 | } | ||
884 | if (userinput=="w") { | ||
885 | cout << "Writing " << blockend-blockstart << " sectors to " << filename << endl; | ||
886 | writetofile(rawdevice,filename,blockstart,blockend); | ||
887 | nodump=1; // inhibit viewing the sector after this command. | ||
888 | cout << "Done." << endl; | ||
889 | continue; | ||
890 | } | ||
891 | if (userinput=="ws") { | ||
892 | if (expertmode==1) { | ||
893 | writesec=1; | ||
894 | } else { | ||
895 | noread=1; | ||
896 | expertmodemessage("Writing sectors"); | ||
897 | nodump=1; | ||
898 | } | ||
899 | } | ||
900 | if (userinput=="freesec") { | ||
901 | nodump=1; | ||
902 | cout << "Sector " << *Convert::int32tohex((long)rawdevice->getnextfreesector(0xFFFFFFFF)) << endl; | ||
903 | cout << rawdevice->getnextfreesector(0xFFFFFFFF) << endl; | ||
904 | } | ||
905 | if (userinput=="commit") { | ||
906 | if (expertmode==1) { | ||
907 | cout << "Commit FS to disk." << endl; | ||
908 | fsys->commit(); | ||
909 | } | ||
910 | } | ||
911 | } while (userinput!="q"); | ||
912 | |||
913 | } catch (string e) { | ||
914 | cout << "Exiting because of an unexpected error." << endl; | ||
915 | delete rawdevice; rawdevice=NULL; | ||
916 | delete fsys; fsys=NULL; | ||
917 | return 1; | ||
918 | } | ||
919 | delete rawdevice; rawdevice=NULL; | ||
920 | delete fsys; fsys=NULL; | ||
921 | return 0; | ||
922 | } | ||
923 | |||
diff --git a/src/hd24info.cpp b/src/hd24info.cpp new file mode 100755 index 0000000..bcc834b --- /dev/null +++ b/src/hd24info.cpp | |||
@@ -0,0 +1,111 @@ | |||
1 | #include <iostream> | ||
2 | #include <string> | ||
3 | #include <convertlib.h> | ||
4 | #include <hd24fs.h> | ||
5 | |||
6 | using namespace std; | ||
7 | |||
8 | void showsongs(hd24project* currentproj) | ||
9 | { | ||
10 | int numsongs = currentproj->songcount(); | ||
11 | |||
12 | cout << "======================================================================" << endl; | ||
13 | |||
14 | if (numsongs == 0) | ||
15 | { | ||
16 | cout << " There are no songs in this project." << endl; | ||
17 | } | ||
18 | |||
19 | for (int i = 1; i <= numsongs; i++) | ||
20 | { | ||
21 | hd24song currsong = *(currentproj->getsong(i)); | ||
22 | string* songname1 = new string(""); | ||
23 | cout << " "; | ||
24 | |||
25 | if (i < 10) | ||
26 | { | ||
27 | cout << " "; | ||
28 | } | ||
29 | |||
30 | cout << i << ": "; | ||
31 | |||
32 | string* currsname = currsong.songname(); | ||
33 | *songname1 += *currsname; | ||
34 | |||
35 | cout << *(Convert::padright(*songname1, 20, " ")); | ||
36 | cout << *(currsong.display_duration()) << ", "; | ||
37 | |||
38 | string* chans = Convert::int2str(currsong.logical_channels()); | ||
39 | chans = Convert::padleft(*chans,2," "); | ||
40 | |||
41 | cout << *chans << "ch. " << currsong.samplerate() << " Hz "; | ||
42 | |||
43 | delete(currsname); | ||
44 | delete(songname1); | ||
45 | |||
46 | cout << endl; | ||
47 | } | ||
48 | } | ||
49 | |||
50 | void showprojects(hd24fs* currenthd24) | ||
51 | { | ||
52 | int numprojs = currenthd24->projectcount(); | ||
53 | |||
54 | for (int i = 1; i <= numprojs; i++) | ||
55 | { | ||
56 | hd24project currproj = *(currenthd24->getproject(i)); | ||
57 | string* projname1 = new string(""); | ||
58 | string* currpname = currproj.projectname(); | ||
59 | *projname1 += *currpname; | ||
60 | |||
61 | cout << "======================================================================" << endl << "Project " << i << ": "; | ||
62 | cout << *projname1 << endl; | ||
63 | |||
64 | showsongs (&currproj); | ||
65 | |||
66 | delete(currpname); | ||
67 | delete(projname1); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | int main() | ||
72 | { | ||
73 | hd24fs* fsysp=new hd24fs((const char*)NULL); | ||
74 | hd24fs fsys=*fsysp; | ||
75 | string* volname; | ||
76 | |||
77 | if (!fsys.isOpen()) | ||
78 | { | ||
79 | cout << "Cannot open hd24 device." << endl; | ||
80 | return 1; | ||
81 | } | ||
82 | |||
83 | int devcount = fsys.hd24devicecount(); | ||
84 | |||
85 | if (devcount > 1) | ||
86 | { | ||
87 | cout << "Number of hd24 devices found: " << fsys.hd24devicecount() << endl; | ||
88 | } | ||
89 | |||
90 | for (int i = 0; i < devcount; i++) | ||
91 | { | ||
92 | hd24fs* currhd24 = new hd24fs((const char*)NULL,fsys.mode(), i); | ||
93 | |||
94 | if (devcount > 1) | ||
95 | { | ||
96 | cout << "Showing info for device #" << i << endl; | ||
97 | } | ||
98 | |||
99 | volname = currhd24->volumename(); | ||
100 | string vname = ""; | ||
101 | vname += *volname; | ||
102 | cout << "Volume name : " << vname<<endl; | ||
103 | delete volname; | ||
104 | |||
105 | cout << "Number of projects : " << currhd24->projectcount() << endl; | ||
106 | showprojects(currhd24); | ||
107 | delete currhd24; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
diff --git a/src/hd24syx2bin.cpp b/src/hd24syx2bin.cpp new file mode 100644 index 0000000..1ccc501 --- /dev/null +++ b/src/hd24syx2bin.cpp | |||
@@ -0,0 +1,113 @@ | |||
1 | //syx2bin.cpp | ||
2 | //converts an alesis hd24 .syx OS file to binary | ||
3 | using namespace std; | ||
4 | #include <iostream> | ||
5 | #define SKIPCHARS 9 | ||
6 | |||
7 | int main(int argc, char *argv[]) | ||
8 | { | ||
9 | |||
10 | FILE *pInfile; | ||
11 | FILE *pOutfile; | ||
12 | char *pInfilename, *pOutfilename; | ||
13 | int loop; | ||
14 | int msbits; | ||
15 | |||
16 | if(argc < 3) | ||
17 | { | ||
18 | fprintf(stderr, "Usage : %s infile outfile\n",argv[0]); | ||
19 | exit(1); | ||
20 | } | ||
21 | |||
22 | pInfilename = argv[1]; | ||
23 | pOutfilename = argv[2]; | ||
24 | |||
25 | pInfile = fopen(pInfilename, "rb"); | ||
26 | if(!pInfile) | ||
27 | { | ||
28 | fprintf(stderr, "ERROR : couldn't open %s for reading\n", pInfilename); | ||
29 | exit(1); | ||
30 | } | ||
31 | pOutfile = fopen(pOutfilename, "wb"); | ||
32 | if(!pOutfile) | ||
33 | { | ||
34 | fprintf(stderr, "ERROR : couldn't open %s for writing\n", pOutfilename); | ||
35 | fclose(pInfile); //close open infile | ||
36 | exit(1); | ||
37 | } | ||
38 | |||
39 | //skip F0 and 5 byte header | ||
40 | for(loop = 0; loop < SKIPCHARS; loop++) | ||
41 | { | ||
42 | fgetc(pInfile); | ||
43 | } | ||
44 | |||
45 | // msbits = fgetc(pInfile); | ||
46 | unsigned char b[8]; | ||
47 | unsigned char header[64]; | ||
48 | int whichbyte=3; | ||
49 | int headerbyte=0; | ||
50 | unsigned int checksum=0; | ||
51 | int filesize=0; | ||
52 | int written=0; | ||
53 | while((msbits != EOF) && (msbits != 0xF7)) //get most significant bits byte | ||
54 | { | ||
55 | int i; | ||
56 | int j; | ||
57 | j=10; | ||
58 | |||
59 | for (i=0;i<8;i++) { | ||
60 | b[i]=fgetc(pInfile); | ||
61 | if (b[i]==0xF7) { | ||
62 | msbits=0xF7; | ||
63 | j=i; | ||
64 | } | ||
65 | } | ||
66 | // convert 8->7 bytes | ||
67 | unsigned char bits=b[0]; | ||
68 | int max=8; | ||
69 | if (j<max) { max=j; } | ||
70 | for (i=1;i<max;i++) { | ||
71 | #ifdef LSB | ||
72 | int onebit=(bits & 1) <<7; | ||
73 | b[i]|=onebit; | ||
74 | bits = (bits>>1); | ||
75 | #else | ||
76 | int onebit=(bits << 1) & 0x80; | ||
77 | b[i]|=onebit; | ||
78 | bits = (bits << 1); | ||
79 | #endif | ||
80 | fputc((unsigned char) b[i], pOutfile); | ||
81 | written++; | ||
82 | if (headerbyte<64) { | ||
83 | header[headerbyte]=b[i]; | ||
84 | headerbyte++; | ||
85 | } | ||
86 | else | ||
87 | { | ||
88 | if (filesize==0) { | ||
89 | int x1=(int)((unsigned char)header[47]); | ||
90 | int x2=(int)((unsigned char)header[46]); | ||
91 | int x3=(int)((unsigned char)header[45]); | ||
92 | int x4=(int)((unsigned char)header[44]); | ||
93 | filesize=x1+(256*x2)+(256*256*x3)+(256*256*256*x4); | ||
94 | } | ||
95 | } | ||
96 | whichbyte=(whichbyte+1)%4; | ||
97 | checksum=(checksum+b[i] ) % 256; | ||
98 | //((unsigned char)(b[i]) << (8*(whichbyte))) ; | ||
99 | if (filesize!=0) { | ||
100 | if (written>=filesize) break; | ||
101 | } | ||
102 | } | ||
103 | if (filesize!=0) { | ||
104 | if (written>=filesize) break; | ||
105 | } | ||
106 | |||
107 | } | ||
108 | printf("Checksum=%x\n",checksum); | ||
109 | fclose(pInfile); | ||
110 | fclose(pOutfile); | ||
111 | return 0; | ||
112 | } | ||
113 | |||
diff --git a/src/hd24towav.cpp b/src/hd24towav.cpp new file mode 100755 index 0000000..7d654ef --- /dev/null +++ b/src/hd24towav.cpp | |||
@@ -0,0 +1,233 @@ | |||
1 | #ifdef WINDOWS | ||
2 | namespace std {} | ||
3 | #endif | ||
4 | using namespace std; | ||
5 | #include <string> | ||
6 | #include <iostream> | ||
7 | #include "convertlib.h" | ||
8 | /* | ||
9 | ** Copyright (C) 2001-2005 Erik de Castro Lopo <erikd@mega-nerd.com> | ||
10 | ** | ||
11 | ** This program is free software; you can redistribute it and/or modify | ||
12 | ** it under the terms of the GNU General Public License as published by | ||
13 | ** the Free Software Foundation; either version 2 of the License, or | ||
14 | ** (at your option) any later version. | ||
15 | ** | ||
16 | ** This program is distributed in the hope that it will be useful, | ||
17 | ** but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | ** GNU General Public License for more details. | ||
20 | ** | ||
21 | ** You should have received a copy of the GNU General Public License | ||
22 | ** along with this program; if not, write to the Free Software | ||
23 | ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
24 | */ | ||
25 | |||
26 | #include <stdio.h> | ||
27 | |||
28 | /* Include this header file to use functions from libsndfile. */ | ||
29 | #include <sndfile.h> | ||
30 | |||
31 | /* This will be the length of the buffer used to hold.frames while | ||
32 | ** we process them. | ||
33 | */ | ||
34 | #define BUFFER_LEN 1024 | ||
35 | |||
36 | /* libsndfile can handle more than 6 channels but we'll restrict it to 6. */ | ||
37 | #define MAX_CHANNELS 6 | ||
38 | string inputfilename; | ||
39 | string outputfilename; | ||
40 | string format; | ||
41 | long rate; | ||
42 | long bits; | ||
43 | int convertfile(string inputfilename) { | ||
44 | /* This is a buffer of double precision floating point values | ||
45 | * which will hold our data while we process it. | ||
46 | */ | ||
47 | format="wav"; | ||
48 | cout << "Converting " << inputfilename << endl; | ||
49 | if (rate==0) { | ||
50 | if ( | ||
51 | (inputfilename.find("44k1",0) != string::npos) | ||
52 | ||(inputfilename.find("44K1",0) != string::npos) | ||
53 | ||(inputfilename.find("44100",0) != string::npos) | ||
54 | ) { | ||
55 | rate=44100; | ||
56 | } | ||
57 | if ( | ||
58 | (inputfilename.find("48k",0) != string::npos) | ||
59 | ||(inputfilename.find("48K",0) != string::npos) | ||
60 | ||(inputfilename.find("48000",0) != string::npos) | ||
61 | ) { | ||
62 | rate=48000; | ||
63 | } | ||
64 | if ( | ||
65 | (inputfilename.find("88k2",0) != string::npos) | ||
66 | ||(inputfilename.find("88K2",0) != string::npos) | ||
67 | ||(inputfilename.find("88200",0) != string::npos) | ||
68 | ) { | ||
69 | rate=88200; | ||
70 | } | ||
71 | if ( | ||
72 | (inputfilename.find("96k",0) != string::npos) | ||
73 | ||(inputfilename.find("96K",0) != string::npos) | ||
74 | ||(inputfilename.find("96000",0) != string::npos) | ||
75 | ) { | ||
76 | rate=96000; | ||
77 | } | ||
78 | } | ||
79 | bits=24; | ||
80 | static int data [BUFFER_LEN] ; | ||
81 | |||
82 | /* A SNDFILE is very much like a FILE in the Standard C library. The | ||
83 | ** sf_open function return an SNDFILE* pointer when they sucessfully | ||
84 | ** open the specified file. | ||
85 | */ | ||
86 | SNDFILE *infile, *outfile ; | ||
87 | |||
88 | /* A pointer to an SF_INFO stutct is passed to sf_open. | ||
89 | ** On read, the library fills this struct with information about the file. | ||
90 | ** On write, the struct must be filled in before calling sf_open. | ||
91 | */ | ||
92 | SF_INFO sfinfoin ; | ||
93 | SF_INFO sfinfoout; | ||
94 | int readcount ; | ||
95 | if (inputfilename=="") { | ||
96 | cout << "Must specify --input filename" << endl; | ||
97 | return 1; | ||
98 | } | ||
99 | if (outputfilename=="") { | ||
100 | outputfilename=inputfilename; | ||
101 | string ext=""; | ||
102 | if (format=="wav") { | ||
103 | ext=".wav"; | ||
104 | } | ||
105 | if (outputfilename.substr(outputfilename.length()-4,4)==".raw") { | ||
106 | outputfilename=outputfilename.substr(0,outputfilename.length()-4)+ext; | ||
107 | } | ||
108 | if (outputfilename=="") { | ||
109 | cout << "Must specify --output filename" << endl; | ||
110 | return 1; | ||
111 | } | ||
112 | } | ||
113 | const char *infilename = inputfilename.c_str(); | ||
114 | const char *outfilename = outputfilename.c_str(); | ||
115 | |||
116 | /* Here's where we open the input file. We pass sf_open the file name and | ||
117 | ** a pointer to an SF_INFO struct. | ||
118 | ** On successful open, sf_open returns a SNDFILE* pointer which is used | ||
119 | ** for all subsequent operations on that file. | ||
120 | ** If an error occurs during sf_open, the function returns a NULL pointer. | ||
121 | ** | ||
122 | ** If you are trying to open a raw headerless file you will need to set the | ||
123 | ** format and channels fields of sfinfo before calling sf_open(). For | ||
124 | ** instance to open a raw 16 bit stereo PCM file you would need the following | ||
125 | ** two lines: | ||
126 | ** | ||
127 | ** sfinfo.format = SF_FORMAT_RAW | SF_FORMAT_PCM_16 ; | ||
128 | ** sfinfo.channels = 2 ; | ||
129 | */ | ||
130 | sfinfoin.format = SF_FORMAT_RAW | SF_FORMAT_PCM_24|SF_ENDIAN_BIG ; | ||
131 | sfinfoin.channels = 1 ; | ||
132 | |||
133 | if (format=="wav") { | ||
134 | sfinfoout.format = SF_FORMAT_WAV ; | ||
135 | } | ||
136 | if (bits==16) { | ||
137 | sfinfoout.format|=SF_FORMAT_PCM_16; | ||
138 | } | ||
139 | if (bits==24) { | ||
140 | sfinfoout.format|=SF_FORMAT_PCM_24; | ||
141 | } | ||
142 | |||
143 | sfinfoout.samplerate=rate; | ||
144 | sfinfoout.channels = 1 ; | ||
145 | if (! (infile = sf_open (infilename, SFM_READ, &sfinfoin))) | ||
146 | { /* Open failed so print an error message. */ | ||
147 | printf ("Not able to open input file %s.\n", infilename) ; | ||
148 | /* Print the error message from libsndfile. */ | ||
149 | puts (sf_strerror (NULL)) ; | ||
150 | return 1 ; | ||
151 | } ; | ||
152 | |||
153 | /* Open the output file. */ | ||
154 | if (! (outfile = sf_open (outfilename, SFM_WRITE, &sfinfoout))) | ||
155 | { printf ("Not able to open output file %s.\n", outfilename) ; | ||
156 | puts (sf_strerror (NULL)) ; | ||
157 | return 1 ; | ||
158 | } ; | ||
159 | |||
160 | /* While there are.frames in the input file, read them, process | ||
161 | ** them and write them to the output file. | ||
162 | */ | ||
163 | while ((readcount = sf_read_int (infile, data, BUFFER_LEN))) | ||
164 | { | ||
165 | sf_write_int (outfile, data, readcount) ; | ||
166 | } ; | ||
167 | |||
168 | /* Close input and output files. */ | ||
169 | sf_close (infile) ; | ||
170 | sf_close (outfile) ; | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | int parsecommandline(int argc, char **argv) | ||
175 | { | ||
176 | int invalid = 0; | ||
177 | |||
178 | for (int c = 1; c < argc; c++) { | ||
179 | string arg = argv[c]; | ||
180 | |||
181 | if (arg.substr(0, 1) != "-") { | ||
182 | inputfilename = arg; | ||
183 | outputfilename = ""; | ||
184 | convertfile(inputfilename); | ||
185 | continue; | ||
186 | } | ||
187 | |||
188 | if (arg.substr(0,strlen("--input=")) == "--input=") { | ||
189 | inputfilename = arg.substr(strlen("--input=")); | ||
190 | continue; | ||
191 | } | ||
192 | |||
193 | if (arg.substr(0,strlen("--output=")) == "--output=") { | ||
194 | outputfilename = arg.substr(strlen("--output=")); | ||
195 | continue; | ||
196 | } | ||
197 | |||
198 | if (arg.substr(0,strlen("--rate=")) == "--rate=") { | ||
199 | rate = Convert::str2long(arg.substr(strlen("--rate="))); | ||
200 | continue; | ||
201 | } | ||
202 | |||
203 | if (arg.substr(0,strlen("--bits=")) == "--bits=") { | ||
204 | bits = Convert::str2long(arg.substr(strlen("--bits="))); | ||
205 | continue; | ||
206 | } | ||
207 | |||
208 | cout << "Invalid argument: " << arg << endl; | ||
209 | invalid = 1; | ||
210 | } | ||
211 | return invalid; | ||
212 | } | ||
213 | |||
214 | int main (int argc, char **argv) | ||
215 | { | ||
216 | rate = 0; | ||
217 | int invalid = parsecommandline(argc, argv); | ||
218 | |||
219 | if (invalid!=0) { | ||
220 | return invalid; | ||
221 | } | ||
222 | |||
223 | return 0 ; | ||
224 | } /* main */ | ||
225 | |||
226 | |||
227 | /* | ||
228 | ** Do not edit or modify anything in this comment block. | ||
229 | ** The arch-tag line is a file identity tag for the GNU Arch | ||
230 | ** revision control system. | ||
231 | ** | ||
232 | ** arch-tag: de9fdd1e-b807-41ef-9d51-075ba383e536 | ||
233 | */ | ||
diff --git a/src/hd24wavefix.cpp b/src/hd24wavefix.cpp new file mode 100755 index 0000000..c7ab2f0 --- /dev/null +++ b/src/hd24wavefix.cpp | |||
@@ -0,0 +1,207 @@ | |||
1 | #include "config.h" | ||
2 | #include <iostream> | ||
3 | #include <algorithm> | ||
4 | #include <cctype> | ||
5 | #include <string> | ||
6 | #include "hd24fs.h" | ||
7 | #include <sys/types.h> | ||
8 | #include <sys/stat.h> | ||
9 | #include <fcntl.h> | ||
10 | #ifndef WINDOWS | ||
11 | #include <unistd.h> | ||
12 | #endif | ||
13 | #include <stdio.h> | ||
14 | #include <stdlib.h> | ||
15 | #include <iostream> | ||
16 | #include "convertlib.h" | ||
17 | #define HEADERSIZE 44 | ||
18 | #define SAMPLES_IN_HALF_BUF 1024*1024 | ||
19 | #define SAMPLES_IN_FULL_BUF 2*SAMPLES_IN_HALF_BUF | ||
20 | #define BYTES_PER_SAM 3 | ||
21 | #define BYTES_IN_HALF_BUF BYTES_PER_SAM*SAMPLES_IN_HALF_BUF | ||
22 | #define BYTES_IN_FULL_BUF BYTES_PER_SAM*SAMPLES_IN_FULL_BUF | ||
23 | char audiobuf[BYTES_IN_FULL_BUF]; | ||
24 | char fixbuf[BYTES_IN_HALF_BUF]; | ||
25 | string inputfile; | ||
26 | string outputfile; | ||
27 | int simple=0; | ||
28 | FILE* infile; | ||
29 | FILE* outfile; | ||
30 | __uint64 writeoffset; | ||
31 | |||
32 | void clearaudiobuf() | ||
33 | { | ||
34 | int i; | ||
35 | for (i=0;i<BYTES_IN_FULL_BUF;i++) { | ||
36 | audiobuf[i]=0; | ||
37 | } | ||
38 | } | ||
39 | void shiftaudiobuf() | ||
40 | { | ||
41 | int i; | ||
42 | for (i=0;i<BYTES_IN_HALF_BUF;i++) { | ||
43 | audiobuf[i]=audiobuf[i+BYTES_IN_HALF_BUF]; | ||
44 | audiobuf[i+BYTES_IN_HALF_BUF]=0; | ||
45 | } | ||
46 | } | ||
47 | int getsam(int samnum) | ||
48 | { | ||
49 | int samval=audiobuf[samnum+BYTES_IN_HALF_BUF] | ||
50 | +(audiobuf[samnum+BYTES_IN_HALF_BUF]*256) | ||
51 | +(audiobuf[samnum+BYTES_IN_HALF_BUF]*256*256); | ||
52 | return samval; | ||
53 | } | ||
54 | int tosigned(int samval) { | ||
55 | if (samval>=(1<<23)) { | ||
56 | samval-=(1<<24); | ||
57 | } | ||
58 | return samval; | ||
59 | } | ||
60 | int topos(int samval) { | ||
61 | return samval+(1<<23); | ||
62 | } | ||
63 | bool fileexists (string* fname) { | ||
64 | struct stat fi; | ||
65 | if ((stat (fname->c_str(), &fi) != -1) && ((fi.st_mode & S_IFDIR) == 0)) { | ||
66 | return true; | ||
67 | } | ||
68 | return false; | ||
69 | } | ||
70 | void hd24seek(FSHANDLE devhd24,__uint64 seekpos) | ||
71 | { | ||
72 | #if defined(LINUX) || defined(DARWIN) | ||
73 | lseek(devhd24,seekpos,0); | ||
74 | // lseek64(devhd24,seekpos,0); | ||
75 | #endif | ||
76 | #ifdef WINDOWS | ||
77 | LARGE_INTEGER li; | ||
78 | li.HighPart=seekpos>>32; | ||
79 | li.LowPart=seekpos%((__uint64)1<<32); | ||
80 | SetFilePointerEx(devhd24,li,NULL,FILE_BEGIN); | ||
81 | #endif | ||
82 | return; | ||
83 | } | ||
84 | |||
85 | int parsecommandline(int argc, char ** argv) | ||
86 | { | ||
87 | int invalid=0; | ||
88 | inputfile=""; | ||
89 | outputfile=""; | ||
90 | for (int c=1;c<argc;c++) { | ||
91 | string arg=argv[c]; | ||
92 | if (arg.substr(0,strlen("--input="))=="--input=") { | ||
93 | inputfile=arg.substr(strlen("--input=")); | ||
94 | continue; | ||
95 | } | ||
96 | if (arg.substr(0,strlen("--output="))=="--output=") { | ||
97 | outputfile=arg.substr(strlen("--output=")); | ||
98 | continue; | ||
99 | } | ||
100 | if (arg.substr(0,strlen("--simple"))=="--simple") { | ||
101 | simple=1; | ||
102 | continue; | ||
103 | } | ||
104 | cout << "Invalid argument: " << arg << endl; | ||
105 | invalid=1; | ||
106 | } | ||
107 | return invalid; | ||
108 | } | ||
109 | void findmask(FILE* infile) | ||
110 | { | ||
111 | fseek(infile,HEADERSIZE,SEEK_SET); | ||
112 | return; | ||
113 | } | ||
114 | void copyheader(FILE* infile,FILE* outfile) | ||
115 | { | ||
116 | char buffer[HEADERSIZE]; | ||
117 | fseek(infile,0,SEEK_SET); | ||
118 | int readcount=fread((void*)&buffer[0],1,HEADERSIZE,infile); | ||
119 | if (readcount>0) { | ||
120 | int writecount=fwrite((const void*)&buffer[0],1,HEADERSIZE,outfile); | ||
121 | if (writecount==0) { | ||
122 | cout << "Cannot write output file" << endl; | ||
123 | } | ||
124 | } | ||
125 | return; | ||
126 | } | ||
127 | void copyaudio(FILE* infile,FILE* outfile) { | ||
128 | int readcount; | ||
129 | do { | ||
130 | shiftaudiobuf(); | ||
131 | readcount=fread((void*)&audiobuf[BYTES_IN_HALF_BUF],1,BYTES_IN_HALF_BUF,infile); | ||
132 | for (int i=0; i<SAMPLES_IN_HALF_BUF-1;i+=2) { | ||
133 | int q0=3; | ||
134 | int q1=0; | ||
135 | if (audiobuf[BYTES_IN_HALF_BUF+i*3+q0+2-6]==audiobuf[BYTES_IN_HALF_BUF+i*3+q1+2]) { | ||
136 | audiobuf[BYTES_IN_HALF_BUF+i*3+q0+2]=audiobuf[BYTES_IN_HALF_BUF+i*3+q1+2]; | ||
137 | } else { | ||
138 | audiobuf[BYTES_IN_HALF_BUF+i*3+q0+0]=audiobuf[BYTES_IN_HALF_BUF+i*3+q1+0]; | ||
139 | audiobuf[BYTES_IN_HALF_BUF+i*3+q0+1]=audiobuf[BYTES_IN_HALF_BUF+i*3+q1+1]; | ||
140 | audiobuf[BYTES_IN_HALF_BUF+i*3+q0+2]=audiobuf[BYTES_IN_HALF_BUF+i*3+q1+2]; | ||
141 | } | ||
142 | } | ||
143 | if (readcount>0) { | ||
144 | int writecount=fwrite( | ||
145 | (void*)&audiobuf[BYTES_IN_HALF_BUF],1,readcount,outfile); | ||
146 | if (writecount==0) { | ||
147 | cout << "Cannot write output file" << endl; | ||
148 | } | ||
149 | } | ||
150 | |||
151 | } | ||
152 | while (readcount>0); | ||
153 | return; | ||
154 | } | ||
155 | void simplecopyaudio(FILE* infile,FILE* outfile) | ||
156 | { | ||
157 | int readcount; | ||
158 | do { | ||
159 | readcount=fread((void*)&audiobuf[BYTES_IN_HALF_BUF],1,BYTES_IN_HALF_BUF,infile); | ||
160 | for (int i=0; i<SAMPLES_IN_HALF_BUF-1;i+=2) { | ||
161 | int q0=3; | ||
162 | int q1=0; | ||
163 | audiobuf[BYTES_IN_HALF_BUF+i*3+q0+0]=audiobuf[BYTES_IN_HALF_BUF+i*3+q1+0]; | ||
164 | audiobuf[BYTES_IN_HALF_BUF+i*3+q0+1]=audiobuf[BYTES_IN_HALF_BUF+i*3+q1+1]; | ||
165 | audiobuf[BYTES_IN_HALF_BUF+i*3+q0+2]=audiobuf[BYTES_IN_HALF_BUF+i*3+q1+2]; | ||
166 | } | ||
167 | if (readcount>0) { | ||
168 | int writecount=fwrite( | ||
169 | (void*)&audiobuf[BYTES_IN_HALF_BUF],1,readcount,outfile); | ||
170 | if (writecount==0) { | ||
171 | cout << "Cannot write output file" << endl; | ||
172 | } | ||
173 | } | ||
174 | |||
175 | } | ||
176 | while (readcount>0); | ||
177 | return; | ||
178 | } | ||
179 | void dothefix(FILE* infile, FILE* outfile) | ||
180 | { | ||
181 | copyheader(infile,outfile); | ||
182 | findmask(infile); | ||
183 | if (simple==1) { | ||
184 | simplecopyaudio(infile,outfile); | ||
185 | } else { | ||
186 | copyaudio(infile,outfile); | ||
187 | } | ||
188 | } | ||
189 | int main (int argc,char ** argv) | ||
190 | { | ||
191 | int invalid=parsecommandline(argc,argv); | ||
192 | if (invalid!=0) { | ||
193 | return invalid; | ||
194 | } | ||
195 | if ((inputfile=="")||(outputfile=="")) { | ||
196 | cout << "Usage: hd24wavefix [--simple] --input=<inputfile> --output=<outputfile>" << endl; | ||
197 | return 1; | ||
198 | } | ||
199 | clearaudiobuf(); | ||
200 | // Open files | ||
201 | infile=fopen(inputfile.c_str(),"rb"); | ||
202 | outfile=fopen(outputfile.c_str(),"wb"); | ||
203 | dothefix(infile,outfile); | ||
204 | fclose(outfile); | ||
205 | fclose(infile); | ||
206 | return 0; | ||
207 | } | ||
diff --git a/src/installer/PkgInfo.hd24connect b/src/installer/PkgInfo.hd24connect new file mode 100644 index 0000000..4907b2c --- /dev/null +++ b/src/installer/PkgInfo.hd24connect | |||
@@ -0,0 +1,2 @@ | |||
1 | APPLnone | ||
2 | |||
diff --git a/src/installer/PkgInfo.setup b/src/installer/PkgInfo.setup new file mode 100644 index 0000000..4907b2c --- /dev/null +++ b/src/installer/PkgInfo.setup | |||
@@ -0,0 +1,2 @@ | |||
1 | APPLnone | ||
2 | |||
diff --git a/src/installer/bin2c.c b/src/installer/bin2c.c new file mode 100644 index 0000000..6c81fe6 --- /dev/null +++ b/src/installer/bin2c.c | |||
@@ -0,0 +1,72 @@ | |||
1 | /* BIN2C Converts binary data to be included in C source codes */ | ||
2 | |||
3 | |||
4 | #include <stdio.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <string.h> | ||
7 | #include <sys/stat.h> | ||
8 | |||
9 | |||
10 | static void usage(void) | ||
11 | { | ||
12 | fprintf(stderr, "BIN2C Binary to C converter\n"); | ||
13 | fprintf(stderr, "usage: BIN2C <binfile> <cfile> <varname>\n"); | ||
14 | exit(0); | ||
15 | } | ||
16 | |||
17 | |||
18 | int main(int argc, char **argv) | ||
19 | { | ||
20 | FILE* binfile; | ||
21 | FILE* cfile; | ||
22 | struct stat statbuf; | ||
23 | long len; | ||
24 | int cntr; | ||
25 | unsigned char inbyte; | ||
26 | char varname[80], cfilename[80]; | ||
27 | |||
28 | if (argc == 1) | ||
29 | usage(); | ||
30 | |||
31 | if (! (binfile = fopen(argv[1], "rb"))) { | ||
32 | perror("fopen"); | ||
33 | exit(1); | ||
34 | } | ||
35 | |||
36 | stat(argv[1], &statbuf); | ||
37 | len = statbuf.st_size; | ||
38 | |||
39 | if (argc > 2) | ||
40 | strcpy(cfilename, argv[2]); | ||
41 | else | ||
42 | strcpy(cfilename,"bin2c.c"); | ||
43 | cfile = fopen(cfilename, "wt"); | ||
44 | |||
45 | cntr = 0; | ||
46 | |||
47 | if (argc > 3) | ||
48 | strcpy(varname, argv[3]); | ||
49 | else | ||
50 | strcpy(varname, "varname"); | ||
51 | |||
52 | fprintf(cfile, "unsigned char %s[%ld] = {\n", varname, len); | ||
53 | |||
54 | fread(&inbyte, 1, 1, binfile); | ||
55 | while (1) { | ||
56 | fprintf(cfile, "0X%02X", inbyte); | ||
57 | |||
58 | fread(&inbyte, 1, 1, binfile); | ||
59 | if (feof(binfile)) | ||
60 | break; | ||
61 | fprintf(cfile, ","); | ||
62 | if (++cntr > 30) { | ||
63 | fprintf(cfile, "\n"); | ||
64 | cntr = 0; | ||
65 | } | ||
66 | } | ||
67 | |||
68 | fprintf(cfile, "};\n"); | ||
69 | fclose(binfile); | ||
70 | fclose(cfile); | ||
71 | return 0; | ||
72 | } | ||
diff --git a/src/installer/hd24connect_icon.png b/src/installer/hd24connect_icon.png new file mode 100644 index 0000000..63bca94 --- /dev/null +++ b/src/installer/hd24connect_icon.png | |||
Binary files differ | |||
diff --git a/src/installer/icon.icns b/src/installer/icon.icns new file mode 100644 index 0000000..e1137cd --- /dev/null +++ b/src/installer/icon.icns | |||
Binary files differ | |||
diff --git a/src/installer/info.plist.hd24connect b/src/installer/info.plist.hd24connect new file mode 100644 index 0000000..afc8750 --- /dev/null +++ b/src/installer/info.plist.hd24connect | |||
@@ -0,0 +1,23 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> | ||
3 | <plist version="0.9"> | ||
4 | <dict> | ||
5 | <key>CFBundleIdentifier</key> | ||
6 | <string>com.hd24tools.hd24connect</string> | ||
7 | <key>CFBundleName</key> | ||
8 | <string>hd24connect</string> | ||
9 | <key>CFBundlePackageType</key> | ||
10 | <string>APPL</string> | ||
11 | <key>CFBundleVersion</key> | ||
12 | <string>59</string> | ||
13 | <key>CFBundleShortVersionString</key> | ||
14 | <string>HD24VERSION</string> | ||
15 | <key>CFBundleIconFile</key> | ||
16 | <string>icon.icns</string> | ||
17 | <key>CFBundleSignature</key> | ||
18 | <string>none</string> | ||
19 | <key>CFBundleExecutable</key> | ||
20 | <string>HD24connect</string> | ||
21 | </dict> | ||
22 | </plist> | ||
23 | |||
diff --git a/src/installer/info.plist.setup b/src/installer/info.plist.setup new file mode 100644 index 0000000..6f9d4d8 --- /dev/null +++ b/src/installer/info.plist.setup | |||
@@ -0,0 +1,23 @@ | |||
1 | <?xml version="1.0" encoding="UTF-8"?> | ||
2 | <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd"> | ||
3 | <plist version="0.9"> | ||
4 | <dict> | ||
5 | <key>CFBundleIdentifier</key> | ||
6 | <string>com.hd24tools.setup</string> | ||
7 | <key>CFBundleName</key> | ||
8 | <string>setup</string> | ||
9 | <key>CFBundlePackageType</key> | ||
10 | <string>APPL</string> | ||
11 | <key>CFBundleVersion</key> | ||
12 | <string>59</string> | ||
13 | <key>CFBundleShortVersionString</key> | ||
14 | <string>0.6</string> | ||
15 | <key>CFBundleIconFile</key> | ||
16 | <string>icon.icns</string> | ||
17 | <key>CFBundleSignature</key> | ||
18 | <string>none</string> | ||
19 | <key>CFBundleExecutable</key> | ||
20 | <string>HD24tools Setup</string> | ||
21 | </dict> | ||
22 | </plist> | ||
23 | |||
diff --git a/src/installer/setup.cpp b/src/installer/setup.cpp new file mode 100755 index 0000000..8083510 --- /dev/null +++ b/src/installer/setup.cpp | |||
@@ -0,0 +1,353 @@ | |||
1 | // This is a very rudimentary installer framework- | ||
2 | // it won't do much more than copy a few files to the proper location. | ||
3 | // Of course there are a few wizard screens which are made in fluid (FLTK), | ||
4 | // these can be altered as needed. | ||
5 | // A small portion of the actual install stuff is done in the READY screen | ||
6 | // (search for it in the code), this could still be moved out to the | ||
7 | // installer_resources.h file. | ||
8 | // At this moment, desktop shortcuts are not yet created, for more info | ||
9 | // read | ||
10 | // http://delphi.about.com/od/windowsshellapi/a/create_lnk.htm (shell links) | ||
11 | #include <FL/Fl.H> | ||
12 | #include <FL/Fl_Window.H> | ||
13 | #include <FL/Fl_Box.H> | ||
14 | #include "ui_welcome.h" | ||
15 | #include "ui_license.h" | ||
16 | #include "ui_instdir.h" | ||
17 | #include "ui_ready.h" | ||
18 | #include "setupapi.cpp" | ||
19 | #include "installer_resources.h" | ||
20 | #include <iostream> | ||
21 | #include <fstream> | ||
22 | #include <string> | ||
23 | #ifdef WINDOWS | ||
24 | #define DEFAULT_INSTDIR "C:\\HD24tools\\" | ||
25 | #include <windows.h> | ||
26 | #include <FL/x.H> | ||
27 | #define IDI_ICON1 101 | ||
28 | #endif | ||
29 | #ifndef WINDOWS | ||
30 | #define DEFAULT_INSTDIR "/usr/local/bin/HD24tools/" | ||
31 | #endif | ||
32 | #include <sys/types.h> | ||
33 | #include <sys/stat.h> | ||
34 | #include <fcntl.h> | ||
35 | #ifndef WINDOWS | ||
36 | #include <unistd.h> | ||
37 | #endif | ||
38 | |||
39 | #define ALLOW_OVERWRITE true | ||
40 | #define NO_OVERWRITE false | ||
41 | |||
42 | #ifndef S_IXGRP | ||
43 | #define S_IXGRP 0 | ||
44 | #endif | ||
45 | #ifndef S_IXOTH | ||
46 | #define S_IXOTH 0 | ||
47 | #endif | ||
48 | bool confirm(const char* question) | ||
49 | { | ||
50 | int result=fl_choice(question,"No","Yes",NULL); | ||
51 | if (result==1) { | ||
52 | return true; | ||
53 | } | ||
54 | return false; | ||
55 | } | ||
56 | |||
57 | int lastx=0; | ||
58 | int lasty=0; | ||
59 | string fullbinname=""; | ||
60 | int installer_writefile(unsigned char* filedata,long long filesize,const char* instdir,const char* filename,bool allow_overwrite) | ||
61 | { | ||
62 | string fname=instdir; | ||
63 | fname+=filename; | ||
64 | fstream binfile(fname.c_str(),ios::binary|ios::out); | ||
65 | binfile.write(reinterpret_cast<char *>(filedata),filesize); | ||
66 | binfile.close(); | ||
67 | #ifndef WINDOWS | ||
68 | chmod(fname.c_str(),S_IRWXU|S_IXGRP|S_IRGRP|S_IXOTH|S_IROTH); | ||
69 | #endif | ||
70 | return 0; | ||
71 | } | ||
72 | void installer_getsysdir(char* sysdir) | ||
73 | { | ||
74 | // on Windows: GetSystemDirectory() | ||
75 | } | ||
76 | void installer_getprogdir(char* progdir) | ||
77 | { | ||
78 | // on Windows: getProgramDirectory() | ||
79 | } | ||
80 | int main(int argc, char **argv,char *envp[]) { | ||
81 | UI_Welcome ui_welcome; | ||
82 | UI_License ui_license; | ||
83 | UI_Instdir ui_instdir; | ||
84 | char* instdir=new char[4096]; | ||
85 | instdir[0]='\0'; | ||
86 | bool done=false; | ||
87 | char* currscreen; | ||
88 | currscreen=new char[9]; | ||
89 | currscreen="welcome"; | ||
90 | #ifndef WINDOWS | ||
91 | // on non-windows systems, default to user home dir | ||
92 | // (on non windows or no home found, | ||
93 | // defaults to systemwide dir) | ||
94 | int count=0; | ||
95 | char homedir[255]; | ||
96 | homedir[0]='\0'; | ||
97 | while (envp[count] != NULL) | ||
98 | { | ||
99 | if (strncmp(envp[count],"HOME=",5)==0) | ||
100 | { | ||
101 | strncpy(&homedir[0],&envp[count][5],250); | ||
102 | } | ||
103 | ++count; | ||
104 | } | ||
105 | |||
106 | if (strlen(homedir)>0) | ||
107 | { | ||
108 | strncpy(&instdir[0],&homedir[0],128); | ||
109 | int dirlen=strlen(instdir)-1; | ||
110 | if ((instdir[dirlen]!='/') | ||
111 | &&(instdir[dirlen]!='\\')) | ||
112 | { | ||
113 | #ifdef WINDOWS | ||
114 | instdir[dirlen+1]='\\'; | ||
115 | instdir[dirlen+2]='\0'; | ||
116 | #else | ||
117 | instdir[dirlen+1]='/'; | ||
118 | instdir[dirlen+2]='\0'; | ||
119 | #endif | ||
120 | } | ||
121 | dirlen=strlen(instdir)-1; | ||
122 | strcat(instdir,"HD24tools/"); | ||
123 | } | ||
124 | #endif | ||
125 | int insterror=0; | ||
126 | int result=0; | ||
127 | UI_Ready ui_ready; | ||
128 | char* sysdir=new char[4096]; | ||
129 | installer_getsysdir(&sysdir[0]); | ||
130 | while (done==false) { | ||
131 | if (strncmp(currscreen,"done",4)==0) | ||
132 | { | ||
133 | done=true; | ||
134 | continue; | ||
135 | } | ||
136 | if (strncmp(currscreen,"welcome",7)==0) | ||
137 | { | ||
138 | Fl_Window *window = ui_welcome.make_window(&currscreen[0]); | ||
139 | #ifdef WINDOWS | ||
140 | window->icon((char *)LoadIcon(fl_display,MAKEINTRESOURCE(IDI_ICON1))); | ||
141 | #endif | ||
142 | window->position(lastx,lasty); | ||
143 | window->end(); | ||
144 | window->show(); //argc, argv); | ||
145 | Fl::run(); lastx=window->x(); lasty=window->y(); | ||
146 | |||
147 | currscreen = ui_welcome.currscreen; | ||
148 | if (strncmp(currscreen,"next",4)==0) { | ||
149 | currscreen="license\0"; | ||
150 | continue; | ||
151 | } | ||
152 | if (strncmp(currscreen,"cancel",4)==0) { | ||
153 | currscreen="done\0"; | ||
154 | continue; | ||
155 | } | ||
156 | // screen closed otherwise | ||
157 | currscreen="done\0"; | ||
158 | continue; | ||
159 | } | ||
160 | if (strncmp(currscreen,"license",7)==0) | ||
161 | { | ||
162 | Fl_Window *window = ui_license.make_window(&currscreen[0]); | ||
163 | #ifdef WINDOWS | ||
164 | window->icon((char *)LoadIcon(fl_display,MAKEINTRESOURCE(IDI_ICON1))); | ||
165 | #endif | ||
166 | window->position(lastx,lasty); | ||
167 | window->end(); | ||
168 | window->show(); //argc, argv); | ||
169 | Fl::run(); lastx=window->x(); lasty=window->y(); | ||
170 | currscreen = ui_license.currscreen; | ||
171 | if (strncmp(currscreen,"back",4)==0) { | ||
172 | currscreen="welcome\0"; | ||
173 | continue; | ||
174 | } | ||
175 | if (strncmp(currscreen,"next",4)==0) { | ||
176 | currscreen="instdir\0"; | ||
177 | continue; | ||
178 | } | ||
179 | if (strncmp(currscreen,"cancel",4)==0) { | ||
180 | currscreen="done\0"; | ||
181 | continue; | ||
182 | } | ||
183 | // screen closed otherwise | ||
184 | currscreen="done\0"; | ||
185 | continue; | ||
186 | } | ||
187 | if (strncmp(currscreen,"instdir",7)==0) | ||
188 | { | ||
189 | if (instdir[0]=='\0') | ||
190 | { | ||
191 | strncpy(&instdir[0],DEFAULT_INSTDIR,128); | ||
192 | } | ||
193 | Fl_Window *window = ui_instdir.make_window(&currscreen[0],&instdir[0]); | ||
194 | #ifdef WINDOWS | ||
195 | window->icon((char *)LoadIcon(fl_display,MAKEINTRESOURCE(IDI_ICON1))); | ||
196 | #endif | ||
197 | window->position(lastx,lasty); | ||
198 | window->end(); | ||
199 | window->show(); //argc, argv); | ||
200 | Fl::run(); lastx=window->x(); lasty=window->y(); | ||
201 | currscreen = ui_instdir.currscreen; | ||
202 | instdir = ui_instdir.instdir; | ||
203 | int dirlen=strlen(instdir)-1; | ||
204 | if ((instdir[dirlen]!='/') | ||
205 | &&(instdir[dirlen]!='\\')) | ||
206 | { | ||
207 | #ifdef WINDOWS | ||
208 | instdir[dirlen+1]='\\'; | ||
209 | instdir[dirlen+2]='\0'; | ||
210 | #else | ||
211 | instdir[dirlen+1]='/'; | ||
212 | instdir[dirlen+2]='\0'; | ||
213 | #endif | ||
214 | } | ||
215 | if (strncmp(currscreen,"cancel",6)==0) { | ||
216 | currscreen="done\0"; | ||
217 | continue; | ||
218 | } | ||
219 | if (strncmp(currscreen,"back",4)==0) { | ||
220 | currscreen="license\0"; | ||
221 | continue; | ||
222 | } | ||
223 | if (!setupDirExists(instdir)) | ||
224 | { | ||
225 | bool mustcreate=confirm("Install directory does not exist. Create it?"); | ||
226 | if (!mustcreate) { | ||
227 | currscreen="instdir\0"; | ||
228 | continue; | ||
229 | } | ||
230 | setupCreateDir(instdir,0755); | ||
231 | |||
232 | if (!(setupDirExists(instdir))) | ||
233 | { | ||
234 | fl_message("Could not create install directory.\nPlease create it manually, then try again."); | ||
235 | currscreen="instdir\0"; | ||
236 | continue; | ||
237 | } | ||
238 | } | ||
239 | if (strncmp(currscreen,"next",4)==0) { | ||
240 | currscreen="ready\0"; | ||
241 | continue; | ||
242 | } | ||
243 | // screen closed otherwise | ||
244 | currscreen="done\0"; | ||
245 | continue; | ||
246 | } | ||
247 | if (strncmp(currscreen,"ready",5)==0) | ||
248 | { | ||
249 | // READY | ||
250 | cout << "actually doing the install now" << endl; | ||
251 | insterror=0; | ||
252 | result=installer_writefile( | ||
253 | resource_hd24tools_manual,sizeof(resource_hd24tools_manual),(const char*)instdir,resource_hd24tools_manual_filename,ALLOW_OVERWRITE); | ||
254 | if (result!=0) { insterror=1; currscreen="done\0"; continue; } | ||
255 | result=installer_writefile( | ||
256 | resource_longliverec,sizeof(resource_longliverec),(const char*)instdir,resource_longliverec_filename,ALLOW_OVERWRITE); | ||
257 | if (result!=0) { insterror=1; currscreen="done\0"; continue; } | ||
258 | result=installer_writefile( | ||
259 | resource_unquickformat,sizeof(resource_unquickformat),instdir,resource_unquickformat_filename,ALLOW_OVERWRITE); | ||
260 | if (result!=0) { insterror=1; currscreen="done\0"; continue; } | ||
261 | #ifdef LINUX | ||
262 | /* for linux, wrap the binary into a shell script | ||
263 | * that prepends the application dir to the library | ||
264 | * search path */ | ||
265 | fullbinname=resource_hd24connect_filename; | ||
266 | fullbinname+="_bin"; | ||
267 | result=installer_writefile( | ||
268 | resource_hd24connect,sizeof(resource_hd24connect),(const char*)instdir,fullbinname.c_str(),ALLOW_OVERWRITE); | ||
269 | fullbinname=instdir; | ||
270 | fullbinname+=resource_hd24connect_filename; | ||
271 | fstream wrapper(fullbinname.c_str(),ios::out); | ||
272 | wrapper << "#!/bin/sh" << endl; | ||
273 | wrapper << "export LD_LIBRARY_PATH=" << instdir <<":$LD_LIBRARY_PATH" << endl; | ||
274 | wrapper << "exec " << instdir << "hd24connect_bin $*" << endl; | ||
275 | wrapper.close(); | ||
276 | chmod(fullbinname.c_str(),S_IRWXU|S_IXGRP|S_IRGRP|S_IXOTH|S_IROTH); | ||
277 | #endif | ||
278 | #ifdef WINDOWS | ||
279 | result=installer_writefile( | ||
280 | resource_hd24connect,sizeof(resource_hd24connect),(const char*)instdir,resource_hd24connect_filename,ALLOW_OVERWRITE); | ||
281 | #endif | ||
282 | #ifdef DARWIN | ||
283 | /* For MacOS, wrap the binary into a .app bundle. | ||
284 | * Note: What is called LD_LIBRARY_PATH under Linux | ||
285 | * is called DYLD_LIBRARY_PATH on MacOSX | ||
286 | */ | ||
287 | string bundledir=instdir; | ||
288 | bundledir+="hd24connect.app/"; | ||
289 | setupCreateDir(bundledir.c_str(),0755); | ||
290 | bundledir+="Contents/"; | ||
291 | setupCreateDir(bundledir.c_str(),0755); | ||
292 | string macosdir; | ||
293 | macosdir=bundledir+"MacOS/"; | ||
294 | setupCreateDir(macosdir.c_str(),0755); | ||
295 | string resourcedir=bundledir+"Resources/"; | ||
296 | setupCreateDir(resourcedir.c_str(),0755); | ||
297 | string strplist="Info.plist"; | ||
298 | string strpkginfo="PkgInfo"; | ||
299 | |||
300 | result=installer_writefile(resource_plist_connect,sizeof(resource_plist_connect),bundledir.c_str(),"info.plist",ALLOW_OVERWRITE); | ||
301 | result=installer_writefile(resource_pkginfo_connect,sizeof(resource_pkginfo_connect),bundledir.c_str(),strpkginfo.c_str(),ALLOW_OVERWRITE); | ||
302 | result=installer_writefile(resource_hd24connect,sizeof(resource_hd24connect),macosdir.c_str(),resource_hd24connect_filename,ALLOW_OVERWRITE); | ||
303 | |||
304 | |||
305 | #endif | ||
306 | if (result!=0) { insterror=1; currscreen="done\0"; continue; } | ||
307 | result=installer_writefile( | ||
308 | resource_hd24hexview,sizeof(resource_hd24hexview),(const char*)instdir,resource_hd24hexview_filename,ALLOW_OVERWRITE); | ||
309 | if (result!=0) { insterror=1; currscreen="done\0"; continue; } | ||
310 | result=installer_writefile( | ||
311 | resource_libsndfile_1,sizeof(resource_libsndfile_1),(const char*)instdir,resource_libsndfile_1_filename,ALLOW_OVERWRITE); | ||
312 | if (result!=0) { insterror=1; currscreen="done\0"; continue; } | ||
313 | // result=installer_writefile( | ||
314 | // resource_portaudio,sizeof(resource_portaudio),(const char*)instdir,resource_portaudio_filename,NO_OVERWRITE); | ||
315 | // if (result!=0) { insterror=1; currscreen="done\0"; continue; } | ||
316 | |||
317 | Fl_Window *window = ui_ready.make_window(&currscreen[0]); | ||
318 | #ifdef WINDOWS | ||
319 | window->icon((char *)LoadIcon(fl_display,MAKEINTRESOURCE(IDI_ICON1))); | ||
320 | #endif | ||
321 | window->position(lastx,lasty); | ||
322 | window->end(); | ||
323 | window->show(); //argc, argv); | ||
324 | Fl::run(); lastx=window->x(); lasty=window->y(); | ||
325 | |||
326 | currscreen = ui_ready.currscreen; | ||
327 | if (strncmp(currscreen,"back",4)==0) { | ||
328 | currscreen="license\0"; | ||
329 | continue; | ||
330 | } | ||
331 | if (strncmp(currscreen,"next",4)==0) { | ||
332 | currscreen="doinst\0"; | ||
333 | continue; | ||
334 | } | ||
335 | if (strncmp(currscreen,"cancel",4)==0) { | ||
336 | currscreen="done\0"; | ||
337 | continue; | ||
338 | } | ||
339 | // screen closed otherwise | ||
340 | cout << "???" << currscreen << endl; | ||
341 | currscreen="done\0"; | ||
342 | continue; | ||
343 | } | ||
344 | if (strncmp(currscreen,"doinst",6)==0) | ||
345 | { | ||
346 | currscreen="done\0"; | ||
347 | continue; | ||
348 | } | ||
349 | cout << "Unknown screen '" << currscreen << "'." << endl; | ||
350 | done=true; | ||
351 | } | ||
352 | return 0; | ||
353 | } | ||
diff --git a/src/installer/setupapi.cpp b/src/installer/setupapi.cpp new file mode 100644 index 0000000..b90fd04 --- /dev/null +++ b/src/installer/setupapi.cpp | |||
@@ -0,0 +1,473 @@ | |||
1 | /** BEGIN COPYRIGHT BLOCK | ||
2 | * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. | ||
3 | * Copyright (C) 2005 Red Hat, Inc. | ||
4 | * All rights reserved. | ||
5 | * | ||
6 | * This library is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation version | ||
9 | * 2.1 of the License. | ||
10 | * | ||
11 | * This library is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * Lesser General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU Lesser General Public | ||
17 | * License along with this library; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | * END COPYRIGHT BLOCK **/ | ||
20 | #ifdef WINDOWS | ||
21 | #define XP_WIN32 | ||
22 | #endif | ||
23 | #ifndef MAX_PATH | ||
24 | #define MAX_PATH 127 | ||
25 | #endif | ||
26 | #ifndef TRUE | ||
27 | #define TRUE (1==1) | ||
28 | #endif | ||
29 | #ifndef FALSE | ||
30 | #define FALSE (1==0) | ||
31 | #endif | ||
32 | #include <sys/types.h> | ||
33 | #include <sys/stat.h> | ||
34 | #include <errno.h> | ||
35 | #include <stdio.h> | ||
36 | #include <stdarg.h> | ||
37 | #include <time.h> | ||
38 | #include <string.h> | ||
39 | #include <ctype.h> | ||
40 | |||
41 | #ifdef XP_WIN32 | ||
42 | #include <windows.h> | ||
43 | #include <regstr.h> | ||
44 | #include <direct.h> | ||
45 | #include <io.h> /* For _findfirst */ | ||
46 | #else | ||
47 | |||
48 | |||
49 | #include <sys/types.h> | ||
50 | #include <sys/statvfs.h> | ||
51 | #include <sys/socket.h> /* socket, bind */ | ||
52 | #include <netinet/in.h> /* htonl */ | ||
53 | #include <netdb.h> /* gethostbyname */ | ||
54 | #include <arpa/inet.h> /* inet_ntoa */ | ||
55 | #include <dirent.h> | ||
56 | #include <assert.h> | ||
57 | |||
58 | #endif | ||
59 | |||
60 | |||
61 | #define MINPORT 1024 | ||
62 | #define MAXPORT 65535 | ||
63 | |||
64 | |||
65 | |||
66 | /********************************************************************* | ||
67 | ** | ||
68 | ** FUNCTION: setupIsDirEmpty | ||
69 | ** Replaced: IsDirEmpty | ||
70 | ** | ||
71 | ** DESCRIPTION: checks to see if directory empty | ||
72 | ** | ||
73 | ** | ||
74 | ** INPUTS: | ||
75 | ** | ||
76 | ** RETURN: | ||
77 | ** TRUE or FALSE | ||
78 | ** | ||
79 | ** SIDE EFFECTS: | ||
80 | ** none | ||
81 | ** RESTRICTIONS: | ||
82 | ** None | ||
83 | ** MEMORY: | ||
84 | **********************************************************************/ | ||
85 | |||
86 | int setupIsDirEmpty(const char * pszPath) | ||
87 | { | ||
88 | #ifdef XP_WIN32 | ||
89 | int iReturn = TRUE; | ||
90 | char szFileSpec[MAX_PATH]; | ||
91 | WIN32_FIND_DATA fd; | ||
92 | HANDLE ff; | ||
93 | |||
94 | if (!(pszPath)) | ||
95 | { | ||
96 | //setupLog(NULL, "setupIsDirEmpty failed: passed in NULL parameter for directory Name"); | ||
97 | return FALSE; | ||
98 | } | ||
99 | snprintf(szFileSpec, sizeof(szFileSpec), "%s\\*", pszPath); | ||
100 | if (!memchr(szFileSpec, 0, sizeof(szFileSpec))) return FALSE; /*overflow*/ | ||
101 | |||
102 | ff = FindFirstFile(szFileSpec, &fd); | ||
103 | if (ff != INVALID_HANDLE_VALUE) | ||
104 | { | ||
105 | do | ||
106 | { | ||
107 | if (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..")) | ||
108 | { | ||
109 | iReturn = FALSE; | ||
110 | break; | ||
111 | } | ||
112 | } while (FindNextFile(ff, &fd)); | ||
113 | FindClose(ff); | ||
114 | } | ||
115 | |||
116 | return (iReturn); | ||
117 | #else | ||
118 | DIR *dirp; | ||
119 | struct dirent *dp; | ||
120 | bool rc = TRUE; | ||
121 | |||
122 | dirp = opendir(pszPath); | ||
123 | while ((dp = readdir(dirp)) != NULL) | ||
124 | { | ||
125 | if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) | ||
126 | { | ||
127 | rc = FALSE; | ||
128 | break; | ||
129 | } | ||
130 | } | ||
131 | closedir(dirp); | ||
132 | return rc; | ||
133 | #endif | ||
134 | |||
135 | } | ||
136 | |||
137 | /********************************************************************* | ||
138 | ** | ||
139 | ** FUNCTION: setupFileExist | ||
140 | ** Replaced: FileExist | ||
141 | ** | ||
142 | ** DESCRIPTION: returns 1 if file exists. | ||
143 | ** | ||
144 | ** INPUTS: | ||
145 | ** | ||
146 | ** RETURN: | ||
147 | ** TRUE or FALSE | ||
148 | ** | ||
149 | ** SIDE EFFECTS: | ||
150 | ** none | ||
151 | ** RESTRICTIONS: | ||
152 | ** None | ||
153 | ** MEMORY: | ||
154 | **********************************************************************/ | ||
155 | int setupFileExists(const char * pszFileName) | ||
156 | { | ||
157 | struct stat fi; | ||
158 | |||
159 | if ((stat (pszFileName, &fi) != -1) && ((fi.st_mode & S_IFDIR) == 0)) | ||
160 | { | ||
161 | return TRUE; | ||
162 | } | ||
163 | else | ||
164 | { | ||
165 | return FALSE; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | |||
170 | /********************************************************************* | ||
171 | ** | ||
172 | ** FUNCTION: setupDirExists | ||
173 | ** Replaced: DirExists | ||
174 | ** | ||
175 | ** DESCRIPTION: checks to see if directory exists | ||
176 | ** | ||
177 | ** | ||
178 | ** INPUTS: | ||
179 | ** | ||
180 | ** RETURN: | ||
181 | ** TRUE or FALSE | ||
182 | ** | ||
183 | ** SIDE EFFECTS: | ||
184 | ** none | ||
185 | ** RESTRICTIONS: | ||
186 | ** None | ||
187 | ** MEMORY: | ||
188 | **********************************************************************/ | ||
189 | int setupDirExists(const char * pszDirName) | ||
190 | { | ||
191 | #ifdef XP_WIN32 | ||
192 | unsigned int dwAttrs; | ||
193 | if (!(pszDirName)) | ||
194 | { | ||
195 | //setupLog(NULL, "DirExists failed: passed in NULL parameter for directory"); | ||
196 | return FALSE; | ||
197 | } | ||
198 | dwAttrs = GetFileAttributes(pszDirName); | ||
199 | if ((dwAttrs != 0xFFFFFFFF) && (dwAttrs & FILE_ATTRIBUTE_DIRECTORY)) | ||
200 | { | ||
201 | return TRUE; | ||
202 | } | ||
203 | return FALSE; | ||
204 | #else | ||
205 | struct stat fi; | ||
206 | |||
207 | if (stat (pszDirName, &fi) == -1 || !S_ISDIR(fi.st_mode)) | ||
208 | { | ||
209 | return FALSE; | ||
210 | } | ||
211 | else | ||
212 | { | ||
213 | return TRUE; | ||
214 | } | ||
215 | #endif | ||
216 | } | ||
217 | |||
218 | /********************************************************************* | ||
219 | ** | ||
220 | ** FUNCTION: setupCreateDir | ||
221 | ** Replaced: CreateDir | ||
222 | ** | ||
223 | ** DESCRIPTION: creates a directory | ||
224 | ** | ||
225 | ** | ||
226 | ** INPUTS: | ||
227 | ** | ||
228 | ** RETURN: | ||
229 | ** NT: TRUE or FALSE | ||
230 | ** UNIX: | ||
231 | ** 0 : OK | ||
232 | ** -1 : Can't create directory | ||
233 | ** -2 : input exists and is not a directory | ||
234 | ** -3 : Can't write to directory | ||
235 | ** | ||
236 | ** SIDE EFFECTS: | ||
237 | ** none | ||
238 | ** RESTRICTIONS: | ||
239 | ** None | ||
240 | ** MEMORY: | ||
241 | ** | ||
242 | **********************************************************************/ | ||
243 | bool setupCreateDir(const char * pszDirName, int mode) | ||
244 | { | ||
245 | #ifdef XP_WIN32 | ||
246 | char *pszDelim; | ||
247 | char szDirName[MAX_PATH]; | ||
248 | char szTmpDir[MAX_PATH] = ""; | ||
249 | int cbLen; | ||
250 | |||
251 | if (!(pszDirName)) | ||
252 | { | ||
253 | //setupLog(NULL, "CreateDir failed: passed in NULL parameter for directory"); | ||
254 | return FALSE; | ||
255 | } | ||
256 | |||
257 | if (strlen(pszDirName) >= sizeof(szDirName)) | ||
258 | { | ||
259 | //setupLog(NULL, "CreateDir failed: passed in too long directory"); | ||
260 | return FALSE; | ||
261 | } | ||
262 | |||
263 | snprintf(szDirName, sizeof(szDirName), "%s", pszDirName); | ||
264 | if (!memchr(szDirName, 0, sizeof(szDirName))) return FALSE; /*overflow*/ | ||
265 | pszDelim = szDirName; | ||
266 | while ((pszDelim = strchr(pszDelim, '/')) != NULL) | ||
267 | { | ||
268 | *pszDelim = '\\'; | ||
269 | } | ||
270 | |||
271 | pszDelim = szDirName; | ||
272 | while ((pszDelim = strchr(pszDelim, '\\')) != NULL) | ||
273 | { | ||
274 | cbLen = (pszDelim - szDirName); | ||
275 | strncpy(szTmpDir, szDirName, cbLen); | ||
276 | szTmpDir[cbLen] = '\0'; | ||
277 | CreateDirectory(szTmpDir, NULL); | ||
278 | pszDelim++; | ||
279 | } | ||
280 | |||
281 | if (!CreateDirectory(szDirName, NULL)) | ||
282 | { | ||
283 | // char szLog[MAX_PATH+50]; | ||
284 | return FALSE; | ||
285 | // snprintf(szLog, sizeof(szLog), | ||
286 | // "setupCreateDir failed to create '%s'", pszDirName); | ||
287 | // if (!memchr(szLog, 0, sizeof(szLog))) return FALSE; /*overflow*/ | ||
288 | //setupLog(NULL, szLog); | ||
289 | } | ||
290 | return TRUE; | ||
291 | #else | ||
292 | struct stat fi; | ||
293 | char *s; | ||
294 | char *t; | ||
295 | |||
296 | s = strdup(pszDirName); | ||
297 | t = s + 1; | ||
298 | |||
299 | while (1) | ||
300 | { | ||
301 | t = strchr(t, '/'); | ||
302 | |||
303 | if (t) | ||
304 | *t = '\0'; | ||
305 | if (stat(s, &fi) == -1) | ||
306 | { | ||
307 | if (mkdir(s, mode) == -1) | ||
308 | { | ||
309 | return FALSE; | ||
310 | } | ||
311 | } | ||
312 | else if (!S_ISDIR(fi.st_mode)) | ||
313 | { | ||
314 | return FALSE; | ||
315 | } | ||
316 | if (t) | ||
317 | *t++ = '/'; | ||
318 | else | ||
319 | break; | ||
320 | } | ||
321 | |||
322 | if (access(pszDirName, W_OK) == -1) | ||
323 | { | ||
324 | return FALSE; | ||
325 | } | ||
326 | return TRUE; | ||
327 | #endif | ||
328 | } | ||
329 | /********************************************************************* | ||
330 | ** | ||
331 | ** FUNCTION: setupConvertsPathSlashes | ||
332 | ** Replaced: ConvertsPathSlashes | ||
333 | ** | ||
334 | ** DESCRIPTION: converts slashes TRUE UNIX to NT, FALSE NT to UNIX, | ||
335 | ** | ||
336 | ** INPUTS: | ||
337 | ** | ||
338 | ** RETURN: | ||
339 | ** TRUE or FALSE | ||
340 | ** | ||
341 | ** SIDE EFFECTS: | ||
342 | ** none | ||
343 | ** RESTRICTIONS: | ||
344 | ** None | ||
345 | ** MEMORY: | ||
346 | **********************************************************************/ | ||
347 | int setupConvertPathSlashes(const char * lpszPath, char * lpszNewPath, int bType ) | ||
348 | { | ||
349 | if (lpszPath == NULL) | ||
350 | return FALSE; | ||
351 | |||
352 | /* create reverse slashes and escape them */ | ||
353 | while (*lpszPath) | ||
354 | { | ||
355 | if ((*lpszPath == '\\') || (*lpszPath == '/')) | ||
356 | { | ||
357 | if (bType) | ||
358 | *lpszNewPath = '\\'; | ||
359 | else | ||
360 | *lpszNewPath = '/'; | ||
361 | } | ||
362 | else | ||
363 | *lpszNewPath = *lpszPath; | ||
364 | lpszPath++; | ||
365 | lpszNewPath++; | ||
366 | } | ||
367 | return TRUE; | ||
368 | } | ||
369 | |||
370 | |||
371 | unsigned int setupExecProgram(const char *program, const char *where) | ||
372 | { | ||
373 | char curdir[MAX_PATH]; | ||
374 | unsigned int ret; | ||
375 | #ifdef XP_WIN32 | ||
376 | char szWhere[MAX_PATH]; | ||
377 | char szProgram[MAX_PATH]; | ||
378 | STARTUPINFO si; | ||
379 | PROCESS_INFORMATION pi; | ||
380 | DWORD dwCreationFlags; | ||
381 | #endif | ||
382 | |||
383 | if (!program) | ||
384 | { | ||
385 | //setupLogMessage("info", "setup", "setupExecProgram called with no program"); | ||
386 | return 0; | ||
387 | } | ||
388 | if (!setupFileExists(program)) | ||
389 | { | ||
390 | //setupLogMessage("info", "setup", "setupExecProgram called with invalid program %s", program); | ||
391 | } | ||
392 | getcwd(curdir, sizeof(curdir)); | ||
393 | |||
394 | if (where) | ||
395 | { | ||
396 | chdir(where); | ||
397 | } | ||
398 | #ifndef XP_WIN32 | ||
399 | ret = system(program); | ||
400 | #else | ||
401 | snprintf(szProgram, sizeof(szProgram), "%s", program); | ||
402 | if (!memchr(szProgram, 0, sizeof(szProgram))) { | ||
403 | //setupLogMessage("info", "setup", "Too long program %s", program); | ||
404 | return 0; | ||
405 | } | ||
406 | snprintf(szWhere, sizeof(szWhere), "%s", where); | ||
407 | if (!memchr(szWhere, 0, sizeof(szWhere))) { | ||
408 | //setupLogMessage("info", "setup", "Too long arg %s", where); | ||
409 | return 0; | ||
410 | } | ||
411 | memset(&si,0,sizeof(si)); | ||
412 | si.cb = sizeof(si); | ||
413 | GetStartupInfo(&si); | ||
414 | si.wShowWindow = SW_SHOWDEFAULT; | ||
415 | dwCreationFlags = NORMAL_PRIORITY_CLASS | DETACHED_PROCESS; | ||
416 | ret = CreateProcess(NULL, szProgram, NULL, NULL, FALSE, dwCreationFlags, NULL, szWhere, &si, &pi); | ||
417 | #endif | ||
418 | |||
419 | if (where) | ||
420 | { | ||
421 | chdir(curdir); | ||
422 | } | ||
423 | |||
424 | return ret; | ||
425 | } | ||
426 | |||
427 | |||
428 | /********************************************************************* | ||
429 | ** | ||
430 | ** FUNCTION: setupGetDiskFreeSpace | ||
431 | ** DESCRIPTION: get available disk space in Kilobyte | ||
432 | ** | ||
433 | ** INPUTS: Path name | ||
434 | ** OUTPUTS: | ||
435 | ** RETURN: available disk space in kilobyte | ||
436 | ** SIDE EFFECTS: | ||
437 | ** None | ||
438 | ** RESTRICTIONS: | ||
439 | ** None | ||
440 | ** MEMORY: | ||
441 | ********************************************************************** | ||
442 | */ | ||
443 | |||
444 | unsigned long setupGetDiskFreeSpace(const char *path) | ||
445 | { | ||
446 | #ifdef XP_WIN32 | ||
447 | DWORD dwSectorsPerCluster; | ||
448 | DWORD dwBytesPerSector; | ||
449 | DWORD dwFreeClusters; | ||
450 | DWORD dwTotalClusters; | ||
451 | |||
452 | if (GetDiskFreeSpace(path, &dwSectorsPerCluster, &dwBytesPerSector, &dwFreeClusters, &dwTotalClusters)) | ||
453 | { | ||
454 | long long clusterSize; | ||
455 | |||
456 | clusterSize = dwSectorsPerCluster * dwBytesPerSector; | ||
457 | |||
458 | return (unsigned long)((clusterSize / 1024.0) * dwFreeClusters); | ||
459 | } | ||
460 | |||
461 | return 0; | ||
462 | #else | ||
463 | struct statvfs buf; | ||
464 | |||
465 | statvfs(path, &buf); | ||
466 | |||
467 | if (buf.f_frsize == 0) | ||
468 | return (unsigned long)(((unsigned long long)buf.f_bavail / 1024.0) * buf.f_bsize); | ||
469 | else | ||
470 | return (unsigned long)(((unsigned long long)buf.f_bavail / 1024.0) * buf.f_frsize); | ||
471 | #endif | ||
472 | } | ||
473 | |||
diff --git a/src/installer/starthd24connect.command b/src/installer/starthd24connect.command new file mode 100755 index 0000000..574d4c4 --- /dev/null +++ b/src/installer/starthd24connect.command | |||
@@ -0,0 +1,5 @@ | |||
1 | #!/bin/sh | ||
2 | # to start hd24connect on Mac | ||
3 | export HD24PATH=`echo $0|sed -e 's/starthd24connect\.command//'|sed -e 's/\/$//'` | ||
4 | export DYLD_LIBRARY_PATH=$HD24PATH/hd24connect.app/Contents/MacOS/:$DYLD_LIBRARY_PATH | ||
5 | open $HD24PATH/hd24connect.app $* | ||
diff --git a/src/installer/ui_askpasswd.fl b/src/installer/ui_askpasswd.fl new file mode 100644 index 0000000..f27357c --- /dev/null +++ b/src/installer/ui_askpasswd.fl | |||
@@ -0,0 +1,78 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {using namespace std;} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <string>} {public | ||
9 | } | ||
10 | |||
11 | class UI_Askpasswd {open | ||
12 | } { | ||
13 | decl {char* currscreen;} {public | ||
14 | } | ||
15 | decl {char* instdir;} {public | ||
16 | } | ||
17 | Function {make_window(char* p_currscreen,char* p_instdir)} {open | ||
18 | } { | ||
19 | Fl_Window {} { | ||
20 | label {HD24tools HD24VERSION - Setup Wizard} open selected | ||
21 | xywh {1246 284 590 350} type Double color 7 | ||
22 | code0 {currscreen=p_currscreen;} | ||
23 | code1 {instdir=p_instdir;} visible | ||
24 | } { | ||
25 | Fl_Box {} { | ||
26 | image {welcome.png} xywh {0 -137 165 487} | ||
27 | } | ||
28 | Fl_Button {} { | ||
29 | label {&Browse...} | ||
30 | xywh {505 191 80 20} color 53 labelsize 12 | ||
31 | } | ||
32 | Fl_Box {} { | ||
33 | label {Please enter your password} | ||
34 | xywh {175 -3 320 33} labelfont 1 labelsize 16 align 20 | ||
35 | } | ||
36 | Fl_Group {} {open | ||
37 | xywh {-5 315 620 35} box BORDER_BOX color 53 selection_color 47 | ||
38 | } { | ||
39 | Fl_Button button_next { | ||
40 | label {&Next >} | ||
41 | callback {currscreen="next\\0"; | ||
42 | Fl_Window* winx=Fl::first_window(); | ||
43 | winx->~Fl_Window();} | ||
44 | xywh {415 320 85 25} color 53 labelsize 12 | ||
45 | } | ||
46 | Fl_Button {} { | ||
47 | label Cancel | ||
48 | callback {currscreen="cancel\\0"; | ||
49 | Fl_Window* winx=Fl::first_window(); | ||
50 | winx->~Fl_Window();} | ||
51 | xywh {505 320 85 25} color 53 labelsize 12 | ||
52 | } | ||
53 | Fl_Button {} { | ||
54 | label {< &Back} | ||
55 | callback {currscreen="back\\0"; | ||
56 | Fl_Window* winx=Fl::first_window(); | ||
57 | winx->~Fl_Window();} | ||
58 | xywh {330 320 85 25} color 53 labelsize 12 | ||
59 | } | ||
60 | } | ||
61 | Fl_Output password { | ||
62 | xywh {175 191 325 20} labelsize 12 align 5 textsize 11 | ||
63 | } | ||
64 | Fl_Box {} { | ||
65 | label {The setup wizard needs administrator privileges to allow | ||
66 | writing to the folder where some HD24tools components | ||
67 | need to be installed. | ||
68 | |||
69 | Please enter your password to allow the setup wizard | ||
70 | to access this folder. | ||
71 | |||
72 | Alternatively, if you are an experienced user, you can | ||
73 | temporarily enable write access to the library directory.} | ||
74 | xywh {175 38 405 149} labelsize 12 align 21 | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | } | ||
diff --git a/src/installer/ui_instdir.fl b/src/installer/ui_instdir.fl new file mode 100644 index 0000000..2f62e78 --- /dev/null +++ b/src/installer/ui_instdir.fl | |||
@@ -0,0 +1,105 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {using namespace std;} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <string>} {public | ||
9 | } | ||
10 | |||
11 | decl {\#include <iostream>} {public | ||
12 | } | ||
13 | |||
14 | decl {\#include <FL/Fl_File_Chooser.H>} {public | ||
15 | } | ||
16 | |||
17 | decl {\#include <FL/Fl_Native_File_Chooser.H>} {public | ||
18 | } | ||
19 | |||
20 | class UI_Instdir {open | ||
21 | } { | ||
22 | decl {char* currscreen;} {public | ||
23 | } | ||
24 | decl {char* instdir;} {public | ||
25 | } | ||
26 | Function {make_window(char* p_currscreen,char* p_instdir)} {open | ||
27 | } { | ||
28 | Fl_Window {} { | ||
29 | label {HD24tools HD24VERSION - Setup Wizard} open selected | ||
30 | xywh {1246 284 590 350} type Double color 7 | ||
31 | code0 {currscreen=p_currscreen;} | ||
32 | code1 {instdir=p_instdir;} visible | ||
33 | } { | ||
34 | Fl_Box {} { | ||
35 | image {welcome.png} xywh {0 -137 165 487} | ||
36 | } | ||
37 | Fl_Button {} { | ||
38 | label {&Browse...} | ||
39 | callback {Fl_Native_File_Chooser chooser; | ||
40 | chooser.title("Select installation directory"); | ||
41 | chooser.type(Fl_Native_File_Chooser::BROWSE_DIRECTORY||Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY||Fl_Native_File_Chooser::NEW_FOLDER); | ||
42 | chooser.filter(""); | ||
43 | |||
44 | string cdir=""; | ||
45 | cdir+=currdir->value(); | ||
46 | |||
47 | chooser.directory(cdir.c_str()); | ||
48 | switch (chooser.show()) { | ||
49 | case -1: break; //error | ||
50 | case 1: break; //cancel | ||
51 | default: | ||
52 | if (chooser.filename()) { | ||
53 | currdir->value(chooser.filename()); | ||
54 | } | ||
55 | |||
56 | break; | ||
57 | }} | ||
58 | xywh {505 125 80 20} color 53 labelsize 12 | ||
59 | } | ||
60 | Fl_Box {} { | ||
61 | label {Choose installation directory} | ||
62 | xywh {175 -3 320 33} labelfont 1 labelsize 16 align 20 | ||
63 | } | ||
64 | Fl_Group {} {open | ||
65 | xywh {-5 315 620 35} box BORDER_BOX color 53 selection_color 47 | ||
66 | } { | ||
67 | Fl_Button button_next { | ||
68 | label {&Next >} | ||
69 | callback {currscreen="next\\0"; | ||
70 | string newdir=currdir->value(); | ||
71 | strncpy(&instdir[0],newdir.c_str(),128); | ||
72 | Fl_Window* winx=Fl::first_window(); | ||
73 | winx->~Fl_Window();} | ||
74 | xywh {415 320 85 25} color 53 labelsize 12 | ||
75 | } | ||
76 | Fl_Button {} { | ||
77 | label Cancel | ||
78 | callback {currscreen="cancel\\0"; | ||
79 | Fl_Window* winx=Fl::first_window(); | ||
80 | winx->~Fl_Window();} | ||
81 | xywh {505 320 85 25} color 53 labelsize 12 | ||
82 | } | ||
83 | Fl_Button {} { | ||
84 | label {< &Back} | ||
85 | callback {currscreen="back\\0"; | ||
86 | Fl_Window* winx=Fl::first_window(); | ||
87 | winx->~Fl_Window();} | ||
88 | xywh {330 320 85 25} color 53 labelsize 12 | ||
89 | } | ||
90 | } | ||
91 | Fl_Input currdir { | ||
92 | xywh {175 125 325 20} labelsize 12 align 5 textsize 11 | ||
93 | code0 {currdir->value(p_instdir);} | ||
94 | } | ||
95 | Fl_Box {} { | ||
96 | label {Setup will install HD24tools in the following folder. To | ||
97 | install in a different folder, click Browse and select | ||
98 | another folder. | ||
99 | |||
100 | After that, click Next to start the installation.} | ||
101 | xywh {175 38 370 81} labelsize 12 align 21 | ||
102 | } | ||
103 | } | ||
104 | } | ||
105 | } | ||
diff --git a/src/installer/ui_license.fl b/src/installer/ui_license.fl new file mode 100644 index 0000000..b26bd95 --- /dev/null +++ b/src/installer/ui_license.fl | |||
@@ -0,0 +1,80 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {using namespace std;} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <string>} {public | ||
9 | } | ||
10 | |||
11 | class UI_License {open | ||
12 | } { | ||
13 | decl {char* currscreen;} {public | ||
14 | } | ||
15 | Function {make_window(char* p_currscreen)} {open | ||
16 | } { | ||
17 | Fl_Window {} { | ||
18 | label {HD24tools HD24VERSION - Setup Wizard} open selected | ||
19 | xywh {1302 140 590 350} type Double color 7 | ||
20 | code0 {currscreen=p_currscreen;} visible | ||
21 | } { | ||
22 | Fl_Box {} { | ||
23 | image {welcome.png} xywh {0 -137 165 487} | ||
24 | } | ||
25 | Fl_Box {} { | ||
26 | label {License Agreement} | ||
27 | xywh {175 -3 435 33} labelfont 1 labelsize 16 align 20 | ||
28 | } | ||
29 | Fl_Group agreedisagree {open | ||
30 | xywh {170 265 395 45} | ||
31 | } { | ||
32 | Fl_Round_Button agree { | ||
33 | label {I accept the terms in the license agreement} | ||
34 | callback {agree->value(1); | ||
35 | disagree->value(0); | ||
36 | button_next->activate();} | ||
37 | xywh {175 275 385 15} down_box ROUND_DOWN_BOX labelsize 12 | ||
38 | } | ||
39 | Fl_Round_Button disagree { | ||
40 | label {I do not accept the terms in the license agreement} | ||
41 | callback {agree->value(0); | ||
42 | disagree->value(1); | ||
43 | button_next->deactivate();} | ||
44 | xywh {175 290 385 20} down_box ROUND_DOWN_BOX value 1 labelsize 12 | ||
45 | } | ||
46 | } | ||
47 | Fl_Group {} {open | ||
48 | xywh {-5 315 620 35} box BORDER_BOX color 53 selection_color 47 | ||
49 | } { | ||
50 | Fl_Button button_next { | ||
51 | label {&Next >} | ||
52 | callback {currscreen="next\\0"; | ||
53 | Fl_Window* winx=Fl::first_window(); | ||
54 | winx->~Fl_Window();} | ||
55 | xywh {415 320 85 25} color 53 labelsize 12 | ||
56 | code0 {o->deactivate();} | ||
57 | } | ||
58 | Fl_Button {} { | ||
59 | label Cancel | ||
60 | callback {currscreen="cancel\\0"; | ||
61 | Fl_Window* winx=Fl::first_window(); | ||
62 | winx->~Fl_Window();} | ||
63 | xywh {505 320 85 25} color 53 labelsize 12 | ||
64 | } | ||
65 | Fl_Button {} { | ||
66 | label {< &Back} | ||
67 | callback {currscreen="back\\0"; | ||
68 | Fl_Window* winx=Fl::first_window(); | ||
69 | winx->~Fl_Window();} | ||
70 | xywh {330 320 85 25} color 53 labelsize 12 | ||
71 | } | ||
72 | } | ||
73 | Fl_Output {} { | ||
74 | label {Please read the following license agreement carefully.} | ||
75 | xywh {175 45 405 220} type Multiline labelsize 12 align 5 textsize 11 | ||
76 | code0 {o->value("HD24tools End User License Agreement\\n\\nThis program is SHAREWARE. You are hereby granted\\npermission to download and use this software free of\\ncharge, as well as to give away UNALTERED copies of it.\\n\\nThis program is provided in the hope that it\\nwill be useful, but comes with ABSOLUTELY NO WARRANTY.\\n\\nIf you find this program useful, please make a donation\\nto the author. For details, see\\nhttp://ringbreak.dnd.utwente.nl/~mrjb/hd24tools/\\n\\nThis software is not endorsed not affiliated by Alesis.");} | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | } | ||
diff --git a/src/installer/ui_ready.fl b/src/installer/ui_ready.fl new file mode 100644 index 0000000..df550ed --- /dev/null +++ b/src/installer/ui_ready.fl | |||
@@ -0,0 +1,49 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {using namespace std;} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <string>} {public | ||
9 | } | ||
10 | |||
11 | class UI_Ready {open | ||
12 | } { | ||
13 | decl {char* currscreen;} {public | ||
14 | } | ||
15 | Function {make_window(char* p_currscreen)} {open | ||
16 | } { | ||
17 | Fl_Window {} { | ||
18 | label {HD24tools HD24VERSION - Setup Wizard} open | ||
19 | xywh {1302 140 590 350} type Double color 7 | ||
20 | code0 {currscreen=p_currscreen;} visible | ||
21 | } { | ||
22 | Fl_Box {} { | ||
23 | image {welcome.png} xywh {0 -137 165 487} | ||
24 | } | ||
25 | Fl_Box {} { | ||
26 | label {Installation Complete} | ||
27 | xywh {175 -3 435 33} labelfont 1 labelsize 16 align 20 | ||
28 | } | ||
29 | Fl_Group {} {open | ||
30 | xywh {-5 315 620 35} box BORDER_BOX color 53 selection_color 47 | ||
31 | } { | ||
32 | Fl_Button {} { | ||
33 | label Close | ||
34 | callback {currscreen="cancel\\0"; | ||
35 | Fl_Window* winx=Fl::first_window(); | ||
36 | winx->~Fl_Window();} | ||
37 | xywh {505 320 85 25} color 53 labelsize 12 | ||
38 | } | ||
39 | } | ||
40 | Fl_Box {} { | ||
41 | label {HD24tools installation has been completed successfully. | ||
42 | You may now run it from the installation path. | ||
43 | |||
44 | Please click Close to terminate the installer.} selected | ||
45 | xywh {180 58 385 169} labelsize 12 align 21 | ||
46 | } | ||
47 | } | ||
48 | } | ||
49 | } | ||
diff --git a/src/installer/ui_welcome.fl b/src/installer/ui_welcome.fl new file mode 100644 index 0000000..f7dcb0c --- /dev/null +++ b/src/installer/ui_welcome.fl | |||
@@ -0,0 +1,66 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0107 | ||
3 | header_name {.h} | ||
4 | code_name {.cxx} | ||
5 | decl {using namespace std;} {public | ||
6 | } | ||
7 | |||
8 | decl {\#include <string>} {public | ||
9 | } | ||
10 | |||
11 | class UI_Welcome {open | ||
12 | } { | ||
13 | decl {char* currscreen;} {public | ||
14 | } | ||
15 | Function {make_window(char* p_currscreen)} {open | ||
16 | } { | ||
17 | Fl_Window {} { | ||
18 | label {HD24tools HD24VERSION - Setup Wizard} open | ||
19 | xywh {308 186 590 350} type Double color 7 | ||
20 | code0 {currscreen=p_currscreen;} visible | ||
21 | } { | ||
22 | Fl_Box {} { | ||
23 | image {welcome.png} xywh {0 -137 165 487} | ||
24 | } | ||
25 | Fl_Box {} { | ||
26 | label {Welcome to the setup wizard for} | ||
27 | xywh {165 -3 440 33} labelfont 1 labelsize 16 | ||
28 | } | ||
29 | Fl_Box {} { | ||
30 | label {HD24tools version HD24VERSION} | ||
31 | xywh {165 22 440 31} labelfont 1 labelsize 16 | ||
32 | } | ||
33 | Fl_Group {} {open | ||
34 | xywh {-5 315 620 35} box BORDER_BOX color 53 selection_color 47 | ||
35 | } { | ||
36 | Fl_Button {} { | ||
37 | label {&Next >} | ||
38 | callback {currscreen="next\\0"; | ||
39 | Fl_Window* winx=Fl::first_window(); | ||
40 | winx->~Fl_Window();} | ||
41 | xywh {415 320 85 25} color 53 labelsize 12 | ||
42 | } | ||
43 | Fl_Button {} { | ||
44 | label Cancel | ||
45 | callback {currscreen="cancel\\0"; | ||
46 | Fl_Window* winx=Fl::first_window(); | ||
47 | winx->~Fl_Window();} | ||
48 | xywh {505 320 85 25} color 53 labelsize 12 | ||
49 | } | ||
50 | } | ||
51 | Fl_Box {} { | ||
52 | label {This Setup Wizard will install HD24tools version HD24VERSION | ||
53 | on your computer. | ||
54 | |||
55 | Attention: You may need to run this wizard as administrator/ | ||
56 | superuser/root. | ||
57 | |||
58 | Before continuing, please close all running programs. | ||
59 | |||
60 | |||
61 | WARNING: This program is protected by copyright law.} selected | ||
62 | xywh {185 77 390 173} labelsize 12 align 21 | ||
63 | } | ||
64 | } | ||
65 | } | ||
66 | } | ||
diff --git a/src/installer/welcome.png b/src/installer/welcome.png new file mode 100644 index 0000000..88b9a73 --- /dev/null +++ b/src/installer/welcome.png | |||
Binary files differ | |||
diff --git a/src/lib/FL/FLTKstuff.H b/src/lib/FL/FLTKstuff.H new file mode 100644 index 0000000..0c1f8d1 --- /dev/null +++ b/src/lib/FL/FLTKstuff.H | |||
@@ -0,0 +1,6 @@ | |||
1 | #include <FL/Fl_Image_Button.H> | ||
2 | #include <FL/Fl_Multiline_Output.H> | ||
3 | #include <FL/Fl_Image_Repeat_Button.H> | ||
4 | #include <FL/Fl_Image_Toggle_Button.H> | ||
5 | #include <FL/Fl_Native_File_Chooser.H> | ||
6 | #include <FL/Fl_Roller.H> | ||
diff --git a/src/lib/FL/Fl_Image_Button.H b/src/lib/FL/Fl_Image_Button.H new file mode 100644 index 0000000..656e169 --- /dev/null +++ b/src/lib/FL/Fl_Image_Button.H | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef __FL_IMAGE_BUTTON_H | ||
2 | #define __FL_IMAGE_BUTTON_H | ||
3 | #include <FL/Fl_Button.H> | ||
4 | #include <FL/Fl.H> | ||
5 | |||
6 | class Fl_Image_Button: public Fl_Button { | ||
7 | private: | ||
8 | Fl_Image* upimage; | ||
9 | Fl_Image* downimage; | ||
10 | public: | ||
11 | Fl_Image* up_image(); | ||
12 | Fl_Image* down_image(); | ||
13 | void up_image(Fl_Image* p_up_image); | ||
14 | void down_image(Fl_Image* p_down_image); | ||
15 | void draw(); | ||
16 | Fl_Image_Button(int a,int b,int c,int d,const char* e); | ||
17 | Fl_Image_Button(int a,int b,int c,int d); | ||
18 | }; | ||
19 | |||
20 | #endif | ||
diff --git a/src/lib/FL/Fl_Image_Button.cxx b/src/lib/FL/Fl_Image_Button.cxx new file mode 100644 index 0000000..f169396 --- /dev/null +++ b/src/lib/FL/Fl_Image_Button.cxx | |||
@@ -0,0 +1,110 @@ | |||
1 | #include <FL/Fl_Image_Button.H> | ||
2 | #include <FL/Fl_Image.H> | ||
3 | #include <FL/fl_draw.H> | ||
4 | #ifndef NULL | ||
5 | #define NULL 0 | ||
6 | #endif | ||
7 | void Fl_Image_Button::up_image(Fl_Image* p_upimage) | ||
8 | { | ||
9 | upimage=p_upimage; | ||
10 | } | ||
11 | |||
12 | void Fl_Image_Button::down_image(Fl_Image* p_downimage) | ||
13 | { | ||
14 | downimage=p_downimage; | ||
15 | } | ||
16 | |||
17 | Fl_Image* Fl_Image_Button::up_image() | ||
18 | { | ||
19 | return upimage; | ||
20 | } | ||
21 | |||
22 | Fl_Image* Fl_Image_Button::down_image() | ||
23 | { | ||
24 | return downimage; | ||
25 | } | ||
26 | |||
27 | Fl_Image_Button::Fl_Image_Button(int a,int b,int c,int d,const char* e):Fl_Button(a,b,c,d,e) | ||
28 | { | ||
29 | upimage=NULL; | ||
30 | downimage=NULL; | ||
31 | Fl_Button::clear_visible_focus(); | ||
32 | } | ||
33 | Fl_Image_Button::Fl_Image_Button(int a,int b,int c,int d):Fl_Button(a,b,c,d) | ||
34 | { | ||
35 | upimage=NULL; | ||
36 | downimage=NULL; | ||
37 | Fl_Button::clear_visible_focus(); | ||
38 | } | ||
39 | |||
40 | /*void Fl_Image_Button::draw() { | ||
41 | if (value()==0) | ||
42 | { | ||
43 | if (upimage!=NULL) { | ||
44 | this->image(upimage); | ||
45 | } | ||
46 | } else { | ||
47 | if (this->value()==1) | ||
48 | { | ||
49 | if (downimage!=NULL) { | ||
50 | this->image(downimage); | ||
51 | } | ||
52 | } | ||
53 | } | ||
54 | Fl_Button::draw(); | ||
55 | } | ||
56 | |||
57 | */ | ||
58 | |||
59 | |||
60 | void Fl_Image_Button::draw() | ||
61 | { | ||
62 | // begin - Fl_Button::draw() (box section) | ||
63 | if (type() == FL_HIDDEN_BUTTON) return; | ||
64 | Fl_Color col = value() ? selection_color() : color(); | ||
65 | |||
66 | |||
67 | draw_box(value() ? (down_box()?down_box():fl_down(box())) : box(), col); | ||
68 | // end - Fl_Button::draw() (box section) | ||
69 | |||
70 | // begin - modification to render up/down image | ||
71 | Fl_Boxtype box_; | ||
72 | Fl_Image* pic_; | ||
73 | |||
74 | if(value()) | ||
75 | { | ||
76 | box_ = (down_box())? down_box() : fl_down(box()); | ||
77 | pic_ = downimage; | ||
78 | } | ||
79 | else | ||
80 | { | ||
81 | box_ = box(); | ||
82 | pic_ = upimage; | ||
83 | } | ||
84 | |||
85 | if(pic_) | ||
86 | { | ||
87 | int xx = x() + Fl::box_dx(box_); | ||
88 | int yy = y() + Fl::box_dy(box_); | ||
89 | int ww = w() - Fl::box_dw(box_); | ||
90 | int hh = h() - Fl::box_dh(box_); | ||
91 | int xpos = (ww - pic_->w()) / 2; | ||
92 | int ypos = (hh - pic_->h()) / 2; | ||
93 | |||
94 | fl_push_clip(xx, yy, ww, hh); | ||
95 | pic_->draw(xx + xpos, yy + ypos); | ||
96 | fl_pop_clip(); | ||
97 | } | ||
98 | // end- modification to render up/down image | ||
99 | |||
100 | // begin - Fl_Button::draw() (label section) | ||
101 | if (labeltype() == FL_NORMAL_LABEL && value()) { | ||
102 | Fl_Color c = labelcolor(); | ||
103 | labelcolor(fl_contrast(c, col)); | ||
104 | draw_label(); | ||
105 | labelcolor(c); | ||
106 | } else draw_label(); | ||
107 | if (Fl::focus() == this) draw_focus(); | ||
108 | // end - Fl_Button::draw() (label section) | ||
109 | } | ||
110 | |||
diff --git a/src/lib/FL/Fl_Image_Repeat_Button.H b/src/lib/FL/Fl_Image_Repeat_Button.H new file mode 100644 index 0000000..442082a --- /dev/null +++ b/src/lib/FL/Fl_Image_Repeat_Button.H | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef __FL_IMAGE_Repeat_Button_H | ||
2 | #define __FL_IMAGE_Repeat_Button_H | ||
3 | #include <FL/Fl_Repeat_Button.H> | ||
4 | #include <FL/Fl.H> | ||
5 | |||
6 | class Fl_Image_Repeat_Button: public Fl_Repeat_Button { | ||
7 | private: | ||
8 | Fl_Image* upimage; | ||
9 | Fl_Image* downimage; | ||
10 | public: | ||
11 | Fl_Image* up_image(); | ||
12 | Fl_Image* down_image(); | ||
13 | void up_image(Fl_Image* p_up_image); | ||
14 | void down_image(Fl_Image* p_down_image); | ||
15 | void draw(); | ||
16 | Fl_Image_Repeat_Button(int a,int b,int c,int d,const char* e); | ||
17 | Fl_Image_Repeat_Button(int a,int b,int c,int d); | ||
18 | }; | ||
19 | |||
20 | #endif | ||
diff --git a/src/lib/FL/Fl_Image_Repeat_Button.cxx b/src/lib/FL/Fl_Image_Repeat_Button.cxx new file mode 100644 index 0000000..71530de --- /dev/null +++ b/src/lib/FL/Fl_Image_Repeat_Button.cxx | |||
@@ -0,0 +1,86 @@ | |||
1 | #include <FL/Fl_Image_Repeat_Button.H> | ||
2 | #include <FL/Fl_Image.H> | ||
3 | #include <FL/fl_draw.H> | ||
4 | |||
5 | #ifndef NULL | ||
6 | #define NULL 0 | ||
7 | #endif | ||
8 | void Fl_Image_Repeat_Button::up_image(Fl_Image* p_upimage) | ||
9 | { | ||
10 | upimage=p_upimage; | ||
11 | } | ||
12 | |||
13 | void Fl_Image_Repeat_Button::down_image(Fl_Image* p_downimage) | ||
14 | { | ||
15 | downimage=p_downimage; | ||
16 | } | ||
17 | |||
18 | Fl_Image* Fl_Image_Repeat_Button::up_image() | ||
19 | { | ||
20 | return upimage; | ||
21 | } | ||
22 | |||
23 | Fl_Image* Fl_Image_Repeat_Button::down_image() | ||
24 | { | ||
25 | return downimage; | ||
26 | } | ||
27 | |||
28 | Fl_Image_Repeat_Button::Fl_Image_Repeat_Button(int a,int b,int c,int d):Fl_Repeat_Button(a,b,c,d) | ||
29 | { | ||
30 | upimage=NULL; | ||
31 | downimage=NULL; | ||
32 | Fl_Repeat_Button::clear_visible_focus(); | ||
33 | } | ||
34 | |||
35 | |||
36 | void Fl_Image_Repeat_Button::draw() | ||
37 | { | ||
38 | // begin - Fl_Button::draw() (box section) | ||
39 | if (type() == FL_HIDDEN_BUTTON) return; | ||
40 | Fl_Color col = value() ? selection_color() : color(); | ||
41 | |||
42 | |||
43 | draw_box(value() ? (down_box()?down_box():fl_down(box())) : box(), col); | ||
44 | // end - Fl_Button::draw() (box section) | ||
45 | |||
46 | // begin - modification to render up/down image | ||
47 | Fl_Boxtype box_; | ||
48 | Fl_Image* pic_; | ||
49 | |||
50 | if(value()) | ||
51 | { | ||
52 | box_ = (down_box())? down_box() : fl_down(box()); | ||
53 | pic_ = downimage; | ||
54 | } | ||
55 | else | ||
56 | { | ||
57 | box_ = box(); | ||
58 | pic_ = upimage; | ||
59 | } | ||
60 | |||
61 | if(pic_) | ||
62 | { | ||
63 | int xx = x() + Fl::box_dx(box_); | ||
64 | int yy = y() + Fl::box_dy(box_); | ||
65 | int ww = w() - Fl::box_dw(box_); | ||
66 | int hh = h() - Fl::box_dh(box_); | ||
67 | int xpos = (ww - pic_->w()) / 2; | ||
68 | int ypos = (hh - pic_->h()) / 2; | ||
69 | |||
70 | fl_push_clip(xx, yy, ww, hh); | ||
71 | pic_->draw(xx + xpos, yy + ypos); | ||
72 | fl_pop_clip(); | ||
73 | } | ||
74 | // end- modification to render up/down image | ||
75 | |||
76 | // begin - Fl_Button::draw() (label section) | ||
77 | if (labeltype() == FL_NORMAL_LABEL && value()) { | ||
78 | Fl_Color c = labelcolor(); | ||
79 | labelcolor(fl_contrast(c, col)); | ||
80 | draw_label(); | ||
81 | labelcolor(c); | ||
82 | } else draw_label(); | ||
83 | if (Fl::focus() == this) draw_focus(); | ||
84 | // end - Fl_Button::draw() (label section) | ||
85 | } | ||
86 | |||
diff --git a/src/lib/FL/Fl_Image_Toggle_Button.H b/src/lib/FL/Fl_Image_Toggle_Button.H new file mode 100644 index 0000000..e5f01a7 --- /dev/null +++ b/src/lib/FL/Fl_Image_Toggle_Button.H | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef __FL_IMAGE_Toggle_Button_H | ||
2 | #define __FL_IMAGE_Toggle_Button_H | ||
3 | #include <FL/Fl_Toggle_Button.H> | ||
4 | #include <FL/Fl.H> | ||
5 | |||
6 | class Fl_Image_Toggle_Button: public Fl_Toggle_Button { | ||
7 | private: | ||
8 | Fl_Image* upimage; | ||
9 | Fl_Image* downimage; | ||
10 | public: | ||
11 | Fl_Image* up_image(); | ||
12 | Fl_Image* down_image(); | ||
13 | void up_image(Fl_Image* p_up_image); | ||
14 | void down_image(Fl_Image* p_down_image); | ||
15 | void draw(); | ||
16 | Fl_Image_Toggle_Button(int a,int b,int c,int d,const char* e); | ||
17 | Fl_Image_Toggle_Button(int a,int b,int c,int d); | ||
18 | }; | ||
19 | |||
20 | #endif | ||
diff --git a/src/lib/FL/Fl_Image_Toggle_Button.cxx b/src/lib/FL/Fl_Image_Toggle_Button.cxx new file mode 100644 index 0000000..df006c8 --- /dev/null +++ b/src/lib/FL/Fl_Image_Toggle_Button.cxx | |||
@@ -0,0 +1,92 @@ | |||
1 | #include <FL/Fl_Image_Toggle_Button.H> | ||
2 | #include <FL/Fl_Image.H> | ||
3 | #include <FL/fl_draw.H> | ||
4 | #ifndef NULL | ||
5 | #define NULL 0 | ||
6 | #endif | ||
7 | void Fl_Image_Toggle_Button::up_image(Fl_Image* p_upimage) | ||
8 | { | ||
9 | upimage=p_upimage; | ||
10 | } | ||
11 | |||
12 | void Fl_Image_Toggle_Button::down_image(Fl_Image* p_downimage) | ||
13 | { | ||
14 | downimage=p_downimage; | ||
15 | } | ||
16 | |||
17 | Fl_Image* Fl_Image_Toggle_Button::up_image() | ||
18 | { | ||
19 | return upimage; | ||
20 | } | ||
21 | |||
22 | Fl_Image* Fl_Image_Toggle_Button::down_image() | ||
23 | { | ||
24 | return downimage; | ||
25 | } | ||
26 | |||
27 | Fl_Image_Toggle_Button::Fl_Image_Toggle_Button(int a,int b,int c,int d,const char* e):Fl_Toggle_Button(a,b,c,d,e) | ||
28 | { | ||
29 | upimage=NULL; | ||
30 | downimage=NULL; | ||
31 | Fl_Toggle_Button::clear_visible_focus(); | ||
32 | } | ||
33 | |||
34 | Fl_Image_Toggle_Button::Fl_Image_Toggle_Button(int a,int b,int c,int d):Fl_Toggle_Button(a,b,c,d) | ||
35 | { | ||
36 | upimage=NULL; | ||
37 | downimage=NULL; | ||
38 | Fl_Toggle_Button::clear_visible_focus(); | ||
39 | } | ||
40 | |||
41 | |||
42 | void Fl_Image_Toggle_Button::draw() | ||
43 | { | ||
44 | // begin - Fl_Button::draw() (box section) | ||
45 | if (type() == FL_HIDDEN_BUTTON) return; | ||
46 | Fl_Color col = value() ? selection_color() : color(); | ||
47 | |||
48 | |||
49 | draw_box(value() ? (down_box()?down_box():fl_down(box())) : box(), col); | ||
50 | // end - Fl_Button::draw() (box section) | ||
51 | |||
52 | // begin - modification to render up/down image | ||
53 | Fl_Boxtype box_; | ||
54 | Fl_Image* pic_; | ||
55 | |||
56 | if(value()) | ||
57 | { | ||
58 | box_ = (down_box())? down_box() : fl_down(box()); | ||
59 | pic_ = downimage; | ||
60 | } | ||
61 | else | ||
62 | { | ||
63 | box_ = box(); | ||
64 | pic_ = upimage; | ||
65 | } | ||
66 | |||
67 | if(pic_) | ||
68 | { | ||
69 | int xx = x() + Fl::box_dx(box_); | ||
70 | int yy = y() + Fl::box_dy(box_); | ||
71 | int ww = w() - Fl::box_dw(box_); | ||
72 | int hh = h() - Fl::box_dh(box_); | ||
73 | int xpos = (ww - pic_->w()) / 2; | ||
74 | int ypos = (hh - pic_->h()) / 2; | ||
75 | |||
76 | fl_push_clip(xx, yy, ww, hh); | ||
77 | pic_->draw(xx + xpos, yy + ypos); | ||
78 | fl_pop_clip(); | ||
79 | } | ||
80 | // end- modification to render up/down image | ||
81 | |||
82 | // begin - Fl_Button::draw() (label section) | ||
83 | if (labeltype() == FL_NORMAL_LABEL && value()) { | ||
84 | Fl_Color c = Fl_Button::labelcolor(); | ||
85 | labelcolor(fl_contrast(c, col)); | ||
86 | draw_label(); | ||
87 | labelcolor(c); | ||
88 | } else draw_label(); | ||
89 | if (Fl::focus() == this) draw_focus(); | ||
90 | // end - Fl_Button::draw() (label section) | ||
91 | } | ||
92 | |||
diff --git a/src/lib/FL/Fl_Native_File_Chooser.H b/src/lib/FL/Fl_Native_File_Chooser.H new file mode 100644 index 0000000..cc5f7bf --- /dev/null +++ b/src/lib/FL/Fl_Native_File_Chooser.H | |||
@@ -0,0 +1,40 @@ | |||
1 | // | ||
2 | // Fl_Native_File_Chooser.H -- FLTK native OS file chooser widget | ||
3 | // | ||
4 | // Copyright 2004 by Greg Ercolano. | ||
5 | // | ||
6 | // This library is free software; you can redistribute it and/or | ||
7 | // modify it under the terms of the GNU Library General Public | ||
8 | // License as published by the Free Software Foundation; either | ||
9 | // version 2 of the License, or (at your option) any later version. | ||
10 | // | ||
11 | // This library is distributed in the hope that it will be useful, | ||
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | // Library General Public License for more details. | ||
15 | // | ||
16 | // You should have received a copy of the GNU Library General Public | ||
17 | // License along with this library; if not, write to the Free Software | ||
18 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
19 | // USA. | ||
20 | // | ||
21 | |||
22 | #ifndef FL_NATIVE_FILE_CHOOSER_H | ||
23 | #define FL_NATIVE_FILE_CHOOSER_H | ||
24 | #include <sys/stat.h> | ||
25 | // Use Windows' chooser | ||
26 | #ifdef _WIN32 | ||
27 | #include <FL/Fl_Native_File_Chooser_WIN32.H> | ||
28 | #endif | ||
29 | |||
30 | // Use Apple's chooser | ||
31 | #ifdef __APPLE__ | ||
32 | #include <FL/Fl_Native_File_Chooser_MAC.H> | ||
33 | #endif | ||
34 | |||
35 | // All else falls back to FLTK's own chooser | ||
36 | #if ! defined(__APPLE__) && !defined(_WIN32) | ||
37 | #include <FL/Fl_Native_File_Chooser_FLTK.H> | ||
38 | #endif | ||
39 | |||
40 | #endif /*FL_NATIVE_FILE_CHOOSER_H*/ | ||
diff --git a/src/lib/FL/Fl_Native_File_Chooser.cxx b/src/lib/FL/Fl_Native_File_Chooser.cxx new file mode 100644 index 0000000..cdc4c27 --- /dev/null +++ b/src/lib/FL/Fl_Native_File_Chooser.cxx | |||
@@ -0,0 +1,44 @@ | |||
1 | // | ||
2 | // Fl_Native_File_Chooser.cxx -- FLTK native OS file chooser widget | ||
3 | // | ||
4 | // Copyright 2004 by Greg Ercolano. | ||
5 | // | ||
6 | // This library is free software; you can redistribute it and/or | ||
7 | // modify it under the terms of the GNU Library General Public | ||
8 | // License as published by the Free Software Foundation; either | ||
9 | // version 2 of the License, or (at your option) any later version. | ||
10 | // | ||
11 | // This library is distributed in the hope that it will be useful, | ||
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | // Library General Public License for more details. | ||
15 | // | ||
16 | // You should have received a copy of the GNU Library General Public | ||
17 | // License along with this library; if not, write to the Free Software | ||
18 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
19 | // USA. | ||
20 | // | ||
21 | // Use Windows' chooser | ||
22 | #ifdef WINDOWS | ||
23 | #ifndef _WIN32 | ||
24 | #define _WIN32 | ||
25 | #endif | ||
26 | #endif | ||
27 | #ifdef DARWIN | ||
28 | #define __APPLE__ | ||
29 | #endif | ||
30 | |||
31 | #ifdef _WIN32 | ||
32 | #include "Fl_Native_File_Chooser_WIN32.cxx" | ||
33 | #endif | ||
34 | |||
35 | // Use Apple's chooser | ||
36 | #ifdef __APPLE__ | ||
37 | #include "Fl_Native_File_Chooser_MAC.cxx" | ||
38 | #endif | ||
39 | |||
40 | // All else falls back to FLTK's own chooser | ||
41 | #if ! defined(__APPLE__) && !defined(_WIN32) | ||
42 | #include "Fl_Native_File_Chooser_FLTK.cxx" | ||
43 | #endif | ||
44 | |||
diff --git a/src/lib/FL/Fl_Native_File_Chooser_FLTK.H b/src/lib/FL/Fl_Native_File_Chooser_FLTK.H new file mode 100644 index 0000000..39e4a4a --- /dev/null +++ b/src/lib/FL/Fl_Native_File_Chooser_FLTK.H | |||
@@ -0,0 +1,89 @@ | |||
1 | // | ||
2 | // Fl_Native_File_Chooser_DEFAULT.H -- FLTK native OS file chooser widget | ||
3 | // | ||
4 | // Copyright 2005 by Nathan Vander Wilt. | ||
5 | // March 2005 - wrapper around Fl_File_Chooser | ||
6 | // | ||
7 | // This library is free software; you can redistribute it and/or | ||
8 | // modify it under the terms of the GNU Library General Public | ||
9 | // License as published by the Free Software Foundation; either | ||
10 | // version 2 of the License, or (at your option) any later version. | ||
11 | // | ||
12 | // This library is distributed in the hope that it will be useful, | ||
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | // Library General Public License for more details. | ||
16 | // | ||
17 | // You should have received a copy of the GNU Library General Public | ||
18 | // License along with this library; if not, write to the Free Software | ||
19 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
20 | // USA. | ||
21 | // | ||
22 | |||
23 | // Use FLTK BROWSER | ||
24 | #include <FL/Fl_File_Chooser.H> | ||
25 | #include <string.h> | ||
26 | |||
27 | class Fl_Native_File_Chooser { | ||
28 | public: | ||
29 | enum Type { | ||
30 | BROWSE_FILE = 0, | ||
31 | BROWSE_DIRECTORY, | ||
32 | BROWSE_MULTI_FILE, | ||
33 | BROWSE_MULTI_DIRECTORY, | ||
34 | BROWSE_SAVE_FILE, | ||
35 | BROWSE_SAVE_DIRECTORY | ||
36 | }; | ||
37 | enum Option { | ||
38 | NO_OPTIONS = 0x0000, // no options enabled | ||
39 | SAVEAS_CONFIRM = 0x0001, // Show native 'Save As' overwrite | ||
40 | // confirm dialog (if supported) | ||
41 | NEW_FOLDER = 0x0002, // Show 'New Folder' icon | ||
42 | // (if supported) | ||
43 | PREVIEW = 0x0004 // enable preview mode | ||
44 | }; | ||
45 | private: | ||
46 | int _btype; // kind-of browser to show() | ||
47 | int _options; // general options | ||
48 | char *_filter; // user supplied filter | ||
49 | char *_parsedfilt; // parsed filter | ||
50 | int _filtvalue; // selected filter | ||
51 | char *_preset_file; | ||
52 | char *_prevvalue; // Returned filename | ||
53 | char *_directory; | ||
54 | char *_errmsg; // error message | ||
55 | Fl_File_Chooser *file_chooser; | ||
56 | int _nfilters; | ||
57 | |||
58 | // Private methods | ||
59 | void errmsg(const char *msg); | ||
60 | int type_fl_file(int); | ||
61 | void parse_filter(); | ||
62 | void keeplocation(); | ||
63 | |||
64 | public: | ||
65 | Fl_Native_File_Chooser(int val=BROWSE_FILE); | ||
66 | ~Fl_Native_File_Chooser(); | ||
67 | |||
68 | // Public methods | ||
69 | void type(int); | ||
70 | int type() const; | ||
71 | void options(int); | ||
72 | int options() const; | ||
73 | int count() const; | ||
74 | const char *filename() const; | ||
75 | const char *filename(int i) const; | ||
76 | void directory(const char *val); | ||
77 | const char *directory() const; | ||
78 | void title(const char *); | ||
79 | const char* title() const; | ||
80 | const char *filter() const; | ||
81 | void filter(const char *); | ||
82 | int filters() const { return(_nfilters); } | ||
83 | void filter_value(int i); | ||
84 | int filter_value() const; | ||
85 | void preset_file(const char*); | ||
86 | const char* preset_file() const; | ||
87 | const char *errmsg() const; | ||
88 | int show(); | ||
89 | }; | ||
diff --git a/src/lib/FL/Fl_Native_File_Chooser_FLTK.cxx b/src/lib/FL/Fl_Native_File_Chooser_FLTK.cxx new file mode 100644 index 0000000..5d9c1fd --- /dev/null +++ b/src/lib/FL/Fl_Native_File_Chooser_FLTK.cxx | |||
@@ -0,0 +1,339 @@ | |||
1 | // | ||
2 | // Fl_Native_File_Chooser_DEFAULT.cxx -- FLTK native OS file chooser widget | ||
3 | // March 2005 - wrapper around Fl_File_Chooser by natevw | ||
4 | // | ||
5 | // Copyright 2005 by Nathan Vander Wilt. | ||
6 | // | ||
7 | // | ||
8 | // This library is free software; you can redistribute it and/or | ||
9 | // modify it under the terms of the GNU Library General Public | ||
10 | // License as published by the Free Software Foundation; either | ||
11 | // version 2 of the License, or (at your option) any later version. | ||
12 | // | ||
13 | // This library is distributed in the hope that it will be useful, | ||
14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | // Library General Public License for more details. | ||
17 | // | ||
18 | // You should have received a copy of the GNU Library General Public | ||
19 | // License along with this library; if not, write to the Free Software | ||
20 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
21 | // USA. | ||
22 | // | ||
23 | // Please keep code 80 column compliant. | ||
24 | // | ||
25 | // 10 20 30 40 50 60 70 | ||
26 | // | | | | | | | | ||
27 | // 4567890123456789012345678901234567890123456789012345678901234567890123456789 | ||
28 | // | ||
29 | #include <Fl/x.H> | ||
30 | #include <FL/Fl_File_Icon.H> | ||
31 | #include <FL/Fl_Native_File_Chooser.H> | ||
32 | #include "common.cxx" | ||
33 | |||
34 | static int G_init = 0; // 'first time' initialize flag | ||
35 | |||
36 | // CTOR | ||
37 | Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { | ||
38 | if ( G_init == 0 ) { | ||
39 | // Initialize when instanced for first time | ||
40 | // Fl_File_Icon::load_system_icons(); // OK to call more than once | ||
41 | G_init = 1; // eg. if app already called from main() | ||
42 | } | ||
43 | _btype = val; | ||
44 | _options = NO_OPTIONS; | ||
45 | _filter = NULL; | ||
46 | _parsedfilt = NULL; | ||
47 | _preset_file = NULL; | ||
48 | _prevvalue = NULL; | ||
49 | _directory = NULL; | ||
50 | _errmsg = NULL; | ||
51 | file_chooser = new Fl_File_Chooser(NULL, NULL, 0, NULL); | ||
52 | type(val); // do this after file_chooser created | ||
53 | _nfilters = 0; | ||
54 | } | ||
55 | |||
56 | // DTOR | ||
57 | Fl_Native_File_Chooser::~Fl_Native_File_Chooser() { | ||
58 | delete file_chooser; | ||
59 | _filter = strfree(_filter); | ||
60 | _parsedfilt = strfree(_parsedfilt); | ||
61 | _preset_file = strfree(_preset_file); | ||
62 | _prevvalue = strfree(_prevvalue); | ||
63 | _directory = strfree(_directory); | ||
64 | _errmsg = strfree(_errmsg); | ||
65 | } | ||
66 | |||
67 | // PRIVATE: SET ERROR MESSAGE | ||
68 | void Fl_Native_File_Chooser::errmsg(const char *msg) { | ||
69 | _errmsg = strfree(_errmsg); | ||
70 | _errmsg = strnew(msg); | ||
71 | } | ||
72 | |||
73 | // PRIVATE: translate Native types to Fl_File_Chooser types | ||
74 | int Fl_Native_File_Chooser::type_fl_file(int val) { | ||
75 | switch (val) { | ||
76 | case BROWSE_FILE: | ||
77 | return(Fl_File_Chooser::SINGLE); | ||
78 | case BROWSE_DIRECTORY: | ||
79 | return(Fl_File_Chooser::SINGLE | Fl_File_Chooser::DIRECTORY); | ||
80 | case BROWSE_MULTI_FILE: | ||
81 | return(Fl_File_Chooser::MULTI); | ||
82 | case BROWSE_MULTI_DIRECTORY: | ||
83 | return(Fl_File_Chooser::DIRECTORY | Fl_File_Chooser::MULTI); | ||
84 | case BROWSE_SAVE_FILE: | ||
85 | return(Fl_File_Chooser::SINGLE | Fl_File_Chooser::CREATE); | ||
86 | case BROWSE_SAVE_DIRECTORY: | ||
87 | return(Fl_File_Chooser::DIRECTORY | Fl_File_Chooser::SINGLE | Fl_File_Chooser::CREATE); | ||
88 | default: | ||
89 | return(Fl_File_Chooser::SINGLE); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | void Fl_Native_File_Chooser::type(int val) { | ||
94 | _btype = val; | ||
95 | file_chooser->type(type_fl_file(val)); | ||
96 | } | ||
97 | |||
98 | int Fl_Native_File_Chooser::type() const { | ||
99 | return(_btype); | ||
100 | } | ||
101 | |||
102 | // SET OPTIONS | ||
103 | void Fl_Native_File_Chooser::options(int val) { | ||
104 | _options = val; | ||
105 | } | ||
106 | |||
107 | // GET OPTIONS | ||
108 | int Fl_Native_File_Chooser::options() const { | ||
109 | return(_options); | ||
110 | } | ||
111 | |||
112 | // Show chooser, blocks until done. | ||
113 | // RETURNS: | ||
114 | // 0 - user picked a file | ||
115 | // 1 - user cancelled | ||
116 | // -1 - failed; errmsg() has reason | ||
117 | // | ||
118 | int Fl_Native_File_Chooser::show() { | ||
119 | // FILTER | ||
120 | if ( _parsedfilt ) { | ||
121 | file_chooser->filter(_parsedfilt); | ||
122 | } | ||
123 | |||
124 | // FILTER VALUE | ||
125 | // Set this /after/ setting the filter | ||
126 | // | ||
127 | if (_filtvalue!=-1) | ||
128 | { | ||
129 | file_chooser->filter_value(_filtvalue); | ||
130 | } | ||
131 | |||
132 | // DIRECTORY | ||
133 | if ( _directory && _directory[0] ) { | ||
134 | file_chooser->directory(_directory); | ||
135 | } else { | ||
136 | file_chooser->directory(_prevvalue); | ||
137 | } | ||
138 | |||
139 | // PRESET FILE | ||
140 | if ( _preset_file ) { | ||
141 | file_chooser->value(_preset_file); | ||
142 | } | ||
143 | |||
144 | // OPTIONS: PREVIEW | ||
145 | file_chooser->preview( (options() & PREVIEW) ? 1 : 0); | ||
146 | |||
147 | // OPTIONS: NEW FOLDER | ||
148 | if ( options() & NEW_FOLDER ) | ||
149 | file_chooser->type(file_chooser->type() | Fl_File_Chooser::CREATE); // on | ||
150 | |||
151 | // SHOW | ||
152 | file_chooser->show(); | ||
153 | |||
154 | while ( file_chooser->shown() ) { | ||
155 | Fl::wait(); // block while shown | ||
156 | } | ||
157 | |||
158 | if ( file_chooser->value() && file_chooser->value()[0] ) { | ||
159 | _prevvalue = strfree(_prevvalue); | ||
160 | _prevvalue = strnew(file_chooser->value()); | ||
161 | _filtvalue = file_chooser->filter_value(); // update filter value | ||
162 | |||
163 | // HANDLE SHOWING 'SaveAs' CONFIRM | ||
164 | if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) { | ||
165 | struct stat buf; | ||
166 | if ( stat(file_chooser->value(), &buf) != -1 ) { | ||
167 | if ( buf.st_mode & S_IFREG ) { // Regular file + exists? | ||
168 | if ( fl_choice("File exists. Are you sure you want to overwrite?", "Cancel", " OK ", NULL) == 0 ) { | ||
169 | return(1); | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | if ( file_chooser->count() ) return(0); | ||
177 | else return(1); | ||
178 | } | ||
179 | |||
180 | // RETURN ERROR MESSAGE | ||
181 | const char *Fl_Native_File_Chooser::errmsg() const { | ||
182 | return(_errmsg ? _errmsg : "No error"); | ||
183 | } | ||
184 | |||
185 | // GET FILENAME | ||
186 | const char* Fl_Native_File_Chooser::filename() const { | ||
187 | if ( file_chooser->count() > 0 ) return(file_chooser->value()); | ||
188 | return(""); | ||
189 | } | ||
190 | |||
191 | // GET FILENAME FROM LIST OF FILENAMES | ||
192 | const char* Fl_Native_File_Chooser::filename(int i) const { | ||
193 | if ( i < file_chooser->count() ) return(file_chooser->value(i+1)); // convert fltk 1 based to our 0 based | ||
194 | return(""); | ||
195 | } | ||
196 | |||
197 | // SET TITLE | ||
198 | // Can be NULL if no title desired. | ||
199 | // | ||
200 | void Fl_Native_File_Chooser::title(const char *val) { | ||
201 | file_chooser->label(val); | ||
202 | } | ||
203 | |||
204 | // GET TITLE | ||
205 | // Can return NULL if none set. | ||
206 | // | ||
207 | const char *Fl_Native_File_Chooser::title() const { | ||
208 | return(file_chooser->label()); | ||
209 | } | ||
210 | |||
211 | // SET FILTER | ||
212 | // Can be NULL if no filter needed | ||
213 | // | ||
214 | void Fl_Native_File_Chooser::filter(const char *val) { | ||
215 | _filter = strfree(_filter); | ||
216 | _filter = strnew(val); | ||
217 | parse_filter(); | ||
218 | } | ||
219 | |||
220 | // GET FILTER | ||
221 | const char *Fl_Native_File_Chooser::filter() const { | ||
222 | return(_filter); | ||
223 | } | ||
224 | |||
225 | // SET SELECTED FILTER | ||
226 | void Fl_Native_File_Chooser::filter_value(int val) { | ||
227 | _filtvalue = val; | ||
228 | } | ||
229 | |||
230 | // RETURN SELECTED FILTER | ||
231 | int Fl_Native_File_Chooser::filter_value() const { | ||
232 | return(_filtvalue); | ||
233 | } | ||
234 | |||
235 | // GET TOTAL FILENAMES CHOSEN | ||
236 | int Fl_Native_File_Chooser::count() const { | ||
237 | return(file_chooser->count()); | ||
238 | } | ||
239 | |||
240 | // PRESET PATHNAME | ||
241 | // Can be NULL if no preset is desired. | ||
242 | // | ||
243 | void Fl_Native_File_Chooser::directory(const char *val) { | ||
244 | _directory = strfree(_directory); | ||
245 | _directory = strnew(val); | ||
246 | } | ||
247 | |||
248 | // GET PRESET PATHNAME | ||
249 | // Can return NULL if none set. | ||
250 | // | ||
251 | const char *Fl_Native_File_Chooser::directory() const { | ||
252 | return(_directory); | ||
253 | } | ||
254 | |||
255 | // Convert our filter format to Fl_File_Chooser's format | ||
256 | // FROM TO (FLTK) | ||
257 | // ------------------------- -------------------------- | ||
258 | // "*.cxx" "*.cxx Files(*.cxx)" | ||
259 | // "C Files\t*.{cxx,h}" "C Files(*.{cxx,h})" | ||
260 | // "C Files\t*.{cxx,h}\nText Files\t*.txt" "C Files(*.{cxx,h})\tText Files(*.txt)" | ||
261 | // | ||
262 | // Returns a modified version of the filter that the caller is responsible | ||
263 | // for freeing with strfree(). | ||
264 | // | ||
265 | void Fl_Native_File_Chooser::parse_filter() { | ||
266 | _parsedfilt = strfree(_parsedfilt); // clear previous parsed filter (if any) | ||
267 | _nfilters = 0; | ||
268 | char *in = _filter; | ||
269 | if ( !in ) return; | ||
270 | |||
271 | int has_name = strchr(in, '\t') ? 1 : 0; | ||
272 | |||
273 | char mode = has_name ? 'n' : 'w'; // parse mode: n=title, w=wildcard | ||
274 | char wildcard[1024] = ""; // parsed wildcard | ||
275 | char name[1024] = ""; | ||
276 | |||
277 | // Parse filter user specified | ||
278 | for ( ; 1; in++ ) { | ||
279 | |||
280 | /*** DEBUG | ||
281 | printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n", | ||
282 | *in, mode, name, wildcard); | ||
283 | ***/ | ||
284 | |||
285 | switch (*in) { | ||
286 | // FINISHED PARSING NAME? | ||
287 | case '\t': | ||
288 | if ( mode != 'n' ) goto regchar; | ||
289 | mode = 'w'; | ||
290 | break; | ||
291 | |||
292 | // ESCAPE NEXT CHAR | ||
293 | case '\\': | ||
294 | ++in; | ||
295 | goto regchar; | ||
296 | |||
297 | // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS? | ||
298 | case '\r': | ||
299 | case '\n': | ||
300 | case '\0': | ||
301 | // APPEND NEW FILTER TO LIST | ||
302 | if ( wildcard[0] ) { | ||
303 | // OUT: "name(wild)\tname(wild)" | ||
304 | char comp[2048]; | ||
305 | sprintf(comp, "%s%.511s(%.511s)", ((_parsedfilt)?"\t":""), name, wildcard); | ||
306 | _parsedfilt = strapp(_parsedfilt, comp); | ||
307 | _nfilters++; | ||
308 | //DEBUG printf("DEBUG: PARSED FILT NOW <%s>\n", _parsedfilt); | ||
309 | } | ||
310 | // RESET | ||
311 | wildcard[0] = name[0] = '\0'; | ||
312 | mode = strchr(in, '\t') ? 'n' : 'w'; | ||
313 | // DONE? | ||
314 | if ( *in == '\0' ) return; // done | ||
315 | else continue; // not done yet, more filters | ||
316 | |||
317 | // Parse all other chars | ||
318 | default: // handle all non-special chars | ||
319 | regchar: // handle regular char | ||
320 | switch ( mode ) { | ||
321 | case 'n': chrcat(name, *in); continue; | ||
322 | case 'w': chrcat(wildcard, *in); continue; | ||
323 | } | ||
324 | break; | ||
325 | } | ||
326 | } | ||
327 | //NOTREACHED | ||
328 | } | ||
329 | |||
330 | // SET PRESET FILENAME | ||
331 | void Fl_Native_File_Chooser::preset_file(const char* val) { | ||
332 | _preset_file = strfree(_preset_file); | ||
333 | _preset_file = strnew(val); | ||
334 | } | ||
335 | |||
336 | // GET PRESET FILENAME | ||
337 | const char* Fl_Native_File_Chooser::preset_file() const { | ||
338 | return(_preset_file); | ||
339 | } | ||
diff --git a/src/lib/FL/Fl_Native_File_Chooser_MAC.H b/src/lib/FL/Fl_Native_File_Chooser_MAC.H new file mode 100644 index 0000000..49577c4 --- /dev/null +++ b/src/lib/FL/Fl_Native_File_Chooser_MAC.H | |||
@@ -0,0 +1,138 @@ | |||
1 | // | ||
2 | // Fl_Native_File_Chooser_MAC.H -- FLTK native OS file chooser widget | ||
3 | // | ||
4 | // Copyright 2004 by Greg Ercolano. | ||
5 | // | ||
6 | // This library is free software; you can redistribute it and/or | ||
7 | // modify it under the terms of the GNU Library General Public | ||
8 | // License as published by the Free Software Foundation; either | ||
9 | // version 2 of the License, or (at your option) any later version. | ||
10 | // | ||
11 | // This library is distributed in the hope that it will be useful, | ||
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | // Library General Public License for more details. | ||
15 | // | ||
16 | // You should have received a copy of the GNU Library General Public | ||
17 | // License along with this library; if not, write to the Free Software | ||
18 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
19 | // USA. | ||
20 | // | ||
21 | // 10 20 30 40 50 60 70 | ||
22 | // | | | | | | | | ||
23 | // 4567890123456789012345678901234567890123456789012345678901234567890123456789 | ||
24 | |||
25 | // OSX-SPECIFIC NATIVE BROWSER | ||
26 | #ifdef __APPLE_CC__ | ||
27 | #include <Carbon/Carbon.h> | ||
28 | #else | ||
29 | #include <Carbon.h> | ||
30 | #endif | ||
31 | |||
32 | #include <FL/filename.H> | ||
33 | #define MAXFILTERS 80 | ||
34 | |||
35 | class Fl_Native_File_Chooser { | ||
36 | public: | ||
37 | enum Type { | ||
38 | BROWSE_FILE = 0, | ||
39 | BROWSE_DIRECTORY, | ||
40 | BROWSE_MULTI_FILE, | ||
41 | BROWSE_MULTI_DIRECTORY, | ||
42 | BROWSE_SAVE_FILE, | ||
43 | BROWSE_SAVE_DIRECTORY | ||
44 | }; | ||
45 | enum Option { | ||
46 | NO_OPTIONS = 0x0000, // no options enabled | ||
47 | SAVEAS_CONFIRM = 0x0001, // Show native 'Save As' overwrite | ||
48 | // confirm dialog (if supported) | ||
49 | NEW_FOLDER = 0x0002, // Show 'New Folder' icon | ||
50 | // (if supported) | ||
51 | PREVIEW = 0x0004, // enable preview mode | ||
52 | }; | ||
53 | protected: | ||
54 | NavDialogCreationOptions _opts; // file navigation options | ||
55 | private: | ||
56 | int _btype; // kind-of browser to show() | ||
57 | int _options; // general options | ||
58 | NavDialogRef _ref; // file navigation reference | ||
59 | NavActionState _keepstate; // holds button permissions | ||
60 | NavMenuItemSpec _tempitem; // Popup menu selection | ||
61 | char **_pathnames; // array of pathnames | ||
62 | int _tpathnames; // total pathnames | ||
63 | char *_directory; // default pathname to use | ||
64 | char *_title; // title for window | ||
65 | char *_preset_file; // the 'save as' filename | ||
66 | |||
67 | char *_filter; // user-side search filter, eg: | ||
68 | // C Files\t*.[ch]\nText Files\t*.txt" | ||
69 | |||
70 | char *_filt_names; // filter names (tab delimited) | ||
71 | // eg. "C Files\tText Files" | ||
72 | |||
73 | char *_filt_patt[MAXFILTERS]; | ||
74 | // array of filter patterns, eg: | ||
75 | // _filt_patt[0]="*.{cxx,h}" | ||
76 | // _filt_patt[1]="*.txt" | ||
77 | |||
78 | int _filt_total; // parse_filter() # of filters loaded | ||
79 | int _filt_value; // index of the selected filter | ||
80 | char *_errmsg; // error message | ||
81 | |||
82 | // PRIVATE CLASS TO HANDLE NAVIGATION DIALOG REPLY STRUCT | ||
83 | // Class-ified, mainly to ensure proper cleanup. | ||
84 | // | ||
85 | class NavReply { | ||
86 | int _valid_reply; | ||
87 | NavReplyRecord _reply; | ||
88 | public: | ||
89 | NavReply(); | ||
90 | ~NavReply(); | ||
91 | int get_reply(NavDialogRef& ref); | ||
92 | int get_saveas_basename(char *s, int slen); | ||
93 | int get_dirname(char *s, int slen); | ||
94 | int get_pathnames(char **&pathnames, int& tpathnames); | ||
95 | }; | ||
96 | |||
97 | // Private methods | ||
98 | void errmsg(const char *msg); | ||
99 | void clear_pathnames(); | ||
100 | void set_single_pathname(const char *s); | ||
101 | int get_saveas_basename(NavDialogRef& ref); | ||
102 | int get_pathnames(NavDialogRef& ref); | ||
103 | static void event_handler(NavEventCallbackMessage callBackSelector, | ||
104 | NavCBRecPtr cbparm, void *data); | ||
105 | |||
106 | void clear_filters(); | ||
107 | void add_filter(const char *, const char *); | ||
108 | void parse_filter(const char *from); | ||
109 | static Boolean filter_proc_cb(AEDesc *, void *, void *, NavFilterModes); | ||
110 | Boolean filter_proc_cb2(AEDesc*, void*, void*, NavFilterModes); | ||
111 | int post(); | ||
112 | |||
113 | public: | ||
114 | Fl_Native_File_Chooser(int val = BROWSE_FILE); | ||
115 | ~Fl_Native_File_Chooser(); | ||
116 | |||
117 | // Public methods | ||
118 | void type(int); | ||
119 | int type() const; | ||
120 | void options(int); | ||
121 | int options() const; | ||
122 | int count() const; | ||
123 | const char *filename() const; | ||
124 | const char *filename(int i) const; | ||
125 | void directory(const char *); | ||
126 | const char *directory() const; | ||
127 | void title(const char *); | ||
128 | const char *title() const; | ||
129 | const char *filter() const; | ||
130 | void filter(const char *); | ||
131 | void filter_value(int i) { _filt_value = i; } | ||
132 | int filter_value() { return(_filt_value); } | ||
133 | int filters() { return(_filt_total); } | ||
134 | void preset_file(const char *); | ||
135 | const char *preset_file(); | ||
136 | const char *errmsg() const; | ||
137 | int show(); | ||
138 | }; | ||
diff --git a/src/lib/FL/Fl_Native_File_Chooser_MAC.cxx b/src/lib/FL/Fl_Native_File_Chooser_MAC.cxx new file mode 100644 index 0000000..e556edf --- /dev/null +++ b/src/lib/FL/Fl_Native_File_Chooser_MAC.cxx | |||
@@ -0,0 +1,833 @@ | |||
1 | // | ||
2 | // Fl_Native_File_Chooser_MAC.cxx -- FLTK native OS file chooser widget | ||
3 | // | ||
4 | // Copyright 2004 by Greg Ercolano. | ||
5 | // | ||
6 | // This library is free software; you can redistribute it and/or | ||
7 | // modify it under the terms of the GNU Library General Public | ||
8 | // License as published by the Free Software Foundation; either | ||
9 | // version 2 of the License, or (at your option) any later version. | ||
10 | // | ||
11 | // This library is distributed in the hope that it will be useful, | ||
12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | // Library General Public License for more details. | ||
15 | // | ||
16 | // You should have received a copy of the GNU Library General Public | ||
17 | // License along with this library; if not, write to the Free Software | ||
18 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
19 | // USA. | ||
20 | // | ||
21 | // Please keep code 80 column compliant. | ||
22 | // | ||
23 | // 10 20 30 40 50 60 70 | ||
24 | // | | | | | | | | ||
25 | // 4567890123456789012345678901234567890123456789012345678901234567890123456789 | ||
26 | // | ||
27 | // TODO: | ||
28 | // o When doing 'open file', only dir is preset, not filename. | ||
29 | // Possibly 'preset_file' could be used to select the filename. | ||
30 | // | ||
31 | #include <FL/Fl.H> | ||
32 | #include <FL/Fl_Native_File_Chooser.H> | ||
33 | #include "common.cxx" // strnew/strfree/strapp/chrcat | ||
34 | |||
35 | // TRY TO CONVERT AN AEDesc TO AN FSSpec | ||
36 | // As per Apple Technical Q&A QA1274 | ||
37 | // eg: http://developer.apple.com/qa/qa2001/qa1274.html | ||
38 | // Returns 'noErr' if OK, | ||
39 | // or an 'OSX result code' on error. | ||
40 | // | ||
41 | static int AEDescToFSSpec(const AEDesc* desc, FSSpec* fsspec) { | ||
42 | OSStatus err = noErr; | ||
43 | AEDesc coerceDesc; | ||
44 | // If AEDesc isn't already an FSSpec, convert it to one | ||
45 | if ( desc->descriptorType != typeFSS ) { | ||
46 | if ( ( err = AECoerceDesc(desc, typeFSS, &coerceDesc) ) == noErr ) { | ||
47 | // Get FSSpec out of AEDesc | ||
48 | err = AEGetDescData(&coerceDesc, fsspec, sizeof(FSSpec)); | ||
49 | AEDisposeDesc(&coerceDesc); | ||
50 | } | ||
51 | } else { | ||
52 | err = AEGetDescData(desc, fsspec, sizeof(FSSpec)); | ||
53 | } | ||
54 | return( err ); | ||
55 | } | ||
56 | |||
57 | // CONVERT AN FSSpec TO A PATHNAME | ||
58 | static void FSSpecToPath(const FSSpec &spec, char *buff, int bufflen) { | ||
59 | FSRef fsRef; | ||
60 | FSpMakeFSRef(&spec, &fsRef); | ||
61 | FSRefMakePath(&fsRef, (UInt8*)buff, bufflen); | ||
62 | } | ||
63 | |||
64 | // CONVERT REGULAR PATH -> FSSpec | ||
65 | // If file does not exist, expect fnfErr. | ||
66 | // Returns 'noErr' if OK, | ||
67 | // or an 'OSX result code' on error. | ||
68 | // | ||
69 | static OSStatus PathToFSSpec(const char *path, FSSpec &spec) { | ||
70 | OSStatus err; | ||
71 | FSRef ref; | ||
72 | if ((err = FSPathMakeRef((const UInt8*)path, &ref, NULL)) != noErr) { | ||
73 | return(err); | ||
74 | } | ||
75 | // FSRef -> FSSpec | ||
76 | if ((err = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, &spec, | ||
77 | NULL)) != noErr) { | ||
78 | return(err); | ||
79 | } | ||
80 | return(noErr); | ||
81 | } | ||
82 | |||
83 | // NAVREPLY: CTOR | ||
84 | Fl_Native_File_Chooser::NavReply::NavReply() { | ||
85 | _valid_reply = 0; | ||
86 | } | ||
87 | |||
88 | // NAVREPLY: DTOR | ||
89 | Fl_Native_File_Chooser::NavReply::~NavReply() { | ||
90 | if ( _valid_reply ) { | ||
91 | NavDisposeReply(&_reply); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | // GET REPLY FROM THE NAV* DIALOG | ||
96 | int Fl_Native_File_Chooser::NavReply::get_reply(NavDialogRef& ref) { | ||
97 | if ( _valid_reply ) { | ||
98 | NavDisposeReply(&_reply); // dispose of previous | ||
99 | _valid_reply = 0; | ||
100 | } | ||
101 | if ( ref == NULL || NavDialogGetReply(ref, &_reply) != noErr ) { | ||
102 | return(-1); | ||
103 | } | ||
104 | _valid_reply = 1; | ||
105 | return(0); | ||
106 | } | ||
107 | |||
108 | // RETURN THE BASENAME USER WANTS TO 'Save As' | ||
109 | int Fl_Native_File_Chooser::NavReply::get_saveas_basename(char *s, int slen) { | ||
110 | if (CFStringGetCString(_reply.saveFileName, s, slen-1, | ||
111 | kCFStringEncodingUTF8) == false) { | ||
112 | s[0] = '\0'; | ||
113 | return(-1); | ||
114 | } | ||
115 | return(0); | ||
116 | } | ||
117 | |||
118 | // RETURN THE DIRECTORY NAME | ||
119 | // Returns 0 on success, -1 on error. | ||
120 | // | ||
121 | int Fl_Native_File_Chooser::NavReply::get_dirname(char *s, int slen) { | ||
122 | FSSpec fsspec; | ||
123 | if ( AEDescToFSSpec(&_reply.selection, &fsspec) != noErr ) { | ||
124 | // Conversion failed? Return empty name | ||
125 | s[0] = 0; | ||
126 | return(-1); | ||
127 | } | ||
128 | FSSpecToPath(fsspec, s, slen); | ||
129 | return(0); | ||
130 | } | ||
131 | |||
132 | // RETURN MULTIPLE DIRECTORIES | ||
133 | // Returns: 0 on success with pathnames[] containing pathnames selected, | ||
134 | // -1 on error | ||
135 | // | ||
136 | int Fl_Native_File_Chooser::NavReply::get_pathnames(char **&pathnames, | ||
137 | int& tpathnames) { | ||
138 | // How many items selected? | ||
139 | long count = 0; | ||
140 | if ( AECountItems(&_reply.selection, &count) != noErr ) | ||
141 | { return(-1); } | ||
142 | |||
143 | // Allocate space for that many pathnames | ||
144 | pathnames = new char*[count]; | ||
145 | memset((void*)pathnames, 0, count*sizeof(char*)); | ||
146 | tpathnames = count; | ||
147 | |||
148 | // Walk list of pathnames selected | ||
149 | for (short index=1; index<=count; index++) { | ||
150 | AEKeyword keyWord; | ||
151 | AEDesc desc; | ||
152 | if (AEGetNthDesc(&_reply.selection, index, typeFSS, &keyWord, | ||
153 | &desc) != noErr) { | ||
154 | pathnames[index-1] = strnew(""); | ||
155 | continue; | ||
156 | } | ||
157 | FSSpec fsspec; | ||
158 | if (AEGetDescData(&desc, &fsspec, sizeof(FSSpec)) != noErr ) { | ||
159 | pathnames[index-1] = strnew(""); | ||
160 | continue; | ||
161 | } | ||
162 | char s[4096]; | ||
163 | FSSpecToPath(fsspec, s, sizeof(s)-1); | ||
164 | pathnames[index-1] = strnew(s); | ||
165 | AEDisposeDesc(&desc); | ||
166 | } | ||
167 | return(0); | ||
168 | } | ||
169 | |||
170 | // FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS | ||
171 | void Fl_Native_File_Chooser::clear_pathnames() { | ||
172 | if ( _pathnames ) { | ||
173 | while ( --_tpathnames >= 0 ) { | ||
174 | _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]); | ||
175 | } | ||
176 | delete [] _pathnames; | ||
177 | _pathnames = NULL; | ||
178 | } | ||
179 | _tpathnames = 0; | ||
180 | } | ||
181 | |||
182 | // SET A SINGLE PATHNAME | ||
183 | void Fl_Native_File_Chooser::set_single_pathname(const char *s) { | ||
184 | clear_pathnames(); | ||
185 | _pathnames = new char*[1]; | ||
186 | _pathnames[0] = strnew(s); | ||
187 | _tpathnames = 1; | ||
188 | } | ||
189 | |||
190 | // GET THE 'Save As' FILENAME | ||
191 | // Returns -1 on error, errmsg() has reason, filename == "". | ||
192 | // 0 if OK, filename() has filename chosen. | ||
193 | // | ||
194 | int Fl_Native_File_Chooser::get_saveas_basename(NavDialogRef& ref) { | ||
195 | if ( ref == NULL ) { | ||
196 | errmsg("get_saveas_basename: ref is NULL"); | ||
197 | return(-1); | ||
198 | } | ||
199 | NavReply reply; | ||
200 | OSStatus err; | ||
201 | if ((err = reply.get_reply(ref)) != noErr ) { | ||
202 | errmsg("NavReply::get_reply() failed"); | ||
203 | clear_pathnames(); | ||
204 | return(-1); | ||
205 | } | ||
206 | |||
207 | char pathname[4096] = ""; | ||
208 | // Directory name.. | ||
209 | // -2 leaves room to append '/' | ||
210 | // | ||
211 | if ( reply.get_dirname(pathname, sizeof(pathname)-2) < 0 ) { | ||
212 | clear_pathnames(); | ||
213 | errmsg("NavReply::get_dirname() failed"); | ||
214 | return(-1); | ||
215 | } | ||
216 | // Append '/' | ||
217 | int len = strlen(pathname); | ||
218 | pathname[len++] = '/'; | ||
219 | pathname[len] = '\0'; | ||
220 | // Basename.. | ||
221 | if ( reply.get_saveas_basename(pathname+len, sizeof(pathname)-len) < 0 ) { | ||
222 | clear_pathnames(); | ||
223 | errmsg("NavReply::get_saveas_basename() failed"); | ||
224 | return(-1); | ||
225 | } | ||
226 | set_single_pathname(pathname); | ||
227 | return(0); | ||
228 | } | ||
229 | |||
230 | // GET (POTENTIALLY) MULTIPLE FILENAMES | ||
231 | // Returns: | ||
232 | // -1 -- error, errmsg() has reason, filename == "" | ||
233 | // 0 -- OK, pathnames()/filename() has pathname(s) chosen | ||
234 | // | ||
235 | int Fl_Native_File_Chooser::get_pathnames(NavDialogRef& ref) { | ||
236 | if ( ref == NULL ) { | ||
237 | errmsg("get_saveas_basename: ref is NULL"); | ||
238 | return(-1); | ||
239 | } | ||
240 | NavReply reply; | ||
241 | OSStatus err; | ||
242 | if ((err = reply.get_reply(ref)) != noErr ) { | ||
243 | errmsg("NavReply::get_reply() failed"); | ||
244 | clear_pathnames(); | ||
245 | return(-1); | ||
246 | } | ||
247 | // First, clear pathnames array of any previous contents | ||
248 | clear_pathnames(); | ||
249 | if ( reply.get_pathnames(_pathnames, _tpathnames) < 0 ) { | ||
250 | clear_pathnames(); | ||
251 | errmsg("NavReply::get_dirname() failed"); | ||
252 | return(-1); | ||
253 | } | ||
254 | return(0); | ||
255 | } | ||
256 | |||
257 | // NAV CALLBACK EVENT HANDLER | ||
258 | void Fl_Native_File_Chooser::event_handler( | ||
259 | NavEventCallbackMessage callBackSelector, | ||
260 | NavCBRecPtr cbparm, | ||
261 | void *data) { | ||
262 | OSStatus err; | ||
263 | Fl_Native_File_Chooser *nfb = (Fl_Native_File_Chooser*)data; | ||
264 | switch (callBackSelector) { | ||
265 | case kNavCBStart: | ||
266 | if ( nfb->directory() || nfb->preset_file() ) { | ||
267 | const char *pathname = nfb->directory() ? nfb->directory() : nfb->preset_file(); | ||
268 | FSSpec spec; | ||
269 | if ( ( err = PathToFSSpec(pathname, spec) ) != noErr ) { | ||
270 | fprintf(stderr, "PathToFSSpec(%s) failed: err=%d\n", | ||
271 | pathname, (int)err); | ||
272 | break; | ||
273 | } | ||
274 | AEDesc desc; | ||
275 | if ((err = AECreateDesc(typeFSS, | ||
276 | &spec, sizeof(FSSpec), &desc)) != noErr) { | ||
277 | fprintf(stderr, "AECreateDesc() failed: err=%d\n", | ||
278 | (int)err); | ||
279 | } | ||
280 | if ((err = NavCustomControl(cbparm->context, | ||
281 | kNavCtlSetLocation, &desc)) != noErr) { | ||
282 | fprintf(stderr, "NavCustomControl() failed: err=%d\n", | ||
283 | (int)err); | ||
284 | } | ||
285 | AEDisposeDesc(&desc); | ||
286 | } | ||
287 | if ( nfb->_btype == BROWSE_SAVE_FILE && nfb->preset_file() ) { | ||
288 | CFStringRef namestr = | ||
289 | CFStringCreateWithCString(NULL, | ||
290 | nfb->preset_file(), | ||
291 | kCFStringEncodingASCII); | ||
292 | NavDialogSetSaveFileName(cbparm->context, namestr); | ||
293 | CFRelease(namestr); | ||
294 | } | ||
295 | NavCustomControl(cbparm->context, kNavCtlSetActionState, | ||
296 | &nfb->_keepstate ); | ||
297 | |||
298 | // Select the right filter in pop-up menu | ||
299 | if ( nfb->_filt_value == nfb->_filt_total ) { | ||
300 | // Select All Documents | ||
301 | NavPopupMenuItem kAll = kNavAllFiles; | ||
302 | NavCustomControl(cbparm->context, kNavCtlSelectAllType, &kAll); | ||
303 | } else if (nfb->_filt_value < nfb->_filt_total) { | ||
304 | // Select custom filter | ||
305 | nfb->_tempitem.version = kNavMenuItemSpecVersion; | ||
306 | nfb->_tempitem.menuCreator = 'extn'; | ||
307 | nfb->_tempitem.menuType = nfb->_filt_value; | ||
308 | *nfb->_tempitem.menuItemName = '\0'; // needed on 10.3+ | ||
309 | NavCustomControl(cbparm->context, | ||
310 | kNavCtlSelectCustomType, | ||
311 | &(nfb->_tempitem)); | ||
312 | } | ||
313 | break; | ||
314 | |||
315 | case kNavCBPopupMenuSelect: | ||
316 | NavMenuItemSpecPtr ptr; | ||
317 | // they really buried this one! | ||
318 | ptr = (NavMenuItemSpecPtr)cbparm->eventData.eventDataParms.param; | ||
319 | if ( ptr->menuCreator ) { | ||
320 | // Gets index to filter ( menuCreator = 'extn' ) | ||
321 | nfb->_filt_value = ptr->menuType; | ||
322 | } else { | ||
323 | // All docs filter selected ( menuCreator = '\0\0\0\0' ) | ||
324 | nfb->_filt_value = nfb->_filt_total; | ||
325 | } | ||
326 | break; | ||
327 | |||
328 | case kNavCBSelectEntry: | ||
329 | NavActionState astate; | ||
330 | switch ( nfb->_btype ) { | ||
331 | // these don't need selection override | ||
332 | case BROWSE_MULTI_FILE: | ||
333 | case BROWSE_MULTI_DIRECTORY: | ||
334 | case BROWSE_SAVE_FILE: | ||
335 | break; | ||
336 | |||
337 | // These need to allow only one item, so disable | ||
338 | // Open button if user tries to select multiple files | ||
339 | case BROWSE_SAVE_DIRECTORY: | ||
340 | case BROWSE_DIRECTORY: | ||
341 | case BROWSE_FILE: | ||
342 | SInt32 selectcount; | ||
343 | AECountItems((AEDescList*)cbparm-> | ||
344 | eventData.eventDataParms.param, | ||
345 | &selectcount); | ||
346 | if ( selectcount > 1 ) { | ||
347 | NavCustomControl(cbparm->context, | ||
348 | kNavCtlSetSelection, | ||
349 | NULL); | ||
350 | astate = nfb->_keepstate | | ||
351 | kNavDontOpenState | | ||
352 | kNavDontChooseState; | ||
353 | NavCustomControl(cbparm->context, | ||
354 | kNavCtlSetActionState, | ||
355 | &astate ); | ||
356 | } | ||
357 | else { | ||
358 | astate= nfb->_keepstate | kNavNormalState; | ||
359 | NavCustomControl(cbparm->context, | ||
360 | kNavCtlSetActionState, | ||
361 | &astate ); | ||
362 | } | ||
363 | break; | ||
364 | } | ||
365 | break; | ||
366 | } | ||
367 | } | ||
368 | |||
369 | // CONSTRUCTOR | ||
370 | Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { | ||
371 | _btype = val; | ||
372 | NavGetDefaultDialogCreationOptions(&_opts); | ||
373 | _opts.optionFlags |= kNavDontConfirmReplacement; // no confirms for "save as" | ||
374 | _options = NO_OPTIONS; | ||
375 | _ref = NULL; | ||
376 | memset(&_tempitem, 0, sizeof(_tempitem)); | ||
377 | _pathnames = NULL; | ||
378 | _tpathnames = 0; | ||
379 | _title = NULL; | ||
380 | _filter = NULL; | ||
381 | _filt_names = NULL; | ||
382 | memset(_filt_patt, 0, sizeof(char*) * MAXFILTERS); | ||
383 | _filt_total = 0; | ||
384 | _filt_value = 0; | ||
385 | _directory = NULL; | ||
386 | _preset_file = NULL; | ||
387 | _errmsg = NULL; | ||
388 | _keepstate = kNavNormalState; | ||
389 | } | ||
390 | |||
391 | // DESTRUCTOR | ||
392 | Fl_Native_File_Chooser::~Fl_Native_File_Chooser() { | ||
393 | // _opts // nothing to manage | ||
394 | if (_ref) { NavDialogDispose(_ref); _ref = NULL; } | ||
395 | // _options // nothing to manage | ||
396 | // _keepstate // nothing to manage | ||
397 | // _tempitem // nothing to manage | ||
398 | clear_pathnames(); | ||
399 | _directory = strfree(_directory); | ||
400 | _title = strfree(_title); | ||
401 | _preset_file = strfree(_preset_file); | ||
402 | _filter = strfree(_filter); | ||
403 | //_filt_names // managed by clear_filters() | ||
404 | //_filt_patt[i] // managed by clear_filters() | ||
405 | //_filt_total // managed by clear_filters() | ||
406 | clear_filters(); | ||
407 | //_filt_value // nothing to manage | ||
408 | _errmsg = strfree(_errmsg); | ||
409 | } | ||
410 | |||
411 | // SET THE TYPE OF BROWSER | ||
412 | void Fl_Native_File_Chooser::type(int val) { | ||
413 | _btype = val; | ||
414 | } | ||
415 | |||
416 | // GET TYPE OF BROWSER | ||
417 | int Fl_Native_File_Chooser::type() const { | ||
418 | return(_btype); | ||
419 | } | ||
420 | |||
421 | // SET OPTIONS | ||
422 | void Fl_Native_File_Chooser::options(int val) { | ||
423 | _options = val; | ||
424 | } | ||
425 | |||
426 | // GET OPTIONS | ||
427 | int Fl_Native_File_Chooser::options() const { | ||
428 | return(_options); | ||
429 | } | ||
430 | |||
431 | // SHOW THE BROWSER WINDOW | ||
432 | // Returns: | ||
433 | // 0 - user picked a file | ||
434 | // 1 - user cancelled | ||
435 | // -1 - failed; errmsg() has reason | ||
436 | // | ||
437 | int Fl_Native_File_Chooser::show() { | ||
438 | // Make sure fltk interface updates before posting our dialog | ||
439 | Fl::flush(); | ||
440 | |||
441 | // BROWSER TITLE | ||
442 | CFStringRef cfs_title; | ||
443 | cfs_title = CFStringCreateWithCString(NULL, | ||
444 | _title ? _title : "No Title", | ||
445 | kCFStringEncodingASCII); | ||
446 | _opts.windowTitle = cfs_title; | ||
447 | |||
448 | _keepstate = kNavNormalState; | ||
449 | |||
450 | // BROWSER FILTERS | ||
451 | CFArrayRef filter_array = NULL; | ||
452 | { | ||
453 | // One or more filters specified? | ||
454 | if ( _filt_total ) { | ||
455 | // NAMES -> CFArrayRef | ||
456 | CFStringRef tab = CFSTR("\t"); | ||
457 | CFStringRef tmp_cfs; | ||
458 | tmp_cfs = CFStringCreateWithCString(NULL, _filt_names, | ||
459 | kCFStringEncodingASCII); | ||
460 | filter_array = CFStringCreateArrayBySeparatingStrings( | ||
461 | NULL, tmp_cfs, tab); | ||
462 | CFRelease(tmp_cfs); | ||
463 | CFRelease(tab); | ||
464 | _opts.popupExtension = filter_array; | ||
465 | _opts.optionFlags |= kNavAllFilesInPopup; | ||
466 | } else { | ||
467 | filter_array = NULL; | ||
468 | _opts.popupExtension = NULL; | ||
469 | _opts.optionFlags |= kNavAllFilesInPopup; | ||
470 | } | ||
471 | } | ||
472 | |||
473 | // HANDLE OPTIONS WE SUPPORT | ||
474 | if ( _options & SAVEAS_CONFIRM ) { | ||
475 | _opts.optionFlags &= ~kNavDontConfirmReplacement; // enables confirm | ||
476 | } else { | ||
477 | _opts.optionFlags |= kNavDontConfirmReplacement; // disables confirm | ||
478 | } | ||
479 | |||
480 | // POST BROWSER | ||
481 | int err = post(); | ||
482 | |||
483 | // RELEASE _FILT_ARR | ||
484 | if ( filter_array ) CFRelease(filter_array); | ||
485 | filter_array = NULL; | ||
486 | _opts.popupExtension = NULL; | ||
487 | _filt_total = 0; | ||
488 | |||
489 | // RELEASE TITLE | ||
490 | if ( cfs_title ) CFRelease(cfs_title); | ||
491 | cfs_title = NULL; | ||
492 | |||
493 | return(err); | ||
494 | } | ||
495 | |||
496 | // POST BROWSER | ||
497 | // Internal use only. | ||
498 | // Assumes '_opts' has been initialized. | ||
499 | // | ||
500 | // Returns: | ||
501 | // 0 - user picked a file | ||
502 | // 1 - user cancelled | ||
503 | // -1 - failed; errmsg() has reason | ||
504 | // | ||
505 | int Fl_Native_File_Chooser::post() { | ||
506 | |||
507 | // INITIALIZE BROWSER | ||
508 | OSStatus err; | ||
509 | if ( _filt_total == 0 ) { // Make sure they match | ||
510 | _filt_value = 0; // TBD: move to someplace more logical? | ||
511 | } | ||
512 | |||
513 | if ( ! ( _options & NEW_FOLDER ) ) { | ||
514 | _keepstate |= kNavDontNewFolderState; | ||
515 | } | ||
516 | |||
517 | switch (_btype) { | ||
518 | case BROWSE_FILE: | ||
519 | case BROWSE_MULTI_FILE: | ||
520 | // Prompt user for one or more files | ||
521 | if ((err = NavCreateGetFileDialog( | ||
522 | &_opts, // options | ||
523 | 0, // file types | ||
524 | event_handler, // event handler | ||
525 | 0, // preview callback | ||
526 | filter_proc_cb, // filter callback | ||
527 | (void*)this, // callback data | ||
528 | &_ref)) != noErr ) { // dialog ref | ||
529 | errmsg("NavCreateGetFileDialog: failed"); | ||
530 | return(-1); | ||
531 | } | ||
532 | break; | ||
533 | |||
534 | case BROWSE_DIRECTORY: | ||
535 | case BROWSE_MULTI_DIRECTORY: | ||
536 | case BROWSE_SAVE_DIRECTORY: | ||
537 | // Prompts user for one or more files or folders | ||
538 | if ((err = NavCreateChooseFolderDialog( | ||
539 | &_opts, // options | ||
540 | event_handler, // event callback | ||
541 | 0, // filter callback | ||
542 | (void*)this, // callback data | ||
543 | &_ref)) != noErr ) { // dialog ref | ||
544 | errmsg("NavCreateChooseFolderDialog: failed"); | ||
545 | return(-1); | ||
546 | } | ||
547 | break; | ||
548 | |||
549 | case BROWSE_SAVE_FILE: | ||
550 | // Prompt user for filename to 'save as' | ||
551 | if ((err = NavCreatePutFileDialog( | ||
552 | &_opts, // options | ||
553 | 0, // file types | ||
554 | 0, // file creator | ||
555 | event_handler, // event handler | ||
556 | (void*)this, // callback data | ||
557 | &_ref)) != noErr ) { // dialog ref | ||
558 | errmsg("NavCreatePutFileDialog: failed"); | ||
559 | return(-1); | ||
560 | } | ||
561 | break; | ||
562 | } | ||
563 | |||
564 | // SHOW THE DIALOG | ||
565 | if ( ( err = NavDialogRun(_ref) ) != 0 ) { | ||
566 | char msg[80]; | ||
567 | sprintf(msg, "NavDialogRun: failed (err=%d)", (int)err); | ||
568 | errmsg(msg); | ||
569 | return(-1); | ||
570 | } | ||
571 | |||
572 | // WHAT ACTION DID USER CHOOSE? | ||
573 | NavUserAction act = NavDialogGetUserAction(_ref); | ||
574 | if ( act == kNavUserActionNone ) { | ||
575 | errmsg("Nothing happened yet (dialog still open)"); | ||
576 | return(-1); | ||
577 | } | ||
578 | else if ( act == kNavUserActionCancel ) { // user chose 'cancel' | ||
579 | return(1); | ||
580 | } | ||
581 | else if ( act == kNavUserActionSaveAs ) { // user chose 'save as' | ||
582 | return(get_saveas_basename(_ref)); | ||
583 | } | ||
584 | |||
585 | // TOO MANY FILES CHOSEN? | ||
586 | int ret = get_pathnames(_ref); | ||
587 | if ( _btype == BROWSE_FILE && ret == 0 && _tpathnames != 1 ) { | ||
588 | char msg[80]; | ||
589 | sprintf(msg, "Expected only one file to be chosen.. you chose %d.", | ||
590 | (int)_tpathnames); | ||
591 | errmsg(msg); | ||
592 | return(-1); | ||
593 | } | ||
594 | return(err); | ||
595 | } | ||
596 | |||
597 | // SET ERROR MESSAGE | ||
598 | // Internal use only. | ||
599 | // | ||
600 | void Fl_Native_File_Chooser::errmsg(const char *msg) { | ||
601 | _errmsg = strfree(_errmsg); | ||
602 | _errmsg = strnew(msg); | ||
603 | } | ||
604 | |||
605 | // RETURN ERROR MESSAGE | ||
606 | const char *Fl_Native_File_Chooser::errmsg() const { | ||
607 | return(_errmsg ? _errmsg : "No error"); | ||
608 | } | ||
609 | |||
610 | // GET FILENAME | ||
611 | const char* Fl_Native_File_Chooser::filename() const { | ||
612 | if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]); | ||
613 | return(""); | ||
614 | } | ||
615 | |||
616 | // GET FILENAME FROM LIST OF FILENAMES | ||
617 | const char* Fl_Native_File_Chooser::filename(int i) const { | ||
618 | if ( _pathnames && i < _tpathnames ) return(_pathnames[i]); | ||
619 | return(""); | ||
620 | } | ||
621 | |||
622 | // GET TOTAL FILENAMES CHOSEN | ||
623 | int Fl_Native_File_Chooser::count() const { | ||
624 | return(_tpathnames); | ||
625 | } | ||
626 | |||
627 | // PRESET PATHNAME | ||
628 | // Value can be NULL for none. | ||
629 | // | ||
630 | void Fl_Native_File_Chooser::directory(const char *val) { | ||
631 | _directory = strfree(_directory); | ||
632 | _directory = strnew(val); | ||
633 | } | ||
634 | |||
635 | // GET PRESET PATHNAME | ||
636 | // Returned value can be NULL if none set. | ||
637 | // | ||
638 | const char* Fl_Native_File_Chooser::directory() const { | ||
639 | return(_directory); | ||
640 | } | ||
641 | |||
642 | // SET TITLE | ||
643 | // Value can be NULL if no title desired. | ||
644 | // | ||
645 | void Fl_Native_File_Chooser::title(const char *val) { | ||
646 | _title = strfree(_title); | ||
647 | _title = strnew(val); | ||
648 | } | ||
649 | |||
650 | // GET TITLE | ||
651 | // Returned value can be NULL if none set. | ||
652 | // | ||
653 | const char *Fl_Native_File_Chooser::title() const { | ||
654 | return(_title); | ||
655 | } | ||
656 | |||
657 | // SET FILTER | ||
658 | // Can be NULL if no filter needed | ||
659 | // | ||
660 | void Fl_Native_File_Chooser::filter(const char *val) { | ||
661 | _filter = strfree(_filter); | ||
662 | _filter = strnew(val); | ||
663 | |||
664 | // Parse filter user specified | ||
665 | // IN: _filter = "C Files\t*.{cxx,h}\nText Files\t*.txt" | ||
666 | // OUT: _filt_names = "C Files\tText Files" | ||
667 | // _filt_patt[0] = "*.{cxx,h}" | ||
668 | // _filt_patt[1] = "*.txt" | ||
669 | // _filt_total = 2 | ||
670 | // | ||
671 | parse_filter(_filter); | ||
672 | } | ||
673 | |||
674 | // GET FILTER | ||
675 | // Returned value can be NULL if none set. | ||
676 | // | ||
677 | const char *Fl_Native_File_Chooser::filter() const { | ||
678 | return(_filter); | ||
679 | } | ||
680 | |||
681 | // CLEAR ALL FILTERS | ||
682 | // Internal use only. | ||
683 | // | ||
684 | void Fl_Native_File_Chooser::clear_filters() { | ||
685 | _filt_names = strfree(_filt_names); | ||
686 | for (int i=0; i<_filt_total; i++) { | ||
687 | _filt_patt[i] = strfree(_filt_patt[i]); | ||
688 | } | ||
689 | _filt_total = 0; | ||
690 | } | ||
691 | |||
692 | // PARSE USER'S FILTER SPEC | ||
693 | // Parses user specified filter ('in'), | ||
694 | // breaks out into _filt_patt[], _filt_names, and _filt_total. | ||
695 | // | ||
696 | // Handles: | ||
697 | // IN: OUT:_filt_names OUT: _filt_patt | ||
698 | // ------------------------------------ ------------------ --------------- | ||
699 | // "*.{ma,mb}" "*.{ma,mb} Files" "*.{ma,mb}" | ||
700 | // "*.[abc]" "*.[abc] Files" "*.[abc]" | ||
701 | // "*.txt" "*.txt Files" "*.c" | ||
702 | // "C Files\t*.[ch]" "C Files" "*.[ch]" | ||
703 | // "C Files\t*.[ch]\nText Files\t*.cxx" "C Files" "*.[ch]" | ||
704 | // | ||
705 | // Parsing Mode: | ||
706 | // IN:"C Files\t*.{cxx,h}" | ||
707 | // ||||||| ||||||||| | ||
708 | // mode: nnnnnnn wwwwwwwww | ||
709 | // \_____/ \_______/ | ||
710 | // Name Wildcard | ||
711 | // | ||
712 | void Fl_Native_File_Chooser::parse_filter(const char *in) { | ||
713 | clear_filters(); | ||
714 | if ( ! in ) return; | ||
715 | int has_name = strchr(in, '\t') ? 1 : 0; | ||
716 | |||
717 | char mode = has_name ? 'n' : 'w'; // parse mode: n=title, w=wildcard | ||
718 | char wildcard[1024] = ""; // parsed wildcard | ||
719 | char name[1024] = ""; | ||
720 | |||
721 | // Parse filter user specified | ||
722 | for ( ; 1; in++ ) { | ||
723 | |||
724 | //// DEBUG | ||
725 | //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildcard=<%s>\n", | ||
726 | //// *in, mode, name, wildcard); | ||
727 | |||
728 | switch (*in) { | ||
729 | // FINISHED PARSING NAME? | ||
730 | case '\t': | ||
731 | if ( mode != 'n' ) goto regchar; | ||
732 | mode = 'w'; | ||
733 | break; | ||
734 | |||
735 | // ESCAPE NEXT CHAR | ||
736 | case '\\': | ||
737 | ++in; | ||
738 | goto regchar; | ||
739 | |||
740 | // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS? | ||
741 | case '\r': | ||
742 | case '\n': | ||
743 | case '\0': | ||
744 | // TITLE | ||
745 | // If user didn't specify a name, make one | ||
746 | // | ||
747 | if ( name[0] == '\0' ) { | ||
748 | sprintf(name, "%.*s Files", (int)sizeof(name)-10, wildcard); | ||
749 | } | ||
750 | // APPEND NEW FILTER TO LIST | ||
751 | if ( wildcard[0] ) { | ||
752 | // Add to filtername list | ||
753 | // Tab delimit if more than one. We later break | ||
754 | // tab delimited string into CFArray with | ||
755 | // CFStringCreateArrayBySeparatingStrings() | ||
756 | // | ||
757 | if ( _filt_total ) { | ||
758 | _filt_names = strapp(_filt_names, "\t"); | ||
759 | } | ||
760 | _filt_names = strapp(_filt_names, name); | ||
761 | |||
762 | // Add filter to the pattern array | ||
763 | _filt_patt[_filt_total++] = strnew(wildcard); | ||
764 | } | ||
765 | // RESET | ||
766 | wildcard[0] = name[0] = '\0'; | ||
767 | mode = strchr(in, '\t') ? 'n' : 'w'; | ||
768 | // DONE? | ||
769 | if ( *in == '\0' ) return; // done | ||
770 | else continue; // not done yet, more filters | ||
771 | |||
772 | // Parse all other chars | ||
773 | default: // handle all non-special chars | ||
774 | regchar: // handle regular char | ||
775 | switch ( mode ) { | ||
776 | case 'n': chrcat(name, *in); continue; | ||
777 | case 'w': chrcat(wildcard, *in); continue; | ||
778 | } | ||
779 | break; | ||
780 | } | ||
781 | } | ||
782 | //NOTREACHED | ||
783 | } | ||
784 | |||
785 | // STATIC: FILTER CALLBACK | ||
786 | Boolean Fl_Native_File_Chooser::filter_proc_cb(AEDesc *theItem, | ||
787 | void *info, | ||
788 | void *callBackUD, | ||
789 | NavFilterModes filterMode) { | ||
790 | return((Fl_Native_File_Chooser*)callBackUD)->filter_proc_cb2( | ||
791 | theItem, info, callBackUD, filterMode); | ||
792 | } | ||
793 | |||
794 | // FILTER CALLBACK | ||
795 | // Return true if match, | ||
796 | // false if no match. | ||
797 | // | ||
798 | Boolean Fl_Native_File_Chooser::filter_proc_cb2(AEDesc *theItem, | ||
799 | void *info, | ||
800 | void *callBackUD, | ||
801 | NavFilterModes filterMode) { | ||
802 | // All files chosen or no filters | ||
803 | if ( _filt_value == _filt_total ) return(true); | ||
804 | |||
805 | FSSpec fsspec; | ||
806 | char pathname[4096]; | ||
807 | |||
808 | // On fail, filter should return true by default | ||
809 | if ( AEDescToFSSpec(theItem, &fsspec) != noErr ) { | ||
810 | return(true); | ||
811 | } | ||
812 | FSSpecToPath(fsspec, pathname, sizeof(pathname)-1); | ||
813 | |||
814 | if ( fl_filename_isdir(pathname) ) return(true); | ||
815 | if ( fl_filename_match(pathname, _filt_patt[_filt_value]) ) return(true); | ||
816 | else return(false); | ||
817 | } | ||
818 | |||
819 | // SET PRESET FILE | ||
820 | // Value can be NULL for none. | ||
821 | // | ||
822 | void Fl_Native_File_Chooser::preset_file(const char* val) { | ||
823 | _preset_file = strfree(_preset_file); | ||
824 | _preset_file = strnew(val); | ||
825 | } | ||
826 | |||
827 | // PRESET FILE | ||
828 | // Returned value can be NULL if none set. | ||
829 | // | ||
830 | const char* Fl_Native_File_Chooser::preset_file() { | ||
831 | return(_preset_file); | ||
832 | } | ||
833 | |||
diff --git a/src/lib/FL/Fl_Native_File_Chooser_WIN32.H b/src/lib/FL/Fl_Native_File_Chooser_WIN32.H new file mode 100644 index 0000000..ead87df --- /dev/null +++ b/src/lib/FL/Fl_Native_File_Chooser_WIN32.H | |||
@@ -0,0 +1,114 @@ | |||
1 | // | ||
2 | // Fl_Native_File_Chooser_WINDOWS.H -- FLTK native OS file chooser widget | ||
3 | // | ||
4 | // Copyright 2004 by Greg Ercolano. | ||
5 | // April 2005 - API changes, improved filter processing by Nathan Vander Wilt | ||
6 | // | ||
7 | // This library is free software; you can redistribute it and/or | ||
8 | // modify it under the terms of the GNU Library General Public | ||
9 | // License as published by the Free Software Foundation; either | ||
10 | // version 2 of the License, or (at your option) any later version. | ||
11 | // | ||
12 | // This library is distributed in the hope that it will be useful, | ||
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | // Library General Public License for more details. | ||
16 | // | ||
17 | // You should have received a copy of the GNU Library General Public | ||
18 | // License along with this library; if not, write to the Free Software | ||
19 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
20 | // USA. | ||
21 | // | ||
22 | #ifndef _FL_NATIVE_FILE_BROWSER_H | ||
23 | #define _FL_NATIVE_FILE_BROWSER_H | ||
24 | |||
25 | // #define _WIN32_WINNT 0x0501 // needed for OPENFILENAME's 'FlagsEx' | ||
26 | #include <stdio.h> | ||
27 | #include <stdlib.h> // malloc | ||
28 | #include <windows.h> | ||
29 | #include <commdlg.h> // OPENFILENAME, GetOpenFileName() | ||
30 | #include <shlobj.h> // BROWSEINFO, SHBrowseForFolder() | ||
31 | |||
32 | #define MAXFILTERS 80 | ||
33 | |||
34 | class Fl_Native_File_Chooser { | ||
35 | public: | ||
36 | enum Type { | ||
37 | BROWSE_FILE = 0, | ||
38 | BROWSE_DIRECTORY, | ||
39 | BROWSE_MULTI_FILE, | ||
40 | BROWSE_MULTI_DIRECTORY, | ||
41 | BROWSE_SAVE_FILE, | ||
42 | BROWSE_SAVE_DIRECTORY | ||
43 | }; | ||
44 | enum Option { | ||
45 | NO_OPTIONS = 0x0000, // no options enabled | ||
46 | SAVEAS_CONFIRM = 0x0001, // Show native 'Save As' overwrite | ||
47 | // confirm dialog (if supported) | ||
48 | NEW_FOLDER = 0x0002, // Show 'New Folder' icon | ||
49 | // (if supported) | ||
50 | PREVIEW = 0x0004, // enable preview mode | ||
51 | }; | ||
52 | private: | ||
53 | int _btype; // kind-of browser to show() | ||
54 | int _options; // general options | ||
55 | OPENFILENAME _ofn; // GetOpenFileName() & GetSaveFileName() struct | ||
56 | BROWSEINFO _binf; // SHBrowseForFolder() struct | ||
57 | char **_pathnames; // array of pathnames | ||
58 | int _tpathnames; // total pathnames | ||
59 | char *_directory; // default pathname to use | ||
60 | char *_title; // title for window | ||
61 | char *_filter; // user-side search filter | ||
62 | char *_parsedfilt; // filter parsed for Windows dialog | ||
63 | int _nfilters; // number of filters parse_filter counted | ||
64 | char *_preset_file; // the file to preselect | ||
65 | char *_errmsg; // error message | ||
66 | |||
67 | // Private methods | ||
68 | void errmsg(const char *msg); | ||
69 | |||
70 | void clear_pathnames(); | ||
71 | void set_single_pathname(const char *s); | ||
72 | void add_pathname(const char *s); | ||
73 | |||
74 | void FreePIDL(ITEMIDLIST *pidl); | ||
75 | void ClearOFN(); | ||
76 | void ClearBINF(); | ||
77 | void Win2Unix(char *s); | ||
78 | void Unix2Win(char *s); | ||
79 | int showfile(); | ||
80 | static int CALLBACK Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data); | ||
81 | int showdir(); | ||
82 | |||
83 | void parse_filter(const char *); | ||
84 | void clear_filters(); | ||
85 | void add_filter(const char *, const char *); | ||
86 | |||
87 | public: | ||
88 | Fl_Native_File_Chooser(int val = BROWSE_FILE); | ||
89 | ~Fl_Native_File_Chooser(); | ||
90 | |||
91 | // Public methods | ||
92 | void type(int val); | ||
93 | int type() const; | ||
94 | void options(int); | ||
95 | int options() const; | ||
96 | int count() const; | ||
97 | const char *filename() const; | ||
98 | const char *filename(int i) const; | ||
99 | void directory(const char *val); | ||
100 | const char *directory() const; | ||
101 | void title(const char *val); | ||
102 | const char *title() const; | ||
103 | const char *filter() const; | ||
104 | void filter(const char *val); | ||
105 | int filters() const { return _nfilters; } | ||
106 | void filter_value(int i); | ||
107 | int filter_value() const; | ||
108 | void preset_file(const char *); | ||
109 | const char *preset_file() const; | ||
110 | const char *errmsg() const; | ||
111 | int show(); | ||
112 | }; | ||
113 | |||
114 | #endif /*_FL_NATIVE_FILE_BROWSER_H*/ | ||
diff --git a/src/lib/FL/Fl_Native_File_Chooser_WIN32.cxx b/src/lib/FL/Fl_Native_File_Chooser_WIN32.cxx new file mode 100644 index 0000000..226cf7b --- /dev/null +++ b/src/lib/FL/Fl_Native_File_Chooser_WIN32.cxx | |||
@@ -0,0 +1,765 @@ | |||
1 | // | ||
2 | // Fl_Native_File_Chooser_WINDOWS.cxx -- FLTK native OS file chooser widget | ||
3 | // | ||
4 | // Copyright 2004 by Greg Ercolano. | ||
5 | // April 2005 - API changes, improved filter processing by Nathan Vander Wilt | ||
6 | // | ||
7 | // This library is free software; you can redistribute it and/or | ||
8 | // modify it under the terms of the GNU Library General Public | ||
9 | // License as published by the Free Software Foundation; either | ||
10 | // version 2 of the License, or (at your option) any later version. | ||
11 | // | ||
12 | // This library is distributed in the hope that it will be useful, | ||
13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
15 | // Library General Public License for more details. | ||
16 | // | ||
17 | // You should have received a copy of the GNU Library General Public | ||
18 | // License along with this library; if not, write to the Free Software | ||
19 | // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 | ||
20 | // USA. | ||
21 | // | ||
22 | // Please keep code 80 column compliant. | ||
23 | // | ||
24 | // 10 20 30 40 50 60 70 | ||
25 | // | | | | | | | | ||
26 | // 4567890123456789012345678901234567890123456789012345678901234567890123456789 | ||
27 | // | ||
28 | |||
29 | // http://www.codeproject.com/dialog/selectfolder.asp - any application to multi-folder implementation? | ||
30 | |||
31 | #include <FL/Fl_Native_File_Chooser.H> | ||
32 | #include <stdio.h> // debugging | ||
33 | #include "common.cxx" // strnew/strfree/strapp/chrcat | ||
34 | |||
35 | #define LCURLY_CHR '{' | ||
36 | #define RCURLY_CHR '}' | ||
37 | #define LBRACKET_CHR '[' | ||
38 | #define RBRACKET_CHR ']' | ||
39 | #ifndef BIF_NONEWFOLDERBUTTON | ||
40 | #define BIF_NONEWFOLDERBUTTON 0x200 | ||
41 | #endif | ||
42 | // STATIC: PRINT WINDOWS 'DOUBLE NULL' STRING (DEBUG) | ||
43 | /* | ||
44 | static void dnullprint(char *wp) { | ||
45 | if ( ! wp ) return; | ||
46 | for ( int t=0; true; t++ ) { | ||
47 | if ( wp[t] == '\0' && wp[t+1] == '\0' ) { | ||
48 | printf("\\0\\0"); | ||
49 | fflush(stdout); | ||
50 | return; | ||
51 | } else if ( wp[t] == '\0' ) { | ||
52 | printf("\\0"); | ||
53 | } else { | ||
54 | printf("%c",wp[t]); | ||
55 | } | ||
56 | } | ||
57 | } | ||
58 | */ | ||
59 | // RETURN LENGTH OF DOUBLENULL STRING | ||
60 | // Includes single nulls in count, excludes trailing doublenull. | ||
61 | // | ||
62 | // 1234 567 | ||
63 | // |||/\||| | ||
64 | // IN: "one\0two\0\0" | ||
65 | // OUT: 7 | ||
66 | // | ||
67 | static int dnulllen(const char *wp) { | ||
68 | int len = 0; | ||
69 | while ( ! ( *(wp+0) == 0 && *(wp+1) == 0 ) ) | ||
70 | { ++wp; ++len; } | ||
71 | return(len); | ||
72 | } | ||
73 | |||
74 | // STATIC: Append a string to another, leaving terminated with DOUBLE NULL. | ||
75 | // Automatically handles extending length of string. | ||
76 | // wp can be NULL (a new wp will be allocated and initialized). | ||
77 | // string must be NULL terminated. | ||
78 | // The pointer wp may be modified on return. | ||
79 | // | ||
80 | static void dnullcat(char*&wp, const char *string, int n = -1 ) { | ||
81 | //DEBUG printf("DEBUG: dnullcat IN: <"); dnullprint(wp); printf(">\n"); | ||
82 | int inlen = ( n < 0 ) ? strlen(string) : n; | ||
83 | if ( ! wp ) { | ||
84 | wp = new char[inlen + 4]; | ||
85 | *(wp+0) = '\0'; | ||
86 | *(wp+1) = '\0'; | ||
87 | } else { | ||
88 | int wplen = dnulllen(wp); | ||
89 | // Make copy of wp into larger buffer | ||
90 | char *tmp = new char[wplen + inlen + 4]; | ||
91 | memcpy(tmp, wp, wplen+2); // copy of wp plus doublenull | ||
92 | delete [] wp; // delete old wp | ||
93 | wp = tmp; // use new copy | ||
94 | //DEBUG printf("DEBUG: dnullcat COPY: <"); dnullprint(wp); printf("> (wplen=%d)\n", wplen); | ||
95 | } | ||
96 | |||
97 | // Find end of double null string | ||
98 | // *wp2 is left pointing at second null. | ||
99 | // | ||
100 | char *wp2 = wp; | ||
101 | if ( *(wp2+0) != '\0' && *(wp2+1) != '\0' ) { | ||
102 | for ( ; 1; wp2++ ) | ||
103 | if ( *(wp2+0) == '\0' && *(wp2+1) == '\0' ) | ||
104 | { wp2++; break; } | ||
105 | } | ||
106 | |||
107 | if ( n == -1 ) n = strlen(string); | ||
108 | strncpy(wp2, string, n); | ||
109 | |||
110 | // Leave string double-null terminated | ||
111 | *(wp2+n+0) = '\0'; | ||
112 | *(wp2+n+1) = '\0'; | ||
113 | //DEBUG printf("DEBUG: dnullcat OUT: <"); dnullprint(wp); printf(">\n\n"); | ||
114 | } | ||
115 | |||
116 | // CTOR | ||
117 | Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { | ||
118 | _btype = val; | ||
119 | _options = NO_OPTIONS; | ||
120 | memset((void*)&_ofn, 0, sizeof(OPENFILENAME)); | ||
121 | _ofn.lStructSize = sizeof(OPENFILENAME); | ||
122 | _ofn.hwndOwner = NULL; | ||
123 | memset((void*)&_binf, 0, sizeof(BROWSEINFO)); | ||
124 | _pathnames = NULL; | ||
125 | _tpathnames = 0; | ||
126 | _directory = NULL; | ||
127 | _title = NULL; | ||
128 | _filter = NULL; | ||
129 | _parsedfilt = NULL; | ||
130 | _nfilters = 0; | ||
131 | _preset_file = NULL; | ||
132 | _errmsg = NULL; | ||
133 | } | ||
134 | |||
135 | // DTOR | ||
136 | Fl_Native_File_Chooser::~Fl_Native_File_Chooser() { | ||
137 | //_pathnames // managed by clear_pathnames() | ||
138 | //_tpathnames // managed by clear_pathnames() | ||
139 | _directory = strfree(_directory); | ||
140 | _title = strfree(_title); | ||
141 | _filter = strfree(_filter); | ||
142 | //_parsedfilt // managed by clear_filters() | ||
143 | //_nfilters // managed by clear_filters() | ||
144 | _preset_file = strfree(_preset_file); | ||
145 | _errmsg = strfree(_errmsg); | ||
146 | clear_filters(); | ||
147 | clear_pathnames(); | ||
148 | ClearOFN(); | ||
149 | ClearBINF(); | ||
150 | } | ||
151 | |||
152 | // SET TYPE OF BROWSER | ||
153 | void Fl_Native_File_Chooser::type(int val) { | ||
154 | _btype = val; | ||
155 | } | ||
156 | |||
157 | // GET TYPE OF BROWSER | ||
158 | int Fl_Native_File_Chooser::type() const { | ||
159 | return( _btype ); | ||
160 | } | ||
161 | |||
162 | // SET OPTIONS | ||
163 | void Fl_Native_File_Chooser::options(int val) { | ||
164 | _options = val; | ||
165 | } | ||
166 | |||
167 | // GET OPTIONS | ||
168 | int Fl_Native_File_Chooser::options() const { | ||
169 | return(_options); | ||
170 | } | ||
171 | |||
172 | // PRIVATE: SET ERROR MESSAGE | ||
173 | void Fl_Native_File_Chooser::errmsg(const char *val) { | ||
174 | _errmsg = strfree(_errmsg); | ||
175 | _errmsg = strnew(val); | ||
176 | } | ||
177 | |||
178 | // FREE PATHNAMES ARRAY, IF IT HAS ANY CONTENTS | ||
179 | void Fl_Native_File_Chooser::clear_pathnames() { | ||
180 | if ( _pathnames ) { | ||
181 | while ( --_tpathnames >= 0 ) { | ||
182 | _pathnames[_tpathnames] = strfree(_pathnames[_tpathnames]); | ||
183 | } | ||
184 | delete [] _pathnames; | ||
185 | _pathnames = NULL; | ||
186 | } | ||
187 | _tpathnames = 0; | ||
188 | } | ||
189 | |||
190 | // SET A SINGLE PATHNAME | ||
191 | void Fl_Native_File_Chooser::set_single_pathname(const char *s) { | ||
192 | clear_pathnames(); | ||
193 | _pathnames = new char*[1]; | ||
194 | _pathnames[0] = strnew(s); | ||
195 | _tpathnames = 1; | ||
196 | } | ||
197 | |||
198 | // ADD PATHNAME TO EXISTING ARRAY | ||
199 | void Fl_Native_File_Chooser::add_pathname(const char *s) { | ||
200 | if ( ! _pathnames ) { | ||
201 | // Create first element in array | ||
202 | ++_tpathnames; | ||
203 | _pathnames = new char*[_tpathnames]; | ||
204 | } else { | ||
205 | // Grow array by 1 | ||
206 | char **tmp = new char*[_tpathnames+1]; // create new buffer | ||
207 | memcpy((void*)tmp, (void*)_pathnames, sizeof(char*)*_tpathnames); // copy old | ||
208 | delete [] _pathnames; // delete old | ||
209 | _pathnames = tmp; // use new | ||
210 | ++_tpathnames; | ||
211 | } | ||
212 | _pathnames[_tpathnames-1] = strnew(s); | ||
213 | } | ||
214 | |||
215 | // FREE A PIDL (Pointer to IDentity List) | ||
216 | void Fl_Native_File_Chooser::FreePIDL(ITEMIDLIST *pidl) { | ||
217 | IMalloc *imalloc = NULL; | ||
218 | if ( SUCCEEDED(SHGetMalloc(&imalloc)) ) | ||
219 | { imalloc->Free(pidl); imalloc->Release(); imalloc = NULL; } | ||
220 | } | ||
221 | |||
222 | // CLEAR MICROSOFT OFN (OPEN FILE NAME) CLASS | ||
223 | void Fl_Native_File_Chooser::ClearOFN() { | ||
224 | int temp; | ||
225 | // Free any previously allocated lpstrFile before zeroing out _ofn | ||
226 | if ( _ofn.lpstrFile ) | ||
227 | { _ofn.lpstrFile = strfree((char*)_ofn.lpstrFile); } | ||
228 | if ( _ofn.lpstrInitialDir ) | ||
229 | { _ofn.lpstrInitialDir = (LPCSTR)strfree((char*)_ofn.lpstrInitialDir); } | ||
230 | if ( _ofn.lpstrFile ) | ||
231 | { _ofn.lpstrFile = strfree(_ofn.lpstrFile); } | ||
232 | _ofn.lpstrFilter = NULL; // (deleted elsewhere) | ||
233 | temp = _ofn.nFilterIndex; // keep the filter_value | ||
234 | memset((void*)&_ofn, 0, sizeof(_ofn)); | ||
235 | _ofn.lStructSize = sizeof(OPENFILENAME); | ||
236 | _ofn.nFilterIndex = temp; | ||
237 | } | ||
238 | |||
239 | // CLEAR MICROSOFT BINF (BROWSER INFO) CLASS | ||
240 | void Fl_Native_File_Chooser::ClearBINF() { | ||
241 | if ( _binf.pidlRoot ) { | ||
242 | FreePIDL((ITEMIDLIST*)_binf.pidlRoot); | ||
243 | _binf.pidlRoot = NULL; | ||
244 | } | ||
245 | memset((void*)&_binf, 0, sizeof(_binf)); | ||
246 | } | ||
247 | |||
248 | // CONVERT WINDOWS BACKSLASHES TO UNIX FRONTSLASHES | ||
249 | void Fl_Native_File_Chooser::Win2Unix(char *s) { | ||
250 | for ( ; *s; s++ ) | ||
251 | if ( *s == '\\' ) *s = '/'; | ||
252 | } | ||
253 | |||
254 | // CONVERT UNIX FRONTSLASHES TO WINDOWS BACKSLASHES | ||
255 | void Fl_Native_File_Chooser::Unix2Win(char *s) { | ||
256 | for ( ; *s; s++ ) | ||
257 | if ( *s == '/' ) *s = '\\'; | ||
258 | } | ||
259 | |||
260 | // SHOW FILE BROWSER | ||
261 | int Fl_Native_File_Chooser::showfile() { | ||
262 | ClearOFN(); | ||
263 | clear_pathnames(); | ||
264 | size_t fsize = 2048; | ||
265 | _ofn.Flags |= OFN_NOVALIDATE; // prevent disabling of front slashes | ||
266 | _ofn.Flags |= OFN_HIDEREADONLY; // hide goofy readonly flag | ||
267 | // USE NEW BROWSER | ||
268 | _ofn.Flags |= OFN_EXPLORER; // use newer explorer windows | ||
269 | // // USE OLD BROWSER | ||
270 | // _ofn.lpfnHook = MyHook; | ||
271 | // _ofn.Flags |= OFN_ENABLEHOOK; | ||
272 | _ofn.Flags |= OFN_ENABLESIZING; // allow window to be resized (hey, why not?) | ||
273 | |||
274 | switch ( _btype ) { | ||
275 | case BROWSE_DIRECTORY: | ||
276 | case BROWSE_MULTI_DIRECTORY: | ||
277 | case BROWSE_SAVE_DIRECTORY: | ||
278 | abort(); // never happens: handled by showdir() | ||
279 | case BROWSE_FILE: | ||
280 | fsize = 65536; // XXX: there must be a better way | ||
281 | break; | ||
282 | case BROWSE_MULTI_FILE: | ||
283 | _ofn.Flags |= OFN_ALLOWMULTISELECT; | ||
284 | fsize = 65536; // XXX: there must be a better way | ||
285 | break; | ||
286 | case BROWSE_SAVE_FILE: | ||
287 | if ( options() & SAVEAS_CONFIRM && type() == BROWSE_SAVE_FILE ) { | ||
288 | _ofn.Flags |= OFN_OVERWRITEPROMPT; | ||
289 | } | ||
290 | break; | ||
291 | } | ||
292 | // SPACE FOR RETURNED FILENAME | ||
293 | _ofn.lpstrFile = new char[fsize]; | ||
294 | _ofn.nMaxFile = fsize-1; | ||
295 | _ofn.lpstrFile[0] = '\0'; | ||
296 | _ofn.lpstrFile[1] = '\0'; | ||
297 | // PARENT WINDOW | ||
298 | _ofn.hwndOwner = GetForegroundWindow(); | ||
299 | // DIALOG TITLE | ||
300 | _ofn.lpstrTitle = _title ? _title : NULL; | ||
301 | // FILTER | ||
302 | _ofn.lpstrFilter = _parsedfilt ? _parsedfilt : NULL; | ||
303 | // PRESET FILE | ||
304 | // If set, supercedes _directory. See KB Q86920 for details | ||
305 | // | ||
306 | if ( _preset_file ) { | ||
307 | int len = strlen(_preset_file); | ||
308 | char *strfile = new char[MAX_PATH]; // as per KB 222003 >8( | ||
309 | strcpy(strfile, _preset_file); | ||
310 | strfile[len+0] = '\0'; // (multiselect needs dnull) | ||
311 | strfile[len+1] = '\0'; | ||
312 | Unix2Win(strfile); | ||
313 | _ofn.lpstrFile = strfile; | ||
314 | _ofn.nMaxFile = MAX_PATH; // as per KB 222003 >8( | ||
315 | } | ||
316 | if ( _directory ) { | ||
317 | // PRESET DIR | ||
318 | // XXX: See KB Q86920 for doc bug: | ||
319 | // http://support.microsoft.com/default.aspx?scid=kb;en-us;86920 | ||
320 | // | ||
321 | if ( _directory ) { | ||
322 | _ofn.lpstrInitialDir = strnew(_directory); | ||
323 | Unix2Win((char*)_ofn.lpstrInitialDir); | ||
324 | } | ||
325 | } | ||
326 | // OPEN THE DIALOG WINDOW | ||
327 | int err; | ||
328 | if ( _btype == BROWSE_SAVE_FILE ) { | ||
329 | err = GetSaveFileName(&_ofn); | ||
330 | } else { | ||
331 | err = GetOpenFileName(&_ofn); | ||
332 | } | ||
333 | if ( err == 0 ) { | ||
334 | // EXTENDED ERROR CHECK | ||
335 | int err = CommDlgExtendedError(); | ||
336 | // CANCEL? | ||
337 | if ( err == 0 ) | ||
338 | return(1); // user hit 'cancel' | ||
339 | // AN ERROR OCCURRED | ||
340 | char msg[80]; | ||
341 | sprintf(msg, "CommDlgExtendedError() code=%d", err); | ||
342 | errmsg(msg); | ||
343 | return(-1); | ||
344 | } | ||
345 | // PREPARE PATHNAMES FOR RETURN | ||
346 | switch ( _btype ) { | ||
347 | case BROWSE_FILE: | ||
348 | case BROWSE_SAVE_FILE: | ||
349 | set_single_pathname(_ofn.lpstrFile); | ||
350 | Win2Unix(_pathnames[_tpathnames-1]); | ||
351 | break; | ||
352 | case BROWSE_MULTI_FILE: { | ||
353 | // EXTRACT MULTIPLE FILENAMES | ||
354 | const char *dirname = _ofn.lpstrFile; | ||
355 | int dirlen = strlen(dirname); | ||
356 | if ( dirlen > 0 ) { | ||
357 | char pathname[2048]; | ||
358 | |||
359 | // WALK STRING SEARCHING FOR 'DOUBLE-NULL' | ||
360 | // eg. "/dir/name\0foo1\0foo2\0foo3\0\0" | ||
361 | // | ||
362 | for ( const char *s = _ofn.lpstrFile + dirlen + 1; | ||
363 | *s; s+= (strlen(s)+1)) { | ||
364 | strcpy(pathname, dirname); | ||
365 | strcat(pathname, "\\"); | ||
366 | strcat(pathname, s); | ||
367 | add_pathname(pathname); | ||
368 | Win2Unix(_pathnames[_tpathnames-1]); | ||
369 | } | ||
370 | } | ||
371 | // XXX | ||
372 | // Work around problem where pasted forward-slash pathname | ||
373 | // into the file browser causes new "Explorer" interface | ||
374 | // not to grok forward slashes, passing back as a 'filename'..! | ||
375 | // | ||
376 | if ( _tpathnames == 0 ) { | ||
377 | add_pathname(dirname); | ||
378 | Win2Unix(_pathnames[_tpathnames-1]); | ||
379 | } | ||
380 | break; | ||
381 | } | ||
382 | case BROWSE_DIRECTORY: | ||
383 | case BROWSE_MULTI_DIRECTORY: | ||
384 | case BROWSE_SAVE_DIRECTORY: | ||
385 | abort(); // not here | ||
386 | } | ||
387 | return(0); | ||
388 | } | ||
389 | |||
390 | // Used by SHBrowseForFolder(), sets initial selected dir. | ||
391 | // Ref: Usenet: microsoft.public.vc.mfc, Dec 8 2000, 1:38p David Lowndes | ||
392 | // Subject: How to specify to select an initial folder .." | ||
393 | // | ||
394 | int CALLBACK Fl_Native_File_Chooser::Dir_CB(HWND win, UINT msg, LPARAM param, LPARAM data) { | ||
395 | switch (msg) { | ||
396 | case BFFM_INITIALIZED: | ||
397 | if (data) ::SendMessage(win, BFFM_SETSELECTION, TRUE, data); | ||
398 | break; | ||
399 | case BFFM_SELCHANGED: | ||
400 | TCHAR path[MAX_PATH]; | ||
401 | if ( SHGetPathFromIDList((ITEMIDLIST*)param, path) ) { | ||
402 | ::SendMessage(win, BFFM_ENABLEOK, 0, 1); | ||
403 | } else { | ||
404 | //disable ok button if not a path | ||
405 | ::SendMessage(win, BFFM_ENABLEOK, 0, 0); | ||
406 | } | ||
407 | break; | ||
408 | case BFFM_VALIDATEFAILED: | ||
409 | // we could pop up an annoying message here. | ||
410 | // also needs set ulFlags |= BIF_VALIDATE | ||
411 | break; | ||
412 | default: | ||
413 | break; | ||
414 | } | ||
415 | return(0); | ||
416 | } | ||
417 | |||
418 | // SHOW DIRECTORY BROWSER | ||
419 | int Fl_Native_File_Chooser::showdir() { | ||
420 | OleInitialize(NULL); // init needed by BIF_USENEWUI | ||
421 | ClearBINF(); | ||
422 | clear_pathnames(); | ||
423 | // PARENT WINDOW | ||
424 | _binf.hwndOwner = GetForegroundWindow(); | ||
425 | // DIALOG TITLE | ||
426 | _binf.lpszTitle = _title ? _title : NULL; | ||
427 | // FLAGS | ||
428 | _binf.ulFlags =0; // initialize | ||
429 | |||
430 | // TBD: make sure matches to runtime system, if need be. | ||
431 | //( what if _WIN32_IE doesn't match system? does the program not run? ) | ||
432 | // TBD: match all 3 types of directories | ||
433 | |||
434 | #if defined(BIF_NONEWFOLDERBUTTON) // Version 6.0 | ||
435 | if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags &= !BIF_NONEWFOLDERBUTTON; | ||
436 | _binf.ulFlags |= BIF_USENEWUI | BIF_SHAREABLE | BIF_RETURNONLYFSDIRS; | ||
437 | #elif defined(BIF_USENEWUI) // Version 5.0 | ||
438 | if ( _btype == BROWSE_DIRECTORY ) _binf.ulFlags |= BIF_EDITBOX; | ||
439 | else if ( _btype == BROWSE_SAVE_DIRECTORY ) _binf.ulFlags |= BIF_USENEWUI; | ||
440 | _binf.ulFlags |= BIF_SHAREABLE | BIF_RETURNONLYFSDIRS; | ||
441 | #elif defined(BIF_EDITBOX) // Version 4.71 | ||
442 | _binf.ulFlags |= BIF_RETURNONLYFSDIRS | BIF_EDITBOX; | ||
443 | #else // Version Old | ||
444 | _binf.ulFlags |= BIF_RETURNONLYFSDIRS; | ||
445 | #endif | ||
446 | |||
447 | |||
448 | // BUFFER | ||
449 | char displayname[MAX_PATH]; | ||
450 | _binf.pszDisplayName = displayname; | ||
451 | // PRESET DIR | ||
452 | char presetname[MAX_PATH]; | ||
453 | if ( _directory ) { | ||
454 | strcpy(presetname, _directory); | ||
455 | Unix2Win(presetname); | ||
456 | _binf.lParam = (LPARAM)presetname; | ||
457 | } | ||
458 | else _binf.lParam = 0; | ||
459 | _binf.lpfn = Dir_CB; | ||
460 | // OPEN BROWSER | ||
461 | ITEMIDLIST *pidl = SHBrowseForFolder(&_binf); | ||
462 | // CANCEL? | ||
463 | if ( pidl == NULL ) return(1); | ||
464 | |||
465 | // GET THE PATHNAME(S) THE USER SELECTED | ||
466 | // TBD: expand NetHood shortcuts from this PIDL?? | ||
467 | // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/shell/reference/functions/shbrowseforfolder.asp | ||
468 | |||
469 | TCHAR path[MAX_PATH]; | ||
470 | if ( SHGetPathFromIDList(pidl, path) ) | ||
471 | { Win2Unix(path); add_pathname(path); } | ||
472 | FreePIDL(pidl); | ||
473 | if ( !strlen(path) ) return(1); // don't return empty pathnames | ||
474 | return(0); | ||
475 | } | ||
476 | |||
477 | // RETURNS: | ||
478 | // 0 - user picked a file | ||
479 | // 1 - user cancelled | ||
480 | // -1 - failed; errmsg() has reason | ||
481 | // | ||
482 | int Fl_Native_File_Chooser::show() { | ||
483 | if ( _btype == BROWSE_DIRECTORY || | ||
484 | _btype == BROWSE_MULTI_DIRECTORY || | ||
485 | _btype == BROWSE_SAVE_DIRECTORY ) | ||
486 | return(showdir()); | ||
487 | else | ||
488 | return(showfile()); | ||
489 | } | ||
490 | |||
491 | // RETURN ERROR MESSAGE | ||
492 | const char *Fl_Native_File_Chooser::errmsg() const { | ||
493 | return(_errmsg ? _errmsg : "No error"); | ||
494 | } | ||
495 | |||
496 | // GET FILENAME | ||
497 | const char* Fl_Native_File_Chooser::filename() const { | ||
498 | if ( _pathnames && _tpathnames > 0 ) return(_pathnames[0]); | ||
499 | return(""); | ||
500 | } | ||
501 | |||
502 | // GET FILENAME FROM LIST OF FILENAMES | ||
503 | const char* Fl_Native_File_Chooser::filename(int i) const { | ||
504 | if ( _pathnames && i < _tpathnames ) return(_pathnames[i]); | ||
505 | return(""); | ||
506 | } | ||
507 | |||
508 | // GET TOTAL FILENAMES CHOSEN | ||
509 | int Fl_Native_File_Chooser::count() const { | ||
510 | return(_tpathnames); | ||
511 | } | ||
512 | |||
513 | // PRESET PATHNAME | ||
514 | // Can be NULL if no preset is desired. | ||
515 | // | ||
516 | void Fl_Native_File_Chooser::directory(const char *val) { | ||
517 | _directory = strfree(_directory); | ||
518 | _directory = strnew(val); | ||
519 | } | ||
520 | |||
521 | // GET PRESET PATHNAME | ||
522 | // Can return NULL if none set. | ||
523 | // | ||
524 | const char *Fl_Native_File_Chooser::directory() const { | ||
525 | return(_directory); | ||
526 | } | ||
527 | |||
528 | // SET TITLE | ||
529 | // Can be NULL if no title desired. | ||
530 | // | ||
531 | void Fl_Native_File_Chooser::title(const char *val) { | ||
532 | _title = strfree(_title); | ||
533 | _title = strnew(val); | ||
534 | } | ||
535 | |||
536 | // GET TITLE | ||
537 | // Can return NULL if none set. | ||
538 | // | ||
539 | const char *Fl_Native_File_Chooser::title() const { | ||
540 | return(_title); | ||
541 | } | ||
542 | |||
543 | // SET FILTER | ||
544 | // Can be NULL if no filter needed | ||
545 | // | ||
546 | void Fl_Native_File_Chooser::filter(const char *val) { | ||
547 | _filter = strfree(_filter); | ||
548 | clear_filters(); | ||
549 | if ( val ) { | ||
550 | _filter = strnew(val); | ||
551 | parse_filter(_filter); | ||
552 | } | ||
553 | add_filter("All Files", "*.*"); // always include 'all files' option | ||
554 | |||
555 | #ifdef DEBUG | ||
556 | nullprint(_parsedfilt); | ||
557 | #endif /*DEBUG*/ | ||
558 | } | ||
559 | |||
560 | // GET FILTER | ||
561 | // Can return NULL if none set. | ||
562 | // | ||
563 | const char *Fl_Native_File_Chooser::filter() const { | ||
564 | return(_filter); | ||
565 | } | ||
566 | |||
567 | // CLEAR FILTERS | ||
568 | void Fl_Native_File_Chooser::clear_filters() { | ||
569 | _nfilters = 0; | ||
570 | _parsedfilt = strfree(_parsedfilt); | ||
571 | } | ||
572 | |||
573 | // ADD A FILTER | ||
574 | void Fl_Native_File_Chooser::add_filter( | ||
575 | const char *name_in, // name of filter (optional: can be null) | ||
576 | const char *winfilter // windows style filter (eg. "*.cxx;*.h") | ||
577 | ) { | ||
578 | // No name? Make one.. | ||
579 | char name[1024]; | ||
580 | if ( !name_in || name_in[0] == '\0' ) { | ||
581 | sprintf(name, "%.*s Files", sizeof(name)-10, winfilter); | ||
582 | } else { | ||
583 | sprintf(name, "%.*s", sizeof(name)-10, name_in); | ||
584 | } | ||
585 | dnullcat(_parsedfilt, name); | ||
586 | dnullcat(_parsedfilt, winfilter); | ||
587 | //DEBUG printf("DEBUG: ADD FILTER name=<%s> winfilter=<%s>\n", name, winfilter); | ||
588 | } | ||
589 | |||
590 | // CONVERT FLTK STYLE PATTERN MATCHES TO WINDOWS 'DOUBLENULL' PATTERN | ||
591 | // Handles: | ||
592 | // IN OUT | ||
593 | // ----------- ----------------------------- | ||
594 | // *.{ma,mb} "*.{ma,mb} Files\0*.ma;*.mb\0\0" | ||
595 | // *.[abc] "*.[abc] Files\0*.a;*.b;*.c\0\0" | ||
596 | // *.txt "*.txt Files\0*.txt\0\0" | ||
597 | // C Files\t*.[ch] "C Files\0*.c;*.h\0\0" | ||
598 | // | ||
599 | // Example: | ||
600 | // IN: "*.{ma,mb}" | ||
601 | // OUT: "*.ma;*.mb Files\0*.ma;*.mb\0All Files\0*.*\0\0" | ||
602 | // --------------- --------- --------- --- | ||
603 | // | | | | | ||
604 | // Title Wildcards Title Wildcards | ||
605 | // | ||
606 | // Parsing Mode: | ||
607 | // IN:"C Files\t*.{cxx,h}" | ||
608 | // ||||||| ||||||||| | ||
609 | // mode: nnnnnnn ww{{{{{{{ | ||
610 | // \_____/ \_______/ | ||
611 | // Name Wildcard | ||
612 | // | ||
613 | void Fl_Native_File_Chooser::parse_filter(const char *in) { | ||
614 | clear_filters(); | ||
615 | if ( ! in ) return; | ||
616 | |||
617 | int has_name = strchr(in, '\t') ? 1 : 0; | ||
618 | //const char *savein = in; | ||
619 | |||
620 | char mode = has_name ? 'n' : 'w'; // parse mode: n=name, w=wildcard | ||
621 | int nwildcards = 0; | ||
622 | char wildcards[MAXFILTERS][1024]; // parsed wildcards (can be several) | ||
623 | char wildprefix[512] = ""; | ||
624 | char name[512] = ""; | ||
625 | |||
626 | // Init | ||
627 | int t; | ||
628 | for ( t=0; t<MAXFILTERS; t++ ) { | ||
629 | wildcards[t][0] = '\0'; | ||
630 | } | ||
631 | |||
632 | // Parse | ||
633 | for ( ; 1; in++ ) { | ||
634 | |||
635 | //// DEBUG | ||
636 | //// printf("WORKING ON '%c': mode=<%c> name=<%s> wildprefix=<%s> nwildcards=%d wildcards[n]=<%s>\n", | ||
637 | //// *in, mode, name, wildprefix, nwildcards, wildcards[nwildcards]); | ||
638 | |||
639 | switch (*in) { | ||
640 | case ',': | ||
641 | case '|': | ||
642 | if ( mode == LCURLY_CHR ) { | ||
643 | // create new wildcard, copy in prefix | ||
644 | strcat(wildcards[nwildcards++], wildprefix); | ||
645 | continue; | ||
646 | } else { | ||
647 | goto regchar; | ||
648 | } | ||
649 | continue; | ||
650 | |||
651 | // FINISHED PARSING A NAME? | ||
652 | case '\t': | ||
653 | if ( mode != 'n' ) goto regchar; | ||
654 | // finish parsing name? switch to wildcard mode | ||
655 | mode = 'w'; | ||
656 | break; | ||
657 | |||
658 | // ESCAPE NEXT CHAR | ||
659 | case '\\': | ||
660 | ++in; | ||
661 | goto regchar; | ||
662 | |||
663 | // FINISHED PARSING ONE OF POSSIBLY SEVERAL FILTERS? | ||
664 | case '\r': | ||
665 | case '\n': | ||
666 | case '\0': | ||
667 | { | ||
668 | if ( mode == 'w' ) { // finished parsing wildcard? | ||
669 | if ( nwildcards == 0 ) { | ||
670 | strcpy(wildcards[nwildcards++], wildprefix); | ||
671 | } | ||
672 | // Append wildcards in Microsoft's "*.one;*.two" format | ||
673 | char comp[4096] = ""; | ||
674 | for ( t=0; t<nwildcards; t++ ) { | ||
675 | if ( t != 0 ) strcat(comp, ";"); | ||
676 | strcat(comp, wildcards[t]); | ||
677 | } | ||
678 | // Add if not empty | ||
679 | if ( comp[0] ) { | ||
680 | add_filter(name, comp); | ||
681 | } | ||
682 | } | ||
683 | // RESET | ||
684 | for ( t=0; t<MAXFILTERS; t++ ) { | ||
685 | wildcards[t][0] = '\0'; | ||
686 | } | ||
687 | nwildcards = 0; | ||
688 | wildprefix[0] = name[0] = '\0'; | ||
689 | mode = strchr(in,'\t') ? 'n' : 'w'; | ||
690 | // DONE? | ||
691 | if ( *in == '\0' ) return; // done | ||
692 | continue; // not done yet, more filters | ||
693 | } | ||
694 | |||
695 | // STARTING A WILDCARD? | ||
696 | case LBRACKET_CHR: | ||
697 | case LCURLY_CHR: | ||
698 | mode = *in; | ||
699 | if ( *in == LCURLY_CHR ) { | ||
700 | // create new wildcard | ||
701 | strcat(wildcards[nwildcards++], wildprefix); | ||
702 | } | ||
703 | continue; | ||
704 | |||
705 | // ENDING A WILDCARD? | ||
706 | case RBRACKET_CHR: | ||
707 | case RCURLY_CHR: | ||
708 | mode = 'w'; // back to wildcard mode | ||
709 | continue; | ||
710 | |||
711 | // ALL OTHER NON-SPECIAL CHARACTERS | ||
712 | default: | ||
713 | regchar: // handle regular char | ||
714 | switch ( mode ) { | ||
715 | case LBRACKET_CHR: | ||
716 | // create new wildcard | ||
717 | ++nwildcards; | ||
718 | // copy in prefix | ||
719 | strcpy(wildcards[nwildcards-1], wildprefix); | ||
720 | // append search char | ||
721 | chrcat(wildcards[nwildcards-1], *in); | ||
722 | continue; | ||
723 | |||
724 | case LCURLY_CHR: | ||
725 | if ( nwildcards > 0 ) { | ||
726 | chrcat(wildcards[nwildcards-1], *in); | ||
727 | } | ||
728 | continue; | ||
729 | |||
730 | case 'n': | ||
731 | chrcat(name, *in); | ||
732 | continue; | ||
733 | |||
734 | case 'w': | ||
735 | chrcat(wildprefix, *in); | ||
736 | for ( t=0; t<nwildcards; t++ ) { | ||
737 | chrcat(wildcards[t], *in); | ||
738 | } | ||
739 | continue; | ||
740 | } | ||
741 | break; | ||
742 | } | ||
743 | } | ||
744 | } | ||
745 | |||
746 | // SET 'CURRENTLY SELECTED FILTER' | ||
747 | void Fl_Native_File_Chooser::filter_value(int i) { | ||
748 | _ofn.nFilterIndex = i + 1; | ||
749 | } | ||
750 | |||
751 | // RETURN VALUE OF 'CURRENTLY SELECTED FILTER' | ||
752 | int Fl_Native_File_Chooser::filter_value() const { | ||
753 | return(_ofn.nFilterIndex ? _ofn.nFilterIndex-1 : _nfilters+1); | ||
754 | } | ||
755 | |||
756 | // PRESET FILENAME FOR 'SAVE AS' CHOOSER | ||
757 | void Fl_Native_File_Chooser::preset_file(const char* val) { | ||
758 | _preset_file = strfree(_preset_file); | ||
759 | _preset_file = strnew(val); | ||
760 | } | ||
761 | |||
762 | // GET PRESET FILENAME FOR 'SAVE AS' CHOOSER | ||
763 | const char* Fl_Native_File_Chooser::preset_file() const { | ||
764 | return(_preset_file); | ||
765 | } | ||
diff --git a/src/lib/FL/WidgetPDial.fl b/src/lib/FL/WidgetPDial.fl new file mode 100644 index 0000000..5b7ec05 --- /dev/null +++ b/src/lib/FL/WidgetPDial.fl | |||
@@ -0,0 +1,131 @@ | |||
1 | # data file for the Fltk User Interface Designer (fluid) | ||
2 | version 1.0105 | ||
3 | header_name {.h} | ||
4 | code_name {.cc} | ||
5 | decl {//Copyright (c) 2003-2005 Nasca Octavian Paul} {} | ||
6 | |||
7 | decl {//License: GNU GPL version 2 or later} {} | ||
8 | |||
9 | decl {\#include <FL/Fl_Dial.H>} {public | ||
10 | } | ||
11 | |||
12 | decl {\#include <FL/fl_draw.H>} {public | ||
13 | } | ||
14 | |||
15 | decl {\#include <stdio.h>} {public | ||
16 | } | ||
17 | |||
18 | decl {\#include <math.h>} {public | ||
19 | } | ||
20 | |||
21 | class WidgetPDial {: {public Fl_Dial} | ||
22 | } { | ||
23 | Function {WidgetPDial(int x,int y, int w, int h, const char *label=0):Fl_Dial(x,y,w,h,label)} {} { | ||
24 | code {oldvalue=0.0;} {} | ||
25 | } | ||
26 | Function {handle(int event)} {return_type int | ||
27 | } { | ||
28 | code {double dragsize,v,min=minimum(),max=maximum(); | ||
29 | int my; | ||
30 | |||
31 | switch (event){ | ||
32 | case FL_PUSH:oldvalue=value(); | ||
33 | case FL_DRAG: | ||
34 | my=-(Fl::event_y()-y()-h()/2); | ||
35 | |||
36 | dragsize=200.0; | ||
37 | if (Fl::event_state(FL_BUTTON1)==0) dragsize*=10; | ||
38 | v=oldvalue+my/dragsize*(max-min); | ||
39 | if (v<min) v=min; | ||
40 | else if (v>max) v=max; | ||
41 | |||
42 | //printf("%d %g %g\\n",my,v,oldvalue); | ||
43 | value(v); | ||
44 | value_damage(); | ||
45 | if (this->when()!=0) do_callback(); | ||
46 | return(1); | ||
47 | break; | ||
48 | case FL_RELEASE: | ||
49 | if (this->when()==0) do_callback(); | ||
50 | return(1); | ||
51 | break; | ||
52 | }; | ||
53 | return(0);} {selected | ||
54 | } | ||
55 | } | ||
56 | Function {drawgradient(int cx,int cy,int sx,double m1,double m2)} {return_type void | ||
57 | } { | ||
58 | code {for (int i=(int)(m1*sx);i<(int)(m2*sx);i++){ | ||
59 | double tmp=1.0-pow(i*1.0/sx,2.0); | ||
60 | pdialcolor(140+(int) (tmp*90),140+(int)(tmp*90),140+(int) (tmp*100)); | ||
61 | fl_arc(cx+sx/2-i/2,cy+sx/2-i/2,i,i,0,360); | ||
62 | };} {} | ||
63 | } | ||
64 | Function {draw()} {} { | ||
65 | code {int cx=x(),cy=y(),sx=w(),sy=h(); | ||
66 | |||
67 | |||
68 | //clears the button face | ||
69 | pdialcolor(190,190,200); | ||
70 | fl_pie(cx-1,cy-1,sx+2,sy+2,0,360); | ||
71 | |||
72 | //Draws the button face (gradinet) | ||
73 | drawgradient(cx,cy,sx,0.5,1.0); | ||
74 | |||
75 | double val=(value()-minimum())/(maximum()-minimum()); | ||
76 | |||
77 | //draws the scale | ||
78 | pdialcolor(220,220,250); | ||
79 | double a1=angle1(),a2=angle2(); | ||
80 | for (int i=0;i<12;i++){ | ||
81 | double a=-i/12.0*360.0-val*(a2-a1)-a1; | ||
82 | fl_pie(cx,cy,sx,sy,a+270-3,a+3+270); | ||
83 | }; | ||
84 | |||
85 | drawgradient(cx,cy,sx,0.0,0.75); | ||
86 | |||
87 | //draws the value | ||
88 | double a=-(a2-a1)*val-a1; | ||
89 | |||
90 | |||
91 | |||
92 | |||
93 | |||
94 | //draws the max and min points | ||
95 | pdialcolor(0,100,200); | ||
96 | int xp=(int)(cx+sx/2.0+sx/2.0*sin(angle1()/180.0*3.141592)); | ||
97 | int yp=(int)(cy+sy/2.0+sy/2.0*cos(angle1()/180.0*3.141592)); | ||
98 | fl_pie(xp-2,yp-2,4,4,0,360); | ||
99 | |||
100 | xp=(int)(cx+sx/2.0+sx/2.0*sin(angle2()/180.0*3.141592)); | ||
101 | yp=(int)(cy+sy/2.0+sy/2.0*cos(angle2()/180.0*3.141592)); | ||
102 | fl_pie(xp-2,yp-2,4,4,0,360); | ||
103 | |||
104 | |||
105 | |||
106 | |||
107 | |||
108 | fl_push_matrix(); | ||
109 | |||
110 | fl_translate(cx+sx/2,cy+sy/2); | ||
111 | fl_rotate(a-90.0); | ||
112 | |||
113 | fl_translate(sx/2,0); | ||
114 | |||
115 | |||
116 | fl_begin_polygon(); | ||
117 | pdialcolor(0,0,0); | ||
118 | fl_vertex(-10,-4); | ||
119 | fl_vertex(-10,4); | ||
120 | fl_vertex(0,0); | ||
121 | fl_end_polygon(); | ||
122 | |||
123 | |||
124 | fl_pop_matrix();} {} | ||
125 | } | ||
126 | Function {pdialcolor(int r,int g,int b)} {} { | ||
127 | code {if (active_r()) fl_color(r,g,b); | ||
128 | else fl_color(160-(160-r)/3,160-(160-b)/3,160-(160-b)/3);} {} | ||
129 | } | ||
130 | decl {double oldvalue;} {} | ||
131 | } | ||
diff --git a/src/lib/FL/common.cxx b/src/lib/FL/common.cxx new file mode 100644 index 0000000..852b0e7 --- /dev/null +++ b/src/lib/FL/common.cxx | |||
@@ -0,0 +1,60 @@ | |||
1 | // COPY A STRING WITH 'new' | ||
2 | // Value can be NULL | ||
3 | // | ||
4 | static char *strnew(const char *val) | ||
5 | { | ||
6 | if ( val == NULL ) | ||
7 | return(NULL); | ||
8 | |||
9 | char *s = new char[strlen(val)+1]; | ||
10 | strcpy(s, val); | ||
11 | |||
12 | return(s); | ||
13 | } | ||
14 | |||
15 | // FREE STRING CREATED WITH strnew(), NULLS OUT STRING | ||
16 | // Value can be NULL | ||
17 | // | ||
18 | static char *strfree(char *val) | ||
19 | { | ||
20 | if ( val ) | ||
21 | delete [] val; | ||
22 | |||
23 | return(NULL); | ||
24 | } | ||
25 | |||
26 | // 'DYNAMICALLY' APPEND ONE STRING TO ANOTHER | ||
27 | // Returns newly allocated string, or NULL | ||
28 | // if s && val == NULL. | ||
29 | // 's' can be NULL; returns a strnew(val). | ||
30 | // 'val' can be NULL; s is returned unmodified. | ||
31 | // | ||
32 | // Usage: | ||
33 | // char *s = strnew("foo"); // s = "foo" | ||
34 | // s = strapp(s, "bar"); // s = "foobar" | ||
35 | // | ||
36 | #ifndef WINDOWS | ||
37 | static char *strapp(char *s, const char *val) | ||
38 | { | ||
39 | if ( ! val ) | ||
40 | return(s); // Nothing to append? return s | ||
41 | |||
42 | if ( ! s ) | ||
43 | return(strnew(val)); // New string? return copy of val | ||
44 | |||
45 | char *news = new char[strlen(s)+strlen(val)+1]; | ||
46 | strcpy(news, s); | ||
47 | strcat(news, val); | ||
48 | |||
49 | delete [] s; // delete old string | ||
50 | return(news); // return new copy | ||
51 | } | ||
52 | #endif | ||
53 | // APPEND A CHARACTER TO A STRING | ||
54 | static void chrcat(char *s, char c) | ||
55 | { | ||
56 | char tmp[2] = { c, '\0' };; | ||
57 | strcat(s, tmp); | ||
58 | } | ||
59 | |||
60 | |||
diff --git a/src/lib/config.h b/src/lib/config.h new file mode 100755 index 0000000..cd5e634 --- /dev/null +++ b/src/lib/config.h | |||
@@ -0,0 +1,11 @@ | |||
1 | #ifdef WINDOWS | ||
2 | # define __sint64 signed __int64 | ||
3 | # define __uint64 unsigned __int64 | ||
4 | #else | ||
5 | # define __sint64 signed long long | ||
6 | # define __uint64 unsigned long long | ||
7 | #endif | ||
8 | |||
9 | #define __sint32 signed long | ||
10 | #define __uint32 unsigned long | ||
11 | |||
diff --git a/src/lib/convertlib.cpp b/src/lib/convertlib.cpp new file mode 100755 index 0000000..ebbfaff --- /dev/null +++ b/src/lib/convertlib.cpp | |||
@@ -0,0 +1,311 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include "convertlib.h" | ||
3 | |||
4 | bool Convert::isnibble(string x) | ||
5 | { | ||
6 | if ((x >= "0") && (x <= "9")) return true; | ||
7 | if ((x >= "a") && (x <= "f")) return true; | ||
8 | if ((x >= "A") && (x <= "F")) return true; | ||
9 | return false; | ||
10 | } | ||
11 | |||
12 | string* Convert::byte2hex(unsigned char x) | ||
13 | { | ||
14 | int b = x % 16; | ||
15 | int a = x >> 4; | ||
16 | |||
17 | string hex = "0123456789ABCDEF"; | ||
18 | string * newst = new string(""); | ||
19 | *newst = *newst + hex.substr(a, 1); | ||
20 | *newst = *newst + hex.substr(b, 1); | ||
21 | return newst; | ||
22 | } | ||
23 | |||
24 | long Convert::str2long(string decstr) | ||
25 | { | ||
26 | return strtol(decstr.c_str(), 0, 10); | ||
27 | } | ||
28 | |||
29 | double Convert::str2dbl(string decstr) | ||
30 | { | ||
31 | return strtod(decstr.c_str(), 0); | ||
32 | } | ||
33 | |||
34 | string* Convert::int2str(int x, unsigned int pad, string padchar) | ||
35 | { | ||
36 | string* newst = int2str(x); | ||
37 | |||
38 | if (pad > 1) | ||
39 | { | ||
40 | while (newst->length() < pad) | ||
41 | { | ||
42 | *newst = padchar + *newst; | ||
43 | } | ||
44 | } | ||
45 | |||
46 | return newst; | ||
47 | } | ||
48 | |||
49 | string* Convert::int64tostr(__sint64 x) | ||
50 | { | ||
51 | bool isneg=false; | ||
52 | string * newst = new string(""); | ||
53 | if (x == 0) | ||
54 | { | ||
55 | *newst = "0"; | ||
56 | } | ||
57 | else | ||
58 | { | ||
59 | if (x<0) | ||
60 | { | ||
61 | isneg=true; | ||
62 | x=0-x; | ||
63 | } | ||
64 | while (x != 0) | ||
65 | { | ||
66 | long long digit = x % (long long) 10; | ||
67 | string dec = "0123456789"; | ||
68 | *newst = dec.substr(digit, 1) + *newst; | ||
69 | |||
70 | x -= (long long) (x % (long long) 10); | ||
71 | x /= (long long) 10; | ||
72 | } | ||
73 | } | ||
74 | if (isneg) | ||
75 | { | ||
76 | *newst="-"+*newst; | ||
77 | } | ||
78 | return newst; | ||
79 | } | ||
80 | |||
81 | string* Convert::int2str(int x) | ||
82 | { | ||
83 | long long y = x; | ||
84 | return int64tostr(y); | ||
85 | } | ||
86 | |||
87 | string* Convert::int32tostr(__uint32 x) | ||
88 | { | ||
89 | long long y = x; | ||
90 | return int64tostr(y); | ||
91 | } | ||
92 | |||
93 | long Convert::hex2long(string hexstr) | ||
94 | { | ||
95 | return strtol(hexstr.c_str(), 0, 16); | ||
96 | } | ||
97 | |||
98 | unsigned char Convert::hex2byte(string hexstr) | ||
99 | { | ||
100 | long x = hex2long(hexstr); | ||
101 | return (unsigned char) x % 256; | ||
102 | } | ||
103 | |||
104 | unsigned char Convert::safebyte(unsigned char x) | ||
105 | { | ||
106 | if (x < 32) return '.'; | ||
107 | return x; | ||
108 | } | ||
109 | |||
110 | string* Convert::int64tohex(__sint64 x) | ||
111 | { | ||
112 | __sint64 q = x; | ||
113 | unsigned char a = q % 256; q = q >> 8; | ||
114 | unsigned char b = q % 256; q = q >> 8; | ||
115 | unsigned char c = q % 256; q = q >> 8; | ||
116 | unsigned char d = q % 256; q = q >> 8; | ||
117 | unsigned char e = q % 256; q = q >> 8; | ||
118 | unsigned char f = q % 256; q = q >> 8; | ||
119 | unsigned char g = q % 256; q = q >> 8; | ||
120 | unsigned char h = q % 256; | ||
121 | string* b2h8 = byte2hex(h); | ||
122 | string* b2h7 = byte2hex(g); | ||
123 | string* b2h6 = byte2hex(f); | ||
124 | string* b2h5 = byte2hex(e); | ||
125 | string* b2h4 = byte2hex(d); | ||
126 | string* b2h3 = byte2hex(c); | ||
127 | string* b2h2 = byte2hex(b); | ||
128 | string* b2h1 = byte2hex(a); | ||
129 | string* newst = new string(); | ||
130 | *newst += *b2h8 + *b2h7 + ":" + *b2h6 + *b2h5 + "." + *b2h4 + *b2h3 + ":" + *b2h2 + *b2h1; | ||
131 | delete (b2h1); | ||
132 | delete (b2h2); | ||
133 | delete (b2h3); | ||
134 | delete (b2h4); | ||
135 | delete (b2h5); | ||
136 | delete (b2h6); | ||
137 | delete (b2h7); | ||
138 | delete (b2h8); | ||
139 | return newst; | ||
140 | } | ||
141 | |||
142 | string* Convert::int32tohex(unsigned long x) | ||
143 | { | ||
144 | __sint64 q = x; | ||
145 | unsigned char a = q % 256; q = q >> 8; | ||
146 | unsigned char b = q % 256; q = q >> 8; | ||
147 | unsigned char c = q % 256; q = q >> 8; | ||
148 | unsigned char d = q % 256; q = q >> 8; | ||
149 | string* b2h4 = byte2hex(d); | ||
150 | string* b2h3 = byte2hex(c); | ||
151 | string* b2h2 = byte2hex(b); | ||
152 | string* b2h1 = byte2hex(a); | ||
153 | string* newst = new string(); | ||
154 | *newst += *b2h4 + *b2h3 + ":" + *b2h2 + *b2h1; | ||
155 | delete (b2h1); | ||
156 | delete (b2h2); | ||
157 | delete (b2h3); | ||
158 | delete (b2h4); | ||
159 | return newst; | ||
160 | } | ||
161 | |||
162 | unsigned int Convert::getint24(unsigned char * buf, int loc) | ||
163 | { | ||
164 | unsigned int q = 0; | ||
165 | |||
166 | q = buf[loc + 2] | ||
167 | + (buf[loc + 1] << 8) | ||
168 | + (buf [loc + 0] << 16); | ||
169 | return q; | ||
170 | } | ||
171 | |||
172 | |||
173 | unsigned int Convert::getint32(unsigned char * buf, int loc) | ||
174 | { | ||
175 | unsigned int q = 0; | ||
176 | |||
177 | q = buf[loc + 3] | ||
178 | + (buf[loc + 2] << 8) | ||
179 | + (buf [loc + 1] << 16) | ||
180 | + (buf [loc] << 24); | ||
181 | return q; | ||
182 | } | ||
183 | |||
184 | void Convert::setint32(unsigned char * buf, int loc, __uint32 newval) | ||
185 | { | ||
186 | buf[loc + 0] = (newval >> 24) % 256; | ||
187 | buf[loc + 1] = (newval >> 16) % 256; | ||
188 | buf[loc + 2] = (newval >> 8) % 256; | ||
189 | buf[loc + 3] = newval % 256; | ||
190 | } | ||
191 | |||
192 | void Convert::setfloat80(unsigned char * buf, int loc, __uint32 newval) | ||
193 | { | ||
194 | /* Thanks, Erik */ | ||
195 | unsigned int mask = 0x40000000 ; | ||
196 | int count ; | ||
197 | |||
198 | for (int i=0;i<10;i++) | ||
199 | { | ||
200 | buf[loc+i]=0; | ||
201 | } | ||
202 | if (newval <= 1) | ||
203 | { buf[loc+0] = 0x3F ; | ||
204 | buf[loc+1] = 0xFF ; | ||
205 | buf[loc+2] = 0x80 ; | ||
206 | return ; | ||
207 | } ; | ||
208 | |||
209 | buf[loc+0] = 0x40 ; | ||
210 | |||
211 | if (newval >= mask) | ||
212 | { buf[loc+1] = 0x1D ; | ||
213 | return ; | ||
214 | } ; | ||
215 | |||
216 | for (count = 0 ; count <= 32 ; count ++) | ||
217 | { if (newval & mask) | ||
218 | break ; | ||
219 | mask >>= 1 ; | ||
220 | } ; | ||
221 | |||
222 | newval <<= count + 1 ; | ||
223 | buf[loc+1] = 29 - count ; | ||
224 | buf[loc+2] = (newval >> 24) & 0xFF ; | ||
225 | buf[loc+3] = (newval >> 16) & 0xFF ; | ||
226 | buf[loc+4] = (newval >> 8) & 0xFF ; | ||
227 | buf[loc+5] = newval & 0xFF ; | ||
228 | return; | ||
229 | } | ||
230 | |||
231 | string* Convert::readstring(unsigned char * orig, int offset, int len) | ||
232 | { | ||
233 | string * newst = new string(""); | ||
234 | int i; | ||
235 | |||
236 | for (i = offset; i < offset + len; i++) | ||
237 | { | ||
238 | if (i >= offset + len) | ||
239 | return newst; | ||
240 | |||
241 | if (orig[i] == 0) break; | ||
242 | *newst += orig[i]; | ||
243 | } | ||
244 | |||
245 | return newst; | ||
246 | } | ||
247 | |||
248 | string* Convert::padright(string & strinput, int inlen, string strpad) | ||
249 | { | ||
250 | int currlen = strinput.length(); | ||
251 | |||
252 | if (currlen > inlen) | ||
253 | { | ||
254 | strinput=strinput.substr(0,inlen); | ||
255 | return new string(strinput); | ||
256 | } | ||
257 | |||
258 | int pad = inlen - currlen; | ||
259 | if (pad > 0) | ||
260 | { | ||
261 | for (int i = 0; i < pad; i++) | ||
262 | { | ||
263 | strinput += strpad; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | return new string(strinput); | ||
268 | } | ||
269 | |||
270 | string* Convert::padleft(string & strinput, int inlen, string strpad) | ||
271 | { | ||
272 | int currlen = strinput.length(); | ||
273 | |||
274 | if (currlen > inlen) | ||
275 | { | ||
276 | return new string(strinput.substr(0, inlen)); | ||
277 | } | ||
278 | |||
279 | int pad = inlen - currlen; | ||
280 | if (pad > 0) | ||
281 | { | ||
282 | string strtmp = ""; | ||
283 | for (int i = 0; i < pad; i++) | ||
284 | { | ||
285 | strtmp += strpad; | ||
286 | } | ||
287 | strinput = strtmp + strinput; | ||
288 | } | ||
289 | return new string(strinput); | ||
290 | } | ||
291 | |||
292 | string* Convert::trim(string* strinput) | ||
293 | { | ||
294 | if (strinput->length() == 0) | ||
295 | { | ||
296 | string* x = new string(""); | ||
297 | return x; | ||
298 | } | ||
299 | |||
300 | string* strresult = new string(*strinput); | ||
301 | while (strresult->substr(0, 1) == " ") | ||
302 | { | ||
303 | *strresult = strresult->substr(1, strresult->length() - 1); | ||
304 | } | ||
305 | |||
306 | while (strresult->substr(strresult->length() - 1, 1) == " ") | ||
307 | { | ||
308 | *strresult = strresult->substr(0, strresult->length() - 1); | ||
309 | } | ||
310 | return strresult; | ||
311 | } | ||
diff --git a/src/lib/convertlib.h b/src/lib/convertlib.h new file mode 100755 index 0000000..3e742ff --- /dev/null +++ b/src/lib/convertlib.h | |||
@@ -0,0 +1,39 @@ | |||
1 | #ifndef __convert_h__ | ||
2 | #define __convert_h__ | ||
3 | |||
4 | using namespace std; | ||
5 | |||
6 | #include "config.h" | ||
7 | #include <string> | ||
8 | #include <iostream> | ||
9 | |||
10 | class Convert | ||
11 | { | ||
12 | public: | ||
13 | Convert() {}; | ||
14 | ~Convert() {}; | ||
15 | |||
16 | static bool isnibble(string x); | ||
17 | static long str2long(string hexstr); | ||
18 | static double str2dbl(string hexstr); | ||
19 | static long hex2long(string hexstr); | ||
20 | static string* byte2hex(unsigned char x); | ||
21 | static string* int2str(int x,unsigned int pad,string padchar); | ||
22 | static string* int2str(int x); | ||
23 | static string* int32tostr(__uint32 x); | ||
24 | static string* int64tostr(__sint64 x); | ||
25 | static string* int64tohex(__sint64 x); | ||
26 | static string* int32tohex(unsigned long x); | ||
27 | static string* readstring(unsigned char * orig,int offset,int len); | ||
28 | static string* padright(string & strinput,int inlen,string strpad); | ||
29 | static string* padleft(string & strinput,int inlen,string strpad); | ||
30 | static unsigned int getint32(unsigned char * buf,int loc); | ||
31 | static unsigned int getint24(unsigned char * buf,int loc); | ||
32 | static void setint32(unsigned char * buf,int loc,__uint32 newval); | ||
33 | static void setfloat80(unsigned char * buf, int loc, __uint32 newval); /* Only for use in AIFF files */ | ||
34 | static unsigned char hex2byte(string hexstr); | ||
35 | static unsigned char safebyte(unsigned char x); | ||
36 | static string* trim(string* strinput); | ||
37 | }; | ||
38 | |||
39 | #endif | ||
diff --git a/src/lib/hd24devicenamegenerator.cpp b/src/lib/hd24devicenamegenerator.cpp new file mode 100644 index 0000000..99ad4a7 --- /dev/null +++ b/src/lib/hd24devicenamegenerator.cpp | |||
@@ -0,0 +1,286 @@ | |||
1 | #include "hd24devicenamegenerator.h" | ||
2 | #define DEVGENDEBUG 0 | ||
3 | #include <stdio.h> | ||
4 | #include <string.h> | ||
5 | #include <stdlib.h> | ||
6 | #ifdef DARWIN | ||
7 | #include <sys/malloc.h> | ||
8 | #else | ||
9 | #include <malloc.h> | ||
10 | #endif | ||
11 | #include <sys/types.h> | ||
12 | #include <dirent.h> | ||
13 | int endswith(const char* str, const char* end) | ||
14 | { | ||
15 | #if (DEVGENDEBUG==1) | ||
16 | cout << "endswith("<<str<<","<<end<<")"<<endl; | ||
17 | #endif | ||
18 | if (str==NULL) return false; | ||
19 | if (end==NULL) return false; | ||
20 | size_t str_len = strlen(str); | ||
21 | size_t end_len = strlen(end); | ||
22 | if (str_len<end_len) return false; | ||
23 | |||
24 | const char *str_end = str + str_len - end_len; | ||
25 | return strcmp(str_end, end) == 0; | ||
26 | } | ||
27 | |||
28 | __uint32 hd24devicenamegenerator::hd24filecount(const char* dirname) | ||
29 | { | ||
30 | #if (DEVGENDEBUG==1) | ||
31 | cout << "hd24devicenamegenerator::hd24filecount("<<dirname<<")"<< endl; | ||
32 | #endif | ||
33 | unsigned char isFile =0x8; | ||
34 | DIR *Dir; | ||
35 | struct dirent *DirEntry; | ||
36 | Dir = opendir(dirname); | ||
37 | |||
38 | int foundcount=0; | ||
39 | do | ||
40 | { | ||
41 | DirEntry=readdir(Dir); | ||
42 | if (!DirEntry) break; | ||
43 | if ( DirEntry->d_type != isFile) continue; | ||
44 | |||
45 | if (!( endswith(DirEntry->d_name,".h24") | ||
46 | ||endswith(DirEntry->d_name,".H24"))) continue; | ||
47 | |||
48 | foundcount++; | ||
49 | |||
50 | if (filelist==NULL) | ||
51 | { | ||
52 | filelist=new vector<string>(); | ||
53 | } | ||
54 | string* fname=new string(dirname); | ||
55 | *fname+=DirEntry->d_name; | ||
56 | filelist->push_back(*fname); | ||
57 | #if (DEVGENDEBUG==1) | ||
58 | cout <<"Found a File : " << *fname << endl; | ||
59 | #endif | ||
60 | delete fname; | ||
61 | |||
62 | // validity of file image will be extablished by hd24fs device scan | ||
63 | } while(1); | ||
64 | |||
65 | return foundcount; | ||
66 | } | ||
67 | |||
68 | void hd24devicenamegenerator::initvars() | ||
69 | { | ||
70 | imagespath=NULL; | ||
71 | filelist=NULL; | ||
72 | filecount=0; // cache for getnumberoffiles | ||
73 | } | ||
74 | |||
75 | void hd24devicenamegenerator::clearfilelist() | ||
76 | { | ||
77 | if (filelist==NULL) | ||
78 | { | ||
79 | return; | ||
80 | } | ||
81 | while (filelist->size()!=0) | ||
82 | { | ||
83 | filelist->pop_back(); | ||
84 | } | ||
85 | delete filelist; | ||
86 | filelist=NULL; | ||
87 | } | ||
88 | |||
89 | hd24devicenamegenerator::~hd24devicenamegenerator() | ||
90 | { | ||
91 | clearfilelist(); | ||
92 | } | ||
93 | hd24devicenamegenerator::hd24devicenamegenerator() | ||
94 | { | ||
95 | initvars(); | ||
96 | } | ||
97 | |||
98 | const char* hd24devicenamegenerator::imagedir() | ||
99 | { | ||
100 | #if (DEVGENDEBUG==1) | ||
101 | cout << "hd24devicenamegenerator::imagedir()"<<endl; | ||
102 | #endif | ||
103 | return imagespath; | ||
104 | } | ||
105 | |||
106 | const char* hd24devicenamegenerator::imagedir(const char* newdir) | ||
107 | { | ||
108 | #if (DEVGENDEBUG==1) | ||
109 | if (newdir==NULL) | ||
110 | { | ||
111 | cout << "hd24devicenamegenerator::imagedir(NULL)"<< endl; | ||
112 | } | ||
113 | else | ||
114 | { | ||
115 | cout << "hd24devicenamegenerator::imagedir("<<newdir<<")"<< endl; | ||
116 | } | ||
117 | #endif | ||
118 | |||
119 | filecount=0; | ||
120 | clearfilelist(); | ||
121 | |||
122 | if (imagespath!=NULL) | ||
123 | { | ||
124 | free (imagespath); | ||
125 | imagespath=NULL; | ||
126 | } | ||
127 | |||
128 | if (newdir!=NULL) | ||
129 | { | ||
130 | imagespath=(char*)malloc(strlen(newdir)+1); | ||
131 | if (imagespath!=NULL) | ||
132 | { | ||
133 | strncpy(imagespath,newdir,strlen(newdir)+1); | ||
134 | } | ||
135 | #if (DEVGENDEBUG==1) | ||
136 | cout << "new images path is " ; | ||
137 | if (imagespath==NULL) | ||
138 | { | ||
139 | cout << "NULL" << endl; | ||
140 | } else { | ||
141 | cout << imagespath << endl; | ||
142 | } | ||
143 | #endif | ||
144 | } | ||
145 | |||
146 | return (const char*)imagespath; | ||
147 | } | ||
148 | |||
149 | __uint32 hd24devicenamegenerator::getnumberoffiles() | ||
150 | { | ||
151 | #if (DEVGENDEBUG==1) | ||
152 | cout << "hd24devicenamegenerator::getnumberoffiles()"<< endl; | ||
153 | #endif | ||
154 | // Files in the image directory will also be considered devices. | ||
155 | if (filecount==0) | ||
156 | { | ||
157 | if (imagedir()==NULL) | ||
158 | { | ||
159 | return 0; | ||
160 | } | ||
161 | // retrieve a list of .h24 image files. | ||
162 | filecount=hd24filecount(imagedir()); | ||
163 | } | ||
164 | return filecount; | ||
165 | } | ||
166 | |||
167 | __uint32 hd24devicenamegenerator::getnumberofsysdevs() | ||
168 | { | ||
169 | #if (DEVGENDEBUG==1) | ||
170 | cout << "hd24devicenamegenerator::getnumberofsysdevs()"<< endl; | ||
171 | #endif | ||
172 | #ifdef LINUX | ||
173 | // For linux the total number of names is 26x /dev/hd* + 26x /dev/sd* | ||
174 | return 52; | ||
175 | #endif | ||
176 | #ifdef WINDOWS | ||
177 | return 128; | ||
178 | #endif | ||
179 | #ifdef DARWIN | ||
180 | return 100; | ||
181 | #endif | ||
182 | } | ||
183 | |||
184 | __uint32 hd24devicenamegenerator::getnumberofnames() | ||
185 | { | ||
186 | #if (DEVGENDEBUG==1) | ||
187 | cout << "hd24devicenamegenerator::getnumberofnames()"<< endl; | ||
188 | #endif | ||
189 | __uint32 filecount=this->getnumberoffiles(); | ||
190 | __uint32 devcount=this->getnumberofsysdevs(); | ||
191 | #if (DEVGENDEBUG==1) | ||
192 | cout << "return: filecount="<<filecount<<", devcount="<<devcount<<endl; | ||
193 | #endif | ||
194 | return filecount+devcount; | ||
195 | } | ||
196 | |||
197 | const char* hd24devicenamegenerator::getfilename(__uint32 filenum) | ||
198 | { | ||
199 | #if (DEVGENDEBUG==1) | ||
200 | cout << "hd24devicenamegenerator::getfilename("<<filenum<<")"<< endl; | ||
201 | #endif | ||
202 | // Given the list of files, this will return the Nth name (base 0). | ||
203 | if (filelist==NULL) | ||
204 | { | ||
205 | return ""; | ||
206 | } | ||
207 | if (filelist->size()==0) | ||
208 | { | ||
209 | return ""; | ||
210 | } | ||
211 | return filelist->at(filenum).c_str(); | ||
212 | } | ||
213 | |||
214 | #ifdef LINUX | ||
215 | string* hd24devicenamegenerator::getdevicename(__uint32 devicenumber) | ||
216 | { | ||
217 | #if (DEVGENDEBUG==1) | ||
218 | cout << "hd24devicenamegenerator::getdevicename("<<devicenumber<<")"<< endl; | ||
219 | #endif | ||
220 | if (devicenumber>=this->getnumberofsysdevs()) | ||
221 | { | ||
222 | return new string(getfilename(devicenumber-this->getnumberofsysdevs())); | ||
223 | } | ||
224 | string* devname; | ||
225 | __uint32 devgroup = devicenumber; | ||
226 | devicenumber = (devicenumber%26); | ||
227 | devgroup -= devicenumber; | ||
228 | devgroup /= 26; | ||
229 | |||
230 | switch (devgroup) | ||
231 | { | ||
232 | case 0: | ||
233 | devname = new string("/dev/hd"); | ||
234 | break; | ||
235 | case 1: | ||
236 | devname = new string("/dev/sd"); | ||
237 | break; | ||
238 | default: | ||
239 | return new string(""); | ||
240 | } | ||
241 | |||
242 | char devletter = (char) ('a' + devicenumber); | ||
243 | *devname += devletter; | ||
244 | |||
245 | return devname; | ||
246 | } | ||
247 | #endif | ||
248 | |||
249 | #ifdef WINDOWS | ||
250 | |||
251 | string* hd24devicenamegenerator::getdevicename(__uint32 devicenumber) | ||
252 | { | ||
253 | #if (DEVGENDEBUG==1) | ||
254 | cout << "hd24devicenamegenerator::getdevicename("<<devicenumber<<")"<< endl; | ||
255 | #endif | ||
256 | if (devicenumber>=this->getnumberofsysdevs()) | ||
257 | { | ||
258 | return new string(getfilename(devicenumber-this->getnumberofsysdevs())); | ||
259 | } | ||
260 | |||
261 | string* devname = new string("//./PHYSICALDRIVE"); | ||
262 | string* devnum = Convert::int2str(devicenumber); | ||
263 | *devname += *devnum; | ||
264 | delete devnum; | ||
265 | return devname; | ||
266 | } | ||
267 | #endif | ||
268 | |||
269 | #ifdef DARWIN | ||
270 | string* hd24devicenamegenerator::getdevicename(__uint32 devicenumber) | ||
271 | { | ||
272 | #if (DEVGENDEBUG==1) | ||
273 | cout << "hd24devicenamegenerator::getdevicename("<<devicenumber<<")"<< endl; | ||
274 | #endif | ||
275 | if (devicenumber>=this->getnumberofsysdevs()) | ||
276 | { | ||
277 | return new string(getfilename(devicenumber-this->getnumberofsysdevs())); | ||
278 | } | ||
279 | |||
280 | string* devname = new string("/dev/disk"); | ||
281 | string* devnum = Convert::int2str(devicenumber); | ||
282 | *devname += *devnum; | ||
283 | delete devnum; | ||
284 | return devname; | ||
285 | } | ||
286 | #endif | ||
diff --git a/src/lib/hd24devicenamegenerator.h b/src/lib/hd24devicenamegenerator.h new file mode 100755 index 0000000..40349ab --- /dev/null +++ b/src/lib/hd24devicenamegenerator.h | |||
@@ -0,0 +1,52 @@ | |||
1 | #ifndef __hd24devnamegenerator_h__ | ||
2 | #define __hd24devnamegenerator_h__ | ||
3 | |||
4 | #include <config.h> | ||
5 | #include <stdio.h> | ||
6 | #include <string> | ||
7 | #include <iostream> | ||
8 | #include <vector> | ||
9 | #include "convertlib.h" | ||
10 | |||
11 | using namespace std; | ||
12 | |||
13 | class hd24devicenamegenerator | ||
14 | { | ||
15 | private: | ||
16 | char* imagespath; // path of device images | ||
17 | vector<string>* filelist; | ||
18 | __uint32 getnumberoffiles(); | ||
19 | __uint32 filecount; // cache for getnumberoffiles | ||
20 | __uint32 getnumberofsysdevs(); | ||
21 | __uint32 hd24filecount(const char* imagedir); | ||
22 | void initvars(); | ||
23 | const char* getfilename(__uint32 filenum); | ||
24 | void clearfilelist(); | ||
25 | public: | ||
26 | ~hd24devicenamegenerator(); | ||
27 | hd24devicenamegenerator(); | ||
28 | |||
29 | __uint32 getnumberofnames(); | ||
30 | string* getdevicename(__uint32 number); | ||
31 | |||
32 | const char* imagedir(); | ||
33 | |||
34 | /* | ||
35 | Setting the image dir resets the filecount to 0 | ||
36 | which means the next call will actually count the image | ||
37 | files in the image dir (a rather heavy operation), and | ||
38 | caches the result in filecount. | ||
39 | imagedir(imagedir()) will force a filecount reset. | ||
40 | |||
41 | If the image dir is NULL, only system devices are returned. | ||
42 | */ | ||
43 | |||
44 | const char* imagedir(const char* newdir); | ||
45 | /* | ||
46 | returns NULL on alloc error, const char*=dirname otherwise | ||
47 | */ | ||
48 | |||
49 | }; | ||
50 | |||
51 | #endif | ||
52 | |||
diff --git a/src/lib/hd24fs.cpp b/src/lib/hd24fs.cpp new file mode 100755 index 0000000..5c6b3fc --- /dev/null +++ b/src/lib/hd24fs.cpp | |||
@@ -0,0 +1,3002 @@ | |||
1 | #define ALLOC_SECTORS_PER_SONG 5 | ||
2 | #define SONG_SECTORS_PER_SONG 2 | ||
3 | #define TOTAL_SECTORS_PER_SONG (ALLOC_SECTORS_PER_SONG+SONG_SECTORS_PER_SONG) | ||
4 | #ifdef DARWIN | ||
5 | #define creat64 creat | ||
6 | #endif | ||
7 | #define HD24FSDEBUG 0 /* generic hd24fs debugging */ | ||
8 | #define HD24FSDEBUG_QUICKFORMAT 0 /* debugging for calculation of # of free clusters */ | ||
9 | #define HD24FSDEBUG_WRITE 0 /* output debugging messages on disk writes */ | ||
10 | #define HD24FSDEBUG_BITSET 0 /* output debugging messages on disk writes */ | ||
11 | #define HD24FSDEBUG_COMMIT 0 /* output debugging messages on disk writes */ | ||
12 | #define HD24FSDEBUG_DEVSCAN 0 /* output debugging messages for device scan */ | ||
13 | #include "hd24fs.h" | ||
14 | #include <string> | ||
15 | #include <sys/types.h> | ||
16 | #include <sys/stat.h> | ||
17 | #include <fcntl.h> | ||
18 | #ifndef WINDOWS | ||
19 | #include <unistd.h> | ||
20 | #endif | ||
21 | #define RESULT_SUCCESS 0 | ||
22 | #define RESULT_FAIL 1 | ||
23 | #include <stdio.h> | ||
24 | #include <stdlib.h> | ||
25 | #include <iostream> | ||
26 | #include <fstream> | ||
27 | #include <math.h> | ||
28 | #include "convertlib.h" | ||
29 | #include "memutils.h" | ||
30 | |||
31 | #include <hd24devicenamegenerator.h> | ||
32 | #define _LARGE_FILES | ||
33 | #define _FILE_OFFSET_BITS 64 | ||
34 | #define FILE_OFFSET_BITS 64 | ||
35 | #define LARGE_FILES | ||
36 | #define LARGEFILE64_SOURCE | ||
37 | #define SECTORSIZE 512 | ||
38 | #ifdef DARWIN | ||
39 | #define open64 open | ||
40 | #define lseek64 lseek | ||
41 | #define pread64 pread | ||
42 | #define pwrite64 pwrite | ||
43 | #endif | ||
44 | #define FSINFO_VERSION_MAJOR 0x8 | ||
45 | #define FSINFO_VERSION_MINOR 0x9 | ||
46 | #define FSINFO_BLOCKSIZE_IN_SECTORS 0x10 | ||
47 | #define FSINFO_AUDIOBLOCKS_PER_CLUSTER 0x14 | ||
48 | #define FSINFO_STARTSECTOR_DRIVEUSAGE 0x38 | ||
49 | #define FSINFO_NUMSECTORS_DRIVEUSAGE 0x3c | ||
50 | #define FSINFO_FREE_CLUSTERS_ON_DISK 0x44 | ||
51 | #define FSINFO_FIRST_PROJECT_SECTOR 0x48 | ||
52 | #define FSINFO_SECTORS_PER_PROJECT 0x4C | ||
53 | #define FSINFO_MAXPROJECTS 0x50 | ||
54 | #define FSINFO_MAXSONGSPERPROJECT 0x54 | ||
55 | #define FSINFO_FIRST_SONG_SECTOR 0x58 | ||
56 | #define FSINFO_SECTORS_IN_SONGENTRY 0x5C | ||
57 | #define FSINFO_SECTORS_IN_SONGALLOC 0x60 | ||
58 | #define FSINFO_SECTORS_PER_SONG 0x64 | ||
59 | #define FSINFO_CURRENT_SONGS_ON_DISK 0x68 | ||
60 | #define FSINFO_ALLOCATABLE_SECTORCOUNT 0x80 | ||
61 | #define FSINFO_LAST_SECTOR 0x84 | ||
62 | #define FSINFO_DATAAREA 0x7c | ||
63 | |||
64 | #define DRIVEINFO_VOLUME 0x1b8 | ||
65 | #define DRIVEINFO_VOLUME_8 0x00 | ||
66 | #define DRIVEINFO_PROJECTCOUNT 0x0c | ||
67 | #define DRIVEINFO_LASTPROJ 0x10 | ||
68 | #define DRIVEINFO_LASTPROJECT 0x10 | ||
69 | #define DRIVEINFO_PROJECTLIST 0x20 | ||
70 | |||
71 | #include "hd24project.cpp" | ||
72 | #include "hd24song.cpp" | ||
73 | #if defined(LINUX) || defined(DARWIN) | ||
74 | const int hd24fs::MODE_RDONLY=O_RDONLY; | ||
75 | const int hd24fs::MODE_RDWR=O_RDWR; | ||
76 | #endif | ||
77 | #ifdef WINDOWS | ||
78 | #include <shellapi.h> | ||
79 | const int hd24fs::MODE_RDONLY=GENERIC_READ; | ||
80 | const int hd24fs::MODE_RDWR=GENERIC_READ|GENERIC_WRITE; | ||
81 | #define popen _popen | ||
82 | #define pclose _pclose | ||
83 | #endif | ||
84 | |||
85 | const int hd24fs::TRANSPORTSTATUS_STOP =0; | ||
86 | const int hd24fs::TRANSPORTSTATUS_REC =1; | ||
87 | const int hd24fs::TRANSPORTSTATUS_PLAY =2; | ||
88 | |||
89 | void dumpsector(const char* buffer) | ||
90 | { | ||
91 | for (int i=0;i<512;i+=16) { | ||
92 | string* dummy=Convert::int32tohex(i); | ||
93 | cout << *dummy << " "; | ||
94 | delete dummy; dummy=NULL; | ||
95 | for (int j=0;j<16;j++) { | ||
96 | string* dummy= Convert::byte2hex(buffer[i+j]); | ||
97 | cout << *dummy; | ||
98 | if (j==7) { | ||
99 | cout << "-" ; | ||
100 | } else { | ||
101 | cout << " " ; | ||
102 | } | ||
103 | delete dummy; dummy=NULL; | ||
104 | } | ||
105 | cout << " "; | ||
106 | for (int j=0;j<16;j++) { | ||
107 | cout << Convert::safebyte(buffer[i+j]); | ||
108 | } | ||
109 | cout << "" << endl; | ||
110 | } | ||
111 | } | ||
112 | |||
113 | __uint32 hd24fs::songentry2sector(__uint32 songentry) | ||
114 | { | ||
115 | // Given the possibility to store 99*99 songs, | ||
116 | // converts the song number (0..99*99-1) to | ||
117 | // the sector where the info of that song starts. | ||
118 | // TODO: answer is FSINFO_FIRST_SONG_SECTOR+(FSINFO_SECTORS_PER_SONG*songentry) | ||
119 | // returns 0 when entry number is not legal. | ||
120 | getsector_bootinfo(); | ||
121 | if (sector_boot==NULL) { | ||
122 | // info needed for the calculation is missing. | ||
123 | return 0; | ||
124 | } | ||
125 | __uint32 firstsongsec=Convert::getint32(sector_boot,FSINFO_FIRST_SONG_SECTOR); | ||
126 | __uint32 secspersong=Convert::getint32(sector_boot,FSINFO_SECTORS_PER_SONG); | ||
127 | if (songentry<(99*99)) { | ||
128 | __uint32 secnum=(firstsongsec+(songentry*secspersong)); | ||
129 | return secnum; | ||
130 | } | ||
131 | return 0; // entry number is not legal. | ||
132 | } | ||
133 | |||
134 | __uint32 hd24fs::songsondisk() | ||
135 | { | ||
136 | getsector_bootinfo(); | ||
137 | if (sector_boot==NULL) { | ||
138 | // info needed for the calculation is missing. | ||
139 | return 0; | ||
140 | } | ||
141 | return Convert::getint32(sector_boot,FSINFO_CURRENT_SONGS_ON_DISK); | ||
142 | } | ||
143 | |||
144 | void hd24fs::songsondisk(__uint32 songcount) | ||
145 | { | ||
146 | getsector_bootinfo(); | ||
147 | if (sector_boot==NULL) { | ||
148 | // info needed for the calculation is missing. | ||
149 | return; //cannot update. | ||
150 | } | ||
151 | Convert::setint32(sector_boot,FSINFO_CURRENT_SONGS_ON_DISK,songcount); | ||
152 | } | ||
153 | |||
154 | __uint32 hd24fs::songsector2entry(__uint32 songsector) | ||
155 | { | ||
156 | // given the sector where a song entry starts, | ||
157 | // returns the entry number of that song. | ||
158 | // Entry number typically ranges from 0 | ||
159 | // to (99*99)-1. | ||
160 | // A value 0xffffffff is returned when the | ||
161 | // sector number is not valid. | ||
162 | getsector_bootinfo(); | ||
163 | if (sector_boot==NULL) { | ||
164 | // info needed for the calculation is missing. | ||
165 | return 0xFFFFFFFF; // sector number is not valid. | ||
166 | } | ||
167 | __uint32 firstsongsec=Convert::getint32(sector_boot,FSINFO_FIRST_SONG_SECTOR); | ||
168 | __uint32 secspersong=Convert::getint32(sector_boot,FSINFO_SECTORS_PER_SONG); | ||
169 | __uint32 offset=songsector-firstsongsec; | ||
170 | if ((offset%secspersong) !=0) { | ||
171 | return 0xFFFFFFFF; // sector number is not valid. | ||
172 | } | ||
173 | __uint32 resultentry=(offset/secspersong); | ||
174 | if (resultentry>=(99*99)) return 0xFFFFFFFF; | ||
175 | return resultentry; | ||
176 | } | ||
177 | |||
178 | __uint32 hd24fs::cluster2sector(__uint32 clusternum) | ||
179 | { | ||
180 | getsector_bootinfo(); | ||
181 | if (sector_boot==NULL) { | ||
182 | // unknown cluster size. | ||
183 | return 0; | ||
184 | } | ||
185 | return Convert::getint32(sector_boot,FSINFO_DATAAREA) /* first audio sector */ | ||
186 | +( | ||
187 | Convert::getint32(sector_boot,FSINFO_BLOCKSIZE_IN_SECTORS) | ||
188 | * Convert::getint32(sector_boot,FSINFO_AUDIOBLOCKS_PER_CLUSTER) | ||
189 | * clusternum | ||
190 | ); | ||
191 | } | ||
192 | |||
193 | __uint32 hd24fs::sector2cluster(__uint32 sectornum) | ||
194 | { | ||
195 | getsector_bootinfo(); | ||
196 | if (sector_boot==NULL) { | ||
197 | // unknown cluster size. Return 'undefined' cluster number. | ||
198 | return CLUSTER_UNDEFINED; | ||
199 | } | ||
200 | __uint32 dataarea=Convert::getint32(sector_boot,FSINFO_DATAAREA); | ||
201 | |||
202 | if (sectornum<dataarea) { | ||
203 | // A cluster number of a sector outside the data area was requested. | ||
204 | return CLUSTER_UNDEFINED; | ||
205 | } | ||
206 | |||
207 | __uint32 unoffsetsector=sectornum-dataarea; | ||
208 | __uint32 sectorspercluster= | ||
209 | Convert::getint32(sector_boot,FSINFO_BLOCKSIZE_IN_SECTORS) | ||
210 | * Convert::getint32(sector_boot,FSINFO_AUDIOBLOCKS_PER_CLUSTER); | ||
211 | __uint32 firstsectorofcluster=unoffsetsector-(unoffsetsector%sectorspercluster); | ||
212 | __uint32 cluster=firstsectorofcluster/sectorspercluster; | ||
213 | return cluster; | ||
214 | } | ||
215 | |||
216 | __uint32 hd24fs::getnextfreesector(__uint32 cluster) | ||
217 | { | ||
218 | if (cluster==CLUSTER_UNDEFINED) { | ||
219 | __uint32 result=getnextfreesectorword(); | ||
220 | #if (HD24FSDEBUG==1) | ||
221 | cout << result << endl; | ||
222 | #endif | ||
223 | return result; | ||
224 | } | ||
225 | if (isfreecluster(cluster+1,§ors_driveusage[0])) | ||
226 | { | ||
227 | return cluster2sector(cluster+1); | ||
228 | } | ||
229 | return getnextfreesectorword(); | ||
230 | } | ||
231 | |||
232 | __uint32 hd24fs::getnextfreesectorword() | ||
233 | { | ||
234 | __uint32 cluster=getnextfreeclusterword(); | ||
235 | if (cluster==CLUSTER_UNDEFINED) { | ||
236 | return 0; | ||
237 | } | ||
238 | return cluster2sector(cluster); | ||
239 | } | ||
240 | |||
241 | __uint32 hd24fs::getnextfreeclusterword() | ||
242 | { | ||
243 | getsectors_driveusage(); | ||
244 | __uint32 driveusagecount=driveusagesectorcount(); | ||
245 | __uint32 driveusagewords=driveusagecount*(512/4); | ||
246 | |||
247 | // For performance reasons, we start searching | ||
248 | // at last result+1 (this will typically result | ||
249 | // in an immediate hit). | ||
250 | // Wrap around to cluster 0 if nothing found. | ||
251 | |||
252 | #if (HD24FSDEBUG==1) | ||
253 | cout << " start search at " << nextfreeclusterword << endl; | ||
254 | #endif | ||
255 | __uint32 i=nextfreeclusterword; | ||
256 | __uint32 initsec=i; | ||
257 | |||
258 | bool foundfree=false; | ||
259 | while (i<driveusagewords) { | ||
260 | if (Convert::getint32(§ors_driveusage[0],i*4)==0) { | ||
261 | foundfree=true; | ||
262 | break; | ||
263 | } | ||
264 | i++; | ||
265 | } | ||
266 | if (!foundfree) { | ||
267 | if (initsec==0) { | ||
268 | // we didnt find anything although | ||
269 | // we started searching at cluster 0. | ||
270 | return CLUSTER_UNDEFINED; | ||
271 | } else { | ||
272 | // we didnt find anything but started | ||
273 | // searching at a cluster>0. Wrap around. | ||
274 | nextfreeclusterword=0; | ||
275 | return getnextfreeclusterword(); | ||
276 | } | ||
277 | } | ||
278 | // we found a (set of 32) free cluster(s). | ||
279 | nextfreeclusterword=i; | ||
280 | return (i*32); | ||
281 | } | ||
282 | |||
283 | unsigned long hd24fs::getlastsectornum() | ||
284 | { | ||
285 | #if (HD24FSDEBUG==1) | ||
286 | cout <<"hd24fs::getlastsectornum()" << endl; | ||
287 | #endif | ||
288 | // cache result. | ||
289 | if (gotlastsectornum==false) { | ||
290 | foundlastsectornum=getlastsectornum(devhd24); | ||
291 | gotlastsectornum=true; | ||
292 | } | ||
293 | return foundlastsectornum; | ||
294 | } | ||
295 | |||
296 | void hd24fs::setwavefixmode(int mode) | ||
297 | { | ||
298 | wavefixmode=mode; | ||
299 | } | ||
300 | |||
301 | void hd24fs::setmaintenancemode(int mode) | ||
302 | { | ||
303 | maintenancemode=mode; | ||
304 | } | ||
305 | |||
306 | int hd24fs::getmaintenancemode() | ||
307 | { | ||
308 | return maintenancemode; | ||
309 | } | ||
310 | |||
311 | string* hd24fs::getdevicename() { | ||
312 | |||
313 | return this->devicename; | ||
314 | } | ||
315 | |||
316 | void hd24fs::setdevicename(const char* orig,string* devname) | ||
317 | { | ||
318 | if (this->devicename!=NULL) { | ||
319 | delete this->devicename; | ||
320 | this->devicename=NULL; | ||
321 | } | ||
322 | this->devicename=new string(devname->c_str()); | ||
323 | } | ||
324 | |||
325 | unsigned long hd24fs::getlastsectornum(FSHANDLE handle) | ||
326 | { | ||
327 | #if (HD24FSDEBUG==1) | ||
328 | cout <<"hd24fs::getlastsectornum(FSHANDLE handle)" << endl; | ||
329 | #endif | ||
330 | #if defined(LINUX) || defined(DARWIN) | ||
331 | __uint64 curroff=lseek64(handle,0,SEEK_CUR); | ||
332 | __uint64 sectors=(lseek64(handle,0,SEEK_END)+1)>>9; | ||
333 | lseek64(handle,curroff,SEEK_SET); | ||
334 | return sectors-1; | ||
335 | #endif | ||
336 | /* unfortunately, apart from other functions being needed | ||
337 | * to read 64 bit files, the elegant solution above won't | ||
338 | * work on Windows, because it is not possible to | ||
339 | * request the file size of a device. | ||
340 | */ | ||
341 | |||
342 | #ifdef WINDOWS | ||
343 | unsigned char buffer[2048]; | ||
344 | LARGE_INTEGER lizero; | ||
345 | lizero.QuadPart=0; | ||
346 | LARGE_INTEGER saveoff; | ||
347 | LARGE_INTEGER filelen; | ||
348 | filelen.QuadPart=0; | ||
349 | SetFilePointerEx(handle,lizero,&saveoff,FILE_CURRENT); // save offset | ||
350 | /* If things would work properly, the following would | ||
351 | * not only work for regular files, but also for devices. | ||
352 | * Perhaps the next version of Windows has proper hardware | ||
353 | * abstraction and this will magically start working. | ||
354 | */ | ||
355 | if (0!=SetFilePointerEx(handle,lizero,&filelen,FILE_END)) { | ||
356 | SetFilePointerEx(handle,saveoff,NULL,FILE_BEGIN); // restore offset | ||
357 | return ((filelen.QuadPart)/512); | ||
358 | } | ||
359 | SetFilePointerEx(handle,saveoff,NULL,FILE_BEGIN); // restore offset | ||
360 | #if (HD24FSDEBUG==1) | ||
361 | cout << "fileptr method failed" << endl; | ||
362 | #endif | ||
363 | /* The proper way to do things has failed (probably because | ||
364 | * we are dealing with a device file instead of with a | ||
365 | * regular one. | ||
366 | */ | ||
367 | |||
368 | /* TODO: Before trying a raw sectornum scan, | ||
369 | we can still check if we're dealing with a valid | ||
370 | superblock, not using a headerfile and checking if | ||
371 | the last sector as indicated by the superblock points | ||
372 | to a copy of that superblock. This won't work on a raw | ||
373 | drive, of course, but will provide a reasonably safe | ||
374 | workaround for valid HD24 drives. */ | ||
375 | |||
376 | /* The workaround has also failed, so we need to perform | ||
377 | raw drive size detection. Windows does not have a reliable | ||
378 | way to get the real LBA sector count, so we need to perform | ||
379 | the following semi-smart trick (if you have a better idea that | ||
380 | works on all windows versions and all drive types, | ||
381 | I'd be thrilled to know!) | ||
382 | |||
383 | - First, iterate reading sector numbers until it fails. | ||
384 | To keep speed acceptable, multiply sector number by 2 | ||
385 | each time. | ||
386 | - After failed read, do a binary search between the | ||
387 | failed read sector number and the sector number of | ||
388 | the last successful read. | ||
389 | - As the drive MUST be aware of its own size, this will | ||
390 | give the real sector count of the drive. | ||
391 | */ | ||
392 | lizero.QuadPart=0; | ||
393 | saveoff.QuadPart=0; | ||
394 | |||
395 | LARGE_INTEGER maxbytes; | ||
396 | maxbytes.QuadPart=0; | ||
397 | SetFilePointerEx(handle,lizero,&saveoff,FILE_CURRENT); // save offset | ||
398 | |||
399 | long bytesread=1; | ||
400 | unsigned long trysector=1; | ||
401 | unsigned long oldtrysector=1; | ||
402 | int drivetoosmall=1; | ||
403 | bytesread=readsectors(handle,trysector,buffer,1); // raw/audio read (no fstfix needed) | ||
404 | unsigned long lastok=0; | ||
405 | unsigned long firstfail=0; | ||
406 | //int dummy; | ||
407 | /* This loop doubles the sector number. Actually stays at 2^n-1, | ||
408 | * this will likely perform better than 2^n because chances are | ||
409 | * greater that it stays below disk boundaries, preventing slow | ||
410 | * timeouts. | ||
411 | */ | ||
412 | while (bytesread>0) | ||
413 | { | ||
414 | #if (HD24FSDEBUG==1) | ||
415 | cout << "trysector=" << trysector << endl; | ||
416 | #endif | ||
417 | // cin >> dummy; | ||
418 | drivetoosmall=0; | ||
419 | oldtrysector=trysector; | ||
420 | trysector=trysector*2+1; // count will be 1,3,7,15,31,... =(2^n)-1 | ||
421 | if (oldtrysector==trysector) | ||
422 | { | ||
423 | // x*2+1 yields x - this means all | ||
424 | // bits are turned on and we overflow. | ||
425 | // So we're at 4 tera limit. | ||
426 | // 4 terabyte and still nothing found? hmmmm | ||
427 | SetFilePointerEx(handle,saveoff,NULL,FILE_BEGIN); | ||
428 | return 0; | ||
429 | } | ||
430 | bytesread=0; | ||
431 | bytesread=readsectors(handle,trysector,buffer,1); // raw/audio read (no fstfix needed) | ||
432 | #if (HD24FSDEBUG==1) | ||
433 | cout << " bytesread=" <<bytesread << endl; | ||
434 | #endif | ||
435 | if (bytesread>0) { | ||
436 | lastok=trysector; | ||
437 | } else { | ||
438 | firstfail=trysector; | ||
439 | } | ||
440 | } | ||
441 | /* We have the sector number of the last successful read and | ||
442 | * of the failed read. Time to do a binary search. */ | ||
443 | unsigned long lowerbound=lastok; | ||
444 | #if (HD24FSDEBUG==1) | ||
445 | cout << "lastok=" << lastok << endl; | ||
446 | cout << "firstfaiL=" << firstfail << endl; | ||
447 | |||
448 | #endif | ||
449 | if (lastok==0) | ||
450 | { | ||
451 | if (firstfail==0) | ||
452 | { | ||
453 | return 0; | ||
454 | } | ||
455 | } | ||
456 | unsigned long upperbound=lastok*2; | ||
457 | unsigned long midpos=0; | ||
458 | while (lowerbound<=upperbound) | ||
459 | { | ||
460 | //midpos=lowerbound+floor((upperbound-lowerbound)/2); | ||
461 | midpos=lowerbound+(__uint32)floor((upperbound-lowerbound)/8); | ||
462 | // prefer asymmetrical search due to time out when | ||
463 | // searching past upperbound | ||
464 | // cout << "try=" << midpos << endl; | ||
465 | bytesread=readsectors(handle,midpos,buffer,1); // raw/audio read (no fstfix needed) | ||
466 | if (bytesread>0) { | ||
467 | lowerbound=midpos+1; | ||
468 | } else { | ||
469 | // could not read midpos, | ||
470 | // so upperbound is before that. | ||
471 | upperbound=midpos-1; | ||
472 | } | ||
473 | } | ||
474 | if (midpos==lowerbound) | ||
475 | { | ||
476 | midpos--; | ||
477 | } | ||
478 | /* midpos is now last sector number. counting starts at sector 0 | ||
479 | * so total number of sectors is one more. */ | ||
480 | midpos++; | ||
481 | SetFilePointerEx(handle,saveoff,&saveoff,FILE_BEGIN); //restore | ||
482 | |||
483 | __uint64 sectors=midpos; | ||
484 | // cout << "found " <<sectors << "sectors " <<endl; | ||
485 | return sectors; | ||
486 | #endif | ||
487 | } | ||
488 | |||
489 | /* The hd24raw class provides sector level access to hd24 disks | ||
490 | * which is functionality that is shielded off in hd24fs. | ||
491 | */ | ||
492 | |||
493 | __uint32 hd24raw::songsondisk() | ||
494 | { | ||
495 | return fsys->songsondisk(); | ||
496 | } | ||
497 | |||
498 | __uint32 hd24raw::getlastsectornum() | ||
499 | { | ||
500 | return fsys->getlastsectornum(); | ||
501 | } | ||
502 | |||
503 | __uint32 hd24raw::getprojectsectornum(__uint32 x) | ||
504 | { | ||
505 | return fsys->getprojectsectornum(x); | ||
506 | } | ||
507 | |||
508 | __uint32 hd24raw::quickformat(char* message) | ||
509 | { | ||
510 | return fsys->quickformat(message); | ||
511 | } | ||
512 | |||
513 | unsigned long hd24raw::getnextfreesector(__uint32 cluster) | ||
514 | { | ||
515 | return fsys->getnextfreesector(cluster); | ||
516 | } | ||
517 | |||
518 | hd24raw::hd24raw(hd24fs* p_fsys) | ||
519 | { | ||
520 | fsys=p_fsys; | ||
521 | } | ||
522 | |||
523 | long hd24raw::readsectors(unsigned long secnum, unsigned char* buffer,int sectors) | ||
524 | { | ||
525 | return fsys->readsectors(fsys->devhd24, secnum, buffer,sectors); | ||
526 | } | ||
527 | |||
528 | long hd24raw::writesectors(unsigned long secnum, unsigned char* buffer,int sectors) | ||
529 | { | ||
530 | return fsys->writesectors(fsys->devhd24, secnum, buffer,sectors); | ||
531 | }; | ||
532 | |||
533 | bool hd24fs::isinvalidhandle(FSHANDLE handle) | ||
534 | { | ||
535 | #ifdef WINDOWS | ||
536 | if (handle==FSHANDLE_INVALID) { | ||
537 | return true; | ||
538 | } | ||
539 | #endif | ||
540 | #if defined(LINUX) || defined(DARWIN) | ||
541 | if (handle==0) { | ||
542 | return true; | ||
543 | } | ||
544 | if (handle==FSHANDLE_INVALID) { | ||
545 | return true; | ||
546 | } | ||
547 | #endif | ||
548 | return false; | ||
549 | } | ||
550 | |||
551 | bool hd24fs::isexistingdevice(string* devname) | ||
552 | { | ||
553 | #if defined(LINUX) || defined(DARWIN) | ||
554 | #if (HD24FSDEBUG==1) | ||
555 | cout << "try open device " << devname->c_str() << endl; | ||
556 | #endif | ||
557 | FSHANDLE handle=open64(devname->c_str(),MODE_RDONLY); //read binary | ||
558 | #endif | ||
559 | #ifdef WINDOWS | ||
560 | FSHANDLE handle=CreateFile(devname->c_str(),MODE_RDONLY, | ||
561 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
562 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
563 | #endif | ||
564 | if (!isinvalidhandle(handle)) return true; | ||
565 | return false; | ||
566 | } | ||
567 | |||
568 | FSHANDLE hd24fs::findhd24device(int mode,string* devname,bool force,bool tryharder) | ||
569 | { | ||
570 | #if (HD24FSDEBUG_DEVSCAN==1) | ||
571 | cout << "FSHANDLE hd24fs::findhd24device(" << mode << ", " << *devname << ", force=" << force << ",tryharder=" << tryharder <<")" << endl; | ||
572 | #endif | ||
573 | unsigned char findhdbuf[1024]; | ||
574 | unsigned char compare1buf[1024]; | ||
575 | unsigned char compare2buf[1024]; | ||
576 | #if defined(LINUX) | ||
577 | FSHANDLE handle=open64(devname->c_str(),mode,0); //read binary | ||
578 | #endif | ||
579 | #if defined(DARWIN) | ||
580 | FSHANDLE handle=open64(devname->c_str(),mode); //read binary | ||
581 | #endif | ||
582 | #ifdef WINDOWS | ||
583 | #if (HD24FSDEBUG_DEVSCAN==1) | ||
584 | cout << "Mode=" << mode << endl; | ||
585 | #endif | ||
586 | FSHANDLE handle=CreateFile(devname->c_str(),mode, | ||
587 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
588 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
589 | #endif | ||
590 | |||
591 | if (isinvalidhandle(handle)) { | ||
592 | if (mode==MODE_RDWR) | ||
593 | { | ||
594 | // attempt fallback to read-only mode | ||
595 | // (for CDROM/DVD devices etc) | ||
596 | mode=MODE_RDONLY; | ||
597 | #if defined(LINUX) || defined(DARWIN) | ||
598 | handle=open64(devname->c_str(),mode); //read binary | ||
599 | #endif | ||
600 | #ifdef WINDOWS | ||
601 | #if (HD24FSDEBUG==1) | ||
602 | // cout << "Mode=" << mode << endl; | ||
603 | #endif | ||
604 | handle=CreateFile(devname->c_str(),mode, | ||
605 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
606 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
607 | #endif | ||
608 | |||
609 | } | ||
610 | |||
611 | |||
612 | } | ||
613 | |||
614 | if (isinvalidhandle(handle)) { | ||
615 | return handle; | ||
616 | } | ||
617 | |||
618 | // can open device. | ||
619 | __uint32 sectornum=0; | ||
620 | if (tryharder) { | ||
621 | sectornum=getlastsectornum(handle); | ||
622 | } | ||
623 | |||
624 | readsector_noheader(handle,sectornum,findhdbuf); // fstfix follows | ||
625 | fstfix(findhdbuf,512); | ||
626 | string* fstype=Convert::readstring(findhdbuf,0,8); | ||
627 | bool isadat=false; | ||
628 | |||
629 | if (*fstype=="ADAT FST") { | ||
630 | /* Okay, but if we are 'trying harder' we can run into | ||
631 | a false positive for old HD24 drives that are now in | ||
632 | use as OS drive. So we'll demand that the second and | ||
633 | secondlast sector are equal. | ||
634 | */ | ||
635 | if (tryharder) | ||
636 | { | ||
637 | readsector_noheader(handle,sectornum-1,compare1buf); | ||
638 | readsector_noheader(handle,1,compare2buf); | ||
639 | if (memcmp(compare1buf,compare2buf,512)==0) | ||
640 | { | ||
641 | isadat=true; | ||
642 | } | ||
643 | else | ||
644 | { | ||
645 | /* Drive may have been an ADAT drive, | ||
646 | but no longer is. If it is in fact an | ||
647 | ADAT drive but corrupted, it is still | ||
648 | possible to force detection using force | ||
649 | mode. Give it another chance; do not | ||
650 | enable write prevention for now. | ||
651 | */ | ||
652 | isadat=false; | ||
653 | } | ||
654 | } | ||
655 | else | ||
656 | { | ||
657 | isadat=true; | ||
658 | } | ||
659 | } | ||
660 | delete fstype; | ||
661 | |||
662 | if (isadat) return handle; | ||
663 | |||
664 | if (force) | ||
665 | { | ||
666 | forcemode=true; | ||
667 | m_isOpen=true; | ||
668 | this->writeprotected=true; // TODO: unless expert mode is enabled too. May also be overridden to allow formatting. | ||
669 | return handle; | ||
670 | } | ||
671 | hd24closedevice(handle); | ||
672 | return FSHANDLE_INVALID; | ||
673 | } | ||
674 | |||
675 | unsigned long hd24fs::hd24devicecount() | ||
676 | { | ||
677 | /* Attempt to auto-detect a hd24 disk on all IDE and SCSI devices. | ||
678 | (this should include USB and firewire) */ | ||
679 | FSHANDLE handle; | ||
680 | int devcount=0; | ||
681 | #if (HD24FSDEBUG==1) | ||
682 | cout << "====PERFORMING DEVICE COUNT====" << endl; | ||
683 | #endif | ||
684 | hd24devicenamegenerator* dng=new hd24devicenamegenerator(); | ||
685 | dng->imagedir(this->imagedir); | ||
686 | |||
687 | __uint32 totnames=dng->getnumberofnames(); | ||
688 | // cout << totnames << " devices" << endl; | ||
689 | for (__uint32 j=0;j<2;j++) | ||
690 | { | ||
691 | // 2 loops: one to try, one to try harder | ||
692 | // first loop searches strictly valid devices | ||
693 | // second loop searches for possibly corrupted devices | ||
694 | bool tryharder=false; | ||
695 | if (j==1) { | ||
696 | tryharder=true; | ||
697 | } | ||
698 | for (__uint32 i=0;i<totnames;i++) | ||
699 | { | ||
700 | string* devname=dng->getdevicename(i); | ||
701 | handle=findhd24device(MODE_RDONLY,devname,false,tryharder); | ||
702 | #if (HD24FSDEBUG_DEVSCAN==1) | ||
703 | cout << "try device no " <<i << "with name" << *devname << "..."; | ||
704 | #endif | ||
705 | delete (devname); | ||
706 | if (!(isinvalidhandle(handle))) | ||
707 | { | ||
708 | devcount++; | ||
709 | // cout << "found" << endl; | ||
710 | hd24closedevice(handle); | ||
711 | } else { | ||
712 | // cout << "nope." << endl; | ||
713 | } | ||
714 | } | ||
715 | |||
716 | if (devcount>0) { | ||
717 | break; | ||
718 | } | ||
719 | } | ||
720 | #if (HD24FSDEBUG==1) | ||
721 | cout << "====END OF DEVICE COUNT, " << devcount << " DEVICES FOUND ====" << endl; | ||
722 | #endif | ||
723 | delete (dng); | ||
724 | return devcount; | ||
725 | } | ||
726 | |||
727 | void hd24fs::setimagedir(const char* newdir) | ||
728 | { | ||
729 | #if (HD24FSDEBUG==1) | ||
730 | if (newdir==NULL) | ||
731 | { | ||
732 | cout << "hd24fs::setimagedir(NULL)"<< endl; | ||
733 | } | ||
734 | else | ||
735 | { | ||
736 | cout << "hd24fs::setimagedir("<<newdir<<")"<< endl; | ||
737 | } | ||
738 | #endif | ||
739 | |||
740 | if (this->imagedir!=NULL) | ||
741 | { | ||
742 | free ((void*)imagedir); | ||
743 | this->imagedir=NULL; | ||
744 | } | ||
745 | |||
746 | if (newdir!=NULL) | ||
747 | { | ||
748 | this->imagedir=(char*)malloc(strlen(newdir)+1); | ||
749 | if (this->imagedir!=NULL) | ||
750 | { | ||
751 | strncpy((char*)imagedir,newdir,strlen(newdir)+1); | ||
752 | } | ||
753 | } | ||
754 | |||
755 | return; //return (const char*)imagedir; | ||
756 | } | ||
757 | |||
758 | FSHANDLE hd24fs::findhd24device(int mode,int base0devnum) | ||
759 | { | ||
760 | #if (HD24FSDEBUG_DEVSCAN==1) | ||
761 | cout << "hd24fs::findhd24device(" << mode << "," << base0devnum << ")" << endl; | ||
762 | #endif | ||
763 | // TODO: Reduce code duplication in this subroutine | ||
764 | // and hd24devicecount | ||
765 | /* Attempt to auto-detect a hd24 disk on all known | ||
766 | IDE and SCSI devices. (this should include USB | ||
767 | and firewire) */ | ||
768 | int currdev=0; | ||
769 | FSHANDLE handle; | ||
770 | hd24devicenamegenerator* dng=new hd24devicenamegenerator(); | ||
771 | dng->imagedir(this->imagedir); | ||
772 | |||
773 | __uint32 totnames=dng->getnumberofnames(); | ||
774 | #if (HD24FSDEBUG==1) | ||
775 | cout << totnames << " devices" << endl; | ||
776 | #endif | ||
777 | for (__uint32 j=0;j<2;j++) | ||
778 | { | ||
779 | // 2 loops: one to try, one to try harder | ||
780 | // first loop searches strictly valid devices | ||
781 | // second loop searches for possibly corrupted devices | ||
782 | |||
783 | bool tryharder=false; | ||
784 | if (j==1) { | ||
785 | tryharder=true; | ||
786 | } | ||
787 | |||
788 | for (__uint32 i=0;i<totnames;i++) | ||
789 | { | ||
790 | string* devname=dng->getdevicename(i); | ||
791 | handle=findhd24device(mode,devname,false,tryharder); | ||
792 | |||
793 | if (!(isinvalidhandle(handle))) { | ||
794 | if (currdev==base0devnum) { | ||
795 | // String "3" indicates origin, i.e. | ||
796 | // who is setting the device name. | ||
797 | // Useful for debugging purposes. | ||
798 | setdevicename("3",devname); | ||
799 | deviceid=i; | ||
800 | p_mode=mode; | ||
801 | delete (devname); | ||
802 | delete (dng); | ||
803 | return handle; | ||
804 | } | ||
805 | hd24closedevice(handle); | ||
806 | currdev++; | ||
807 | } | ||
808 | delete (devname); | ||
809 | } | ||
810 | } | ||
811 | delete (dng); | ||
812 | return FSHANDLE_INVALID; | ||
813 | } | ||
814 | |||
815 | void hd24fs::hd24closedevice(FSHANDLE handle) { | ||
816 | #if defined(LINUX) || defined(DARWIN) | ||
817 | close(handle); | ||
818 | #endif | ||
819 | #ifdef WINDOWS | ||
820 | CloseHandle(handle); | ||
821 | #endif | ||
822 | } | ||
823 | |||
824 | FSHANDLE hd24fs::findhd24device(int mode) | ||
825 | { | ||
826 | /* Attempt to auto-detect a hd24 disk on all IDE and SCSI devices. | ||
827 | (this should include USB and firewire) */ | ||
828 | return findhd24device(mode,0); | ||
829 | } | ||
830 | |||
831 | FSHANDLE hd24fs::findhd24device() | ||
832 | { | ||
833 | return findhd24device(MODE_RDONLY); | ||
834 | } | ||
835 | |||
836 | int hd24fs::gettransportstatus() | ||
837 | { | ||
838 | return this->transportstatus; | ||
839 | } | ||
840 | |||
841 | void hd24fs::settransportstatus(int newstatus) | ||
842 | { | ||
843 | this->transportstatus=newstatus; | ||
844 | } | ||
845 | |||
846 | int hd24fs::getdeviceid() | ||
847 | { | ||
848 | return deviceid; | ||
849 | } | ||
850 | |||
851 | void hd24fs::initvars() | ||
852 | { | ||
853 | this->deviceid=-1; | ||
854 | this->writeprotected=false; // by default allow writes. | ||
855 | // can be disabled if corrupt | ||
856 | // state is detected. | ||
857 | this->transportstatus=TRANSPORTSTATUS_STOP; | ||
858 | this->imagedir=NULL; | ||
859 | this->nextfreeclusterword=0; | ||
860 | this->gotlastsectornum=false; | ||
861 | this->foundlastsectornum=0; | ||
862 | this->forcemode=false; | ||
863 | this->headersectors=0; | ||
864 | sector_boot=NULL; | ||
865 | sector_diskinfo=NULL; | ||
866 | sectors_driveusage=NULL; | ||
867 | sectors_orphan=NULL; | ||
868 | sectors_songusage=NULL; | ||
869 | projlist=NULL; | ||
870 | this->m_isOpen=false; | ||
871 | this->allinput=false; | ||
872 | this->autoinput=false; | ||
873 | this->wavefixmode=false; | ||
874 | this->formatting=false; | ||
875 | this->maintenancemode=false; | ||
876 | this->headermode=false; | ||
877 | this->devicename=NULL; | ||
878 | this->highestFSsectorwritten=0; | ||
879 | // 0x10c76 is last sector of song/project area (without undo buffer) | ||
880 | return; | ||
881 | } | ||
882 | |||
883 | hd24fs::hd24fs(const char* imagedir,int mode) | ||
884 | { | ||
885 | initvars(); | ||
886 | setimagedir(imagedir); | ||
887 | devicename=new string(""); | ||
888 | devhd24=findhd24device(mode); | ||
889 | if (!(isinvalidhandle(devhd24))) { | ||
890 | m_isOpen=true; | ||
891 | p_mode=mode; | ||
892 | } | ||
893 | return; | ||
894 | } | ||
895 | |||
896 | hd24fs::hd24fs(const char* imagedir,int mode,int base0devnum) | ||
897 | { | ||
898 | #if (HD24FSDEBUG==1) | ||
899 | cout << "hd24fs::hd24fs(" << mode << "," << base0devnum << ")" << endl; | ||
900 | #endif | ||
901 | initvars(); | ||
902 | setimagedir(imagedir); | ||
903 | devicename=new string(""); | ||
904 | devhd24=findhd24device(mode,base0devnum); | ||
905 | if (!(isinvalidhandle(devhd24))) { | ||
906 | m_isOpen=true; | ||
907 | p_mode=mode; | ||
908 | } | ||
909 | return; | ||
910 | } | ||
911 | |||
912 | hd24fs::hd24fs(const char* imagedir,int mode,string* devname,bool force) | ||
913 | { | ||
914 | initvars(); | ||
915 | setimagedir(imagedir); | ||
916 | devicename=new string(devname->c_str()); | ||
917 | bool tryharder=false; | ||
918 | devhd24=findhd24device(mode,devname,force,tryharder); | ||
919 | if (!(isinvalidhandle(devhd24))) { | ||
920 | m_isOpen=true; | ||
921 | p_mode=mode; | ||
922 | } | ||
923 | return; | ||
924 | } | ||
925 | |||
926 | hd24fs::hd24fs(const char* imagedir) | ||
927 | { | ||
928 | initvars(); | ||
929 | setimagedir(imagedir); | ||
930 | devicename=new string(""); | ||
931 | devhd24=findhd24device(MODE_RDONLY); | ||
932 | if (!(isinvalidhandle(devhd24))) { | ||
933 | m_isOpen=true; | ||
934 | p_mode=MODE_RDONLY; | ||
935 | } | ||
936 | return; | ||
937 | } | ||
938 | |||
939 | hd24fs::~hd24fs() | ||
940 | { | ||
941 | #if (HD24FSDEBUG==1) | ||
942 | cout << "Deleting devicename" << endl; | ||
943 | #endif | ||
944 | if (devicename!=NULL) { | ||
945 | delete devicename; | ||
946 | devicename=NULL; | ||
947 | } | ||
948 | #if (HD24FSDEBUG==1) | ||
949 | cout << "Close FS handle" << endl; | ||
950 | #endif | ||
951 | if (isOpen()) | ||
952 | { | ||
953 | hd24close(); | ||
954 | } | ||
955 | #if (HD24FSDEBUG==1) | ||
956 | cout << "Free superblock mem" << endl; | ||
957 | #endif | ||
958 | if (sector_boot!=NULL) | ||
959 | { | ||
960 | memutils::myfree("sectors_boot",sector_boot); | ||
961 | sector_boot=NULL; | ||
962 | } | ||
963 | #if (HD24FSDEBUG==1) | ||
964 | cout << "Free diskinfo mem" << endl; | ||
965 | #endif | ||
966 | if (sector_diskinfo!=NULL) | ||
967 | { | ||
968 | memutils::myfree("sectors_diskinfo",sector_diskinfo); | ||
969 | sector_diskinfo=NULL; | ||
970 | } | ||
971 | #if (HD24FSDEBUG==1) | ||
972 | cout << "Free drive usage mem" << endl; | ||
973 | #endif | ||
974 | if (sectors_driveusage!=NULL) | ||
975 | { | ||
976 | memutils::myfree("sectors_driveusage",sectors_driveusage); | ||
977 | sectors_driveusage=NULL; | ||
978 | } | ||
979 | #if (HD24FSDEBUG==1) | ||
980 | cout << "Free orphan sectors mem" << endl; | ||
981 | #endif | ||
982 | if (sectors_orphan!=NULL) | ||
983 | { | ||
984 | memutils::myfree("sectors_orphan",sectors_orphan); | ||
985 | sectors_orphan=NULL; | ||
986 | } | ||
987 | #if (HD24FSDEBUG==1) | ||
988 | cout << "Free song usage sectors mem" << endl; | ||
989 | #endif | ||
990 | if (sectors_songusage!=NULL) | ||
991 | { | ||
992 | memutils::myfree("sectors_songusage",sectors_songusage); | ||
993 | sectors_songusage=NULL; | ||
994 | }; | ||
995 | // commit? | ||
996 | } | ||
997 | |||
998 | bool hd24fs::isOpen() | ||
999 | { | ||
1000 | if (this->m_isOpen) | ||
1001 | { | ||
1002 | return true; | ||
1003 | } | ||
1004 | return false; | ||
1005 | } | ||
1006 | |||
1007 | void hd24fs::hd24close() | ||
1008 | { | ||
1009 | // TODO: At the point that we start supporting | ||
1010 | // write access, we will need to flush and close | ||
1011 | // the device here. | ||
1012 | |||
1013 | hd24closedevice(this->devhd24); | ||
1014 | } | ||
1015 | |||
1016 | void hd24fs::fstfix(unsigned char * bootblock,int fixsize) | ||
1017 | { | ||
1018 | if (bootblock==NULL) return; | ||
1019 | if (fixsize<=0) return; | ||
1020 | #if (HD24FSDEBUG==1) | ||
1021 | cout << "fstfix("<<bootblock<<","<<fixsize/512 <<"*512)"<< endl; | ||
1022 | #endif | ||
1023 | for (int i=0;i<fixsize;i+=4) | ||
1024 | { | ||
1025 | unsigned char a=bootblock[i]; | ||
1026 | unsigned char b=bootblock[i+1]; | ||
1027 | unsigned char c=bootblock[i+2]; | ||
1028 | unsigned char d=bootblock[i+3]; | ||
1029 | bootblock[i]=d; | ||
1030 | bootblock[i+1]=c; | ||
1031 | bootblock[i+2]=b; | ||
1032 | bootblock[i+3]=a; | ||
1033 | } | ||
1034 | } | ||
1035 | |||
1036 | void hd24fs::hd24seek(FSHANDLE devhd24,__uint64 seekpos) { | ||
1037 | #if defined(LINUX) || defined(DARWIN) | ||
1038 | lseek64(devhd24,seekpos,SEEK_SET); | ||
1039 | #endif | ||
1040 | #ifdef WINDOWS | ||
1041 | // cout << "setfp to " <<seekpos << endl; | ||
1042 | LARGE_INTEGER li; | ||
1043 | li.HighPart=seekpos>>32; | ||
1044 | li.LowPart=seekpos%((__uint64)1<<32); | ||
1045 | //LowPart=seekpos% | ||
1046 | // SetFilePointer(devhd24,seekpos,NULL,FILE_BEGIN); | ||
1047 | SetFilePointerEx(devhd24,li,NULL,FILE_BEGIN); | ||
1048 | // TODO: SetFilePointer vs SetFilePointerEx | ||
1049 | // DWORD SetFilePointer( | ||
1050 | // HANDLE hFile, | ||
1051 | // LONG lDistanceToMove, | ||
1052 | // PLONG lpDistanceToMoveHigh, | ||
1053 | // DWORD dwMoveMethod | ||
1054 | // ); | ||
1055 | // | ||
1056 | // vs. | ||
1057 | // BOOL SetFilePointerEx( | ||
1058 | // HANDLE hFile, | ||
1059 | // LARGE_INTEGER liDistanceToMove, | ||
1060 | // PLARGE_INTEGER lpNewFilePointer, | ||
1061 | // DWORD dwMoveMethod | ||
1062 | // ); | ||
1063 | // | ||
1064 | #endif | ||
1065 | return; | ||
1066 | } | ||
1067 | |||
1068 | long hd24fs::writesectors(FSHANDLE devhd24,unsigned long sectornum,unsigned char * buffer,int sectors) | ||
1069 | { | ||
1070 | ////// | ||
1071 | // this bit keeps track of the highest FS sector written | ||
1072 | // to keep commit times acceptable: commit function will then | ||
1073 | // only backup up to the highest sector used. | ||
1074 | // (this is still suboptimal performance-wise but requires | ||
1075 | // a minimum of memory and administration during writes). | ||
1076 | __uint32 lastsec=sectornum+(sectors-1); | ||
1077 | if (lastsec<=0x10c76) | ||
1078 | { | ||
1079 | // 0x10c76 is last sector of song/project area (without | ||
1080 | // undo buffer). TODO: calculate based on superblock. info. | ||
1081 | if (lastsec>highestFSsectorwritten) | ||
1082 | { | ||
1083 | highestFSsectorwritten=lastsec; | ||
1084 | } | ||
1085 | } | ||
1086 | ////// | ||
1087 | |||
1088 | #if (HD24FSDEBUG_WRITE==1) | ||
1089 | cout << " writesectors sectornum " << sectornum << ", sectorcount=" << sectors << endl; | ||
1090 | #endif | ||
1091 | if (this!=NULL) | ||
1092 | { | ||
1093 | if (this->writeprotected) | ||
1094 | { | ||
1095 | #if (HD24FSDEBUG_WRITE==1) | ||
1096 | cout << "Write protected- not writing. " << endl; | ||
1097 | #endif | ||
1098 | return 0; | ||
1099 | } | ||
1100 | } | ||
1101 | FSHANDLE currdevice=devhd24; | ||
1102 | |||
1103 | #if (HD24FSDEBUG_WRITE==1) | ||
1104 | cout << "WRITESECTORS sec=" << sectornum << " buf=" << buffer << "#=" << sectors << endl; | ||
1105 | #endif | ||
1106 | int WRITESIZE=SECTORSIZE*sectors; // allows searching across sector boundaries | ||
1107 | |||
1108 | // cout << "headersectors=" << this->headersectors << "this=" <<this << endl; | ||
1109 | if (this!=NULL) | ||
1110 | { | ||
1111 | if ((this->headersectors)!=0) | ||
1112 | { | ||
1113 | // cout << "headermode enabled." << endl; | ||
1114 | // Header mode is active. Only allow writing over header area. | ||
1115 | if (sectornum<this->headersectors) | ||
1116 | { | ||
1117 | // cout << "Headermode enabled for sector " << sectornum << endl; | ||
1118 | currdevice=hd24header; | ||
1119 | |||
1120 | } else { | ||
1121 | // headermode is active yet caller is trying to write over drive | ||
1122 | // data area. We cannot allow this (for safety reasons). | ||
1123 | return 0; | ||
1124 | |||
1125 | // cout << "Headermode disabled for sector " << sectornum << endl; | ||
1126 | } | ||
1127 | } else { | ||
1128 | // cout << "Headermode disabled. " << sectornum << endl; | ||
1129 | } | ||
1130 | } | ||
1131 | |||
1132 | hd24seek(currdevice,(__uint64)sectornum*512); | ||
1133 | |||
1134 | #if defined(LINUX) || defined(DARWIN) || defined(__APPLE__) | ||
1135 | long bytes=pwrite64(currdevice,buffer,WRITESIZE,(__uint64)sectornum*512); //1,devhd24); | ||
1136 | // cout << "BYTES=" << bytes << endl; | ||
1137 | #endif | ||
1138 | #ifdef WINDOWS | ||
1139 | DWORD dummy; | ||
1140 | long bytes=0; | ||
1141 | if (WriteFile(currdevice,buffer,WRITESIZE,&dummy,NULL)) { | ||
1142 | bytes=WRITESIZE; | ||
1143 | }; | ||
1144 | #endif | ||
1145 | return bytes; | ||
1146 | } | ||
1147 | |||
1148 | long hd24fs::readsectors(FSHANDLE devhd24,unsigned long sectornum,unsigned char * buffer,int sectors) | ||
1149 | { | ||
1150 | FSHANDLE currdevice=devhd24; | ||
1151 | // The following prints the sector num in hex: | ||
1152 | #if (HD24FSDEBUG==1) | ||
1153 | /* string* x=this->p_convert->int32tohex(sectornum); | ||
1154 | cout << *x << endl; | ||
1155 | delete x; | ||
1156 | */ | ||
1157 | #endif | ||
1158 | |||
1159 | // cout << "headersectors=" << this->headersectors << "this=" <<this << endl; | ||
1160 | if ((this->headersectors)!=0) | ||
1161 | { | ||
1162 | // cout << "headermode enabled." << endl; | ||
1163 | if (sectornum<this->headersectors) | ||
1164 | { | ||
1165 | // cout << "Headermode enabled for sector " << sectornum << endl; | ||
1166 | currdevice=hd24header; | ||
1167 | } else { | ||
1168 | // cout << "Headermode disabled for sector " << sectornum << endl; | ||
1169 | } | ||
1170 | } else { | ||
1171 | // cout << "Headermode disabled. " << sectornum << endl; | ||
1172 | } | ||
1173 | hd24seek(currdevice,(__uint64)sectornum*SECTORSIZE); | ||
1174 | int READSIZE=SECTORSIZE*(sectors); | ||
1175 | #if defined(LINUX) || defined(DARWIN) | ||
1176 | long bytes_read=pread64(currdevice,buffer,READSIZE,(__uint64)sectornum*512); //1,currdevice); | ||
1177 | #endif | ||
1178 | #ifdef WINDOWS | ||
1179 | // cout << "Readsectors: num="<<sectornum<<"buffer available, numsecs=" <<sectors << endl; | ||
1180 | DWORD bytes_read; | ||
1181 | //long bytes=0; | ||
1182 | if( ReadFile(currdevice,buffer,READSIZE,&bytes_read,NULL)) { | ||
1183 | // cout << "read succes"<< bytes_read << "bytes" << endl; | ||
1184 | } else { | ||
1185 | // cout << "read fail" << endl; | ||
1186 | bytes_read = 0; | ||
1187 | } | ||
1188 | #endif | ||
1189 | return bytes_read; | ||
1190 | } | ||
1191 | |||
1192 | long hd24fs::readsector(FSHANDLE devhd24,unsigned long sectornum,unsigned char * bootblock) | ||
1193 | { | ||
1194 | return readsectors(devhd24,sectornum,bootblock,1); | ||
1195 | } | ||
1196 | |||
1197 | long hd24fs::readsector_noheader(hd24fs* currhd24,unsigned long sectornum,unsigned char * bootblock) | ||
1198 | { | ||
1199 | return readsector_noheader(currhd24->devhd24,sectornum,bootblock); | ||
1200 | } | ||
1201 | |||
1202 | long hd24fs::readsector_noheader(FSHANDLE devhd24,unsigned long sectornum,unsigned char * bootblock) | ||
1203 | { | ||
1204 | unsigned long headersecs=this->headersectors; | ||
1205 | this->headersectors=0; // disable header processing, if applies | ||
1206 | long number_read=readsectors(devhd24,sectornum,bootblock,1); | ||
1207 | this->headersectors=headersecs; // re-enable header processing | ||
1208 | return number_read; | ||
1209 | } | ||
1210 | |||
1211 | long hd24fs::writesector(FSHANDLE devhd24,unsigned long sectornum,unsigned char * bootblock) | ||
1212 | { | ||
1213 | return writesectors(devhd24,sectornum,bootblock,1); | ||
1214 | } | ||
1215 | |||
1216 | string* hd24fs::gethd24currentdir(int argc,char* argv[]) | ||
1217 | { | ||
1218 | /* For future use. We may save a file in the | ||
1219 | homedir of the user containing info about which | ||
1220 | "path" (project/songname/file format) was last | ||
1221 | selected by the user. | ||
1222 | */ | ||
1223 | |||
1224 | return new string("/"); | ||
1225 | } | ||
1226 | |||
1227 | string* hd24fs::gethd24currentdir() | ||
1228 | { | ||
1229 | return new string("/"); | ||
1230 | } | ||
1231 | |||
1232 | unsigned char* hd24fs::readdiskinfo() | ||
1233 | { | ||
1234 | #if (HD24FSDEBUG==1) | ||
1235 | cout << "Driveusage before readdiskinfo=" << (int)(this->sectors_driveusage) << endl; | ||
1236 | #endif | ||
1237 | // read disk info | ||
1238 | if (/*formatting||*/(sector_boot==NULL)) | ||
1239 | { | ||
1240 | this->readbootinfo(); | ||
1241 | } | ||
1242 | if (sector_diskinfo!=NULL) | ||
1243 | { | ||
1244 | memutils::myfree("readdiskinfo",sector_diskinfo); | ||
1245 | sector_diskinfo=NULL; | ||
1246 | } | ||
1247 | sector_diskinfo=(unsigned char *)memutils::mymalloc("readdiskinfo",1024,1); | ||
1248 | if (sector_diskinfo!=NULL) | ||
1249 | { | ||
1250 | readsector(devhd24,1,sector_diskinfo); // fstfix follows | ||
1251 | fstfix (sector_diskinfo,512); | ||
1252 | } | ||
1253 | #if (HD24FSDEBUG==1) | ||
1254 | cout << "Driveusage after readdiskinfo=" << (int)(this->sectors_driveusage) << endl; | ||
1255 | #endif | ||
1256 | return sector_diskinfo; | ||
1257 | } | ||
1258 | |||
1259 | bool hd24fs::useheaderfile(string headerfilename) | ||
1260 | { | ||
1261 | getsector_bootinfo(); | ||
1262 | if (sector_boot==NULL) | ||
1263 | { | ||
1264 | /* we haven't got a main device yet | ||
1265 | so we cannot apply a header to it */ | ||
1266 | return false; | ||
1267 | } | ||
1268 | // allow writing to header. | ||
1269 | #if defined(LINUX) || defined(DARWIN) | ||
1270 | FSHANDLE handle=open64(headerfilename.c_str(),MODE_RDWR); //read binary | ||
1271 | #endif | ||
1272 | #ifdef WINDOWS | ||
1273 | // cout << "Mode=" << mode << endl; | ||
1274 | FSHANDLE handle=CreateFile(headerfilename.c_str(),MODE_RDWR, | ||
1275 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
1276 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
1277 | #endif | ||
1278 | |||
1279 | if (isinvalidhandle(handle)) return false; | ||
1280 | // cout << "Trying to enable header mode with file " << headerfilename << endl; | ||
1281 | hd24header=handle; | ||
1282 | this->headersectors=0; | ||
1283 | this->headersectors=getlastsectornum(hd24header)+1; | ||
1284 | // re-read disk info as number of projects etc can differ with header | ||
1285 | readsector(devhd24,1,sector_diskinfo); // fstfix follows | ||
1286 | fstfix (sector_diskinfo,512); | ||
1287 | |||
1288 | // cout << "headersectors=" << this->headersectors << "this=" <<this << endl; | ||
1289 | return true; | ||
1290 | } | ||
1291 | |||
1292 | void hd24fs::clearbuffer(unsigned char* buffer,unsigned int bytes) | ||
1293 | { | ||
1294 | /* clear buffer */ | ||
1295 | for (unsigned int i=0;i<bytes;i++) { | ||
1296 | buffer[i]=0; | ||
1297 | } | ||
1298 | return; | ||
1299 | } | ||
1300 | |||
1301 | void hd24fs::clearbuffer(unsigned char* buffer) | ||
1302 | { | ||
1303 | clearbuffer(buffer,512); | ||
1304 | } | ||
1305 | |||
1306 | |||
1307 | void hd24fs::cleardriveinfo(unsigned char* buffer) | ||
1308 | { | ||
1309 | clearbuffer(buffer); | ||
1310 | string drivename="Drive Name"; | ||
1311 | this->setname(buffer,drivename,DRIVEINFO_VOLUME_8,DRIVEINFO_VOLUME); | ||
1312 | return; | ||
1313 | } | ||
1314 | |||
1315 | void hd24fs::useinternalboot(unsigned char* buffer,__uint32 lastsector) | ||
1316 | { | ||
1317 | unsigned char internal_boot[136]= | ||
1318 | { | ||
1319 | 0x54,0x41,0x44,0x41,0x54,0x53,0x46,0x20, 0x20,0x30,0x31,0x31,0x33,0xcc,0xaa,0x55, | ||
1320 | 0x80,0x04,0x00,0x00,0x02,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, | ||
1321 | 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x01,0x00,0x00,0x00,0x01,0x00,0x00,0x00, | ||
1322 | 0x02,0x00,0x00,0x00,0x03,0x00,0x00,0x00, 0x05,0x00,0x00,0x00,0x0f,0x00,0x00,0x00, | ||
1323 | 0x2f,0x04,0x00,0x00,0x00,0x00,0x00,0x00, 0x14,0x00,0x00,0x00,0x01,0x00,0x00,0x00, | ||
1324 | 0x63,0x00,0x00,0x00,0x63,0x00,0x00,0x00, 0x77,0x00,0x00,0x00,0x02,0x00,0x00,0x00, | ||
1325 | 0x05,0x00,0x00,0x00,0x07,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x49,0x26,0x00,0x00, | ||
1326 | 0x76,0x0c,0x01,0x00,0x80,0x8b,0x12,0x00, 0x1f,0x04,0x00,0x00,0xf6,0x97,0x13,0x00, | ||
1327 | 0x14,0x89,0xb4,0x04,0x7f,0x2d,0xc9,0x04 | ||
1328 | }; | ||
1329 | |||
1330 | clearbuffer(buffer); | ||
1331 | |||
1332 | /* fill buffer with default boot info */ | ||
1333 | for (unsigned int i=0;i<sizeof(internal_boot);i++) { | ||
1334 | buffer[i]=internal_boot[i]; | ||
1335 | } | ||
1336 | |||
1337 | /* If a specific FS size (in sectors) was given, update boot info | ||
1338 | to match that size */ | ||
1339 | if (lastsector!=0) | ||
1340 | { | ||
1341 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1342 | cout << "Calculating number of clusters on the drive" << endl; | ||
1343 | #endif | ||
1344 | fstfix(buffer,512); // convert into editable format | ||
1345 | |||
1346 | Convert::setint32(buffer,FSINFO_LAST_SECTOR,lastsector); | ||
1347 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1348 | cout << "Last sector=" << lastsector << endl; | ||
1349 | #endif | ||
1350 | // allocatable sectors=total sectors-(2*fs sectors+undo area) | ||
1351 | // tot secs-0x14a46b | ||
1352 | |||
1353 | __uint32 allocatablesectors=lastsector-0x14a46b; | ||
1354 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1355 | cout << "# allocatable sectors=" << allocatablesectors << endl; | ||
1356 | #endif | ||
1357 | Convert::setint32(buffer,FSINFO_ALLOCATABLE_SECTORCOUNT,allocatablesectors); | ||
1358 | |||
1359 | // (15 sectors of drive usage info=((15*512)-8)*8 bits | ||
1360 | // | ||
1361 | __uint32 maxclusters=((15 /*sectors of alloc info*/ | ||
1362 | *512 /*bytes*/) | ||
1363 | -8 /* checksum bytes */) | ||
1364 | *8 /* bits per byte */; | ||
1365 | // represents ~ 61376 allocatable clusters | ||
1366 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1367 | cout << "max # of clusters=" << maxclusters << endl; | ||
1368 | #endif | ||
1369 | __uint32 allocatableaudioblocks=(allocatablesectors - (allocatablesectors%0x480))/0x480; | ||
1370 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1371 | cout << "allocatable audio blocks=" << allocatableaudioblocks << endl; | ||
1372 | #endif | ||
1373 | // given the maximum number of clusters | ||
1374 | // and the total number of allocatable audio blocks, | ||
1375 | // we must decide on the number of audio blocks per cluster. | ||
1376 | __uint32 rest=0; | ||
1377 | if ((allocatableaudioblocks%maxclusters)>0) rest++; | ||
1378 | __uint32 blockspercluster=rest+((allocatableaudioblocks-(allocatableaudioblocks%maxclusters))/maxclusters); | ||
1379 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1380 | cout << "blocks per cluster="<<blockspercluster<< endl; | ||
1381 | #endif | ||
1382 | Convert::setint32(buffer,FSINFO_AUDIOBLOCKS_PER_CLUSTER,blockspercluster); | ||
1383 | |||
1384 | // offset 0x14h: number of audio blocks per cluster | ||
1385 | __uint32 allocatableclusters=(allocatableaudioblocks-(allocatableaudioblocks%blockspercluster))/blockspercluster; | ||
1386 | Convert::setint32(buffer,FSINFO_FREE_CLUSTERS_ON_DISK,allocatableclusters); | ||
1387 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1388 | cout << "allocatableclusters="<<allocatableclusters<< endl; | ||
1389 | #endif | ||
1390 | fstfix(buffer,512); // convert back into native format | ||
1391 | } | ||
1392 | |||
1393 | /* Calculate the proper checksum for the bootinfo */ | ||
1394 | setsectorchecksum(buffer, | ||
1395 | 0 /* startoffset */, | ||
1396 | 0 /* sector */, | ||
1397 | 1 /*sectorcount */ | ||
1398 | ); | ||
1399 | return; | ||
1400 | } | ||
1401 | |||
1402 | unsigned char* hd24fs::readbootinfo() | ||
1403 | { | ||
1404 | // read boot info | ||
1405 | |||
1406 | if (sector_boot==NULL) | ||
1407 | { | ||
1408 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1409 | cout << "Malloc space for bootsector" << endl; | ||
1410 | #endif | ||
1411 | sector_boot=(unsigned char *)memutils::mymalloc("readbootinfo",1024,1); | ||
1412 | } | ||
1413 | |||
1414 | if (sector_boot!=NULL) | ||
1415 | { | ||
1416 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1417 | cout << "Malloc space for bootsector succeeded" << endl; | ||
1418 | cout << "forcemode=" << forcemode << endl; | ||
1419 | #endif | ||
1420 | if (formatting||(!forcemode)) { | ||
1421 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1422 | cout << "Reading sector (From disk)" << endl; | ||
1423 | #endif | ||
1424 | readsector(devhd24,0,sector_boot); | ||
1425 | } else { | ||
1426 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1427 | cout << "Using internal boot." << endl; | ||
1428 | #endif | ||
1429 | useinternalboot(sector_boot,0); | ||
1430 | } | ||
1431 | fstfix(sector_boot,512); | ||
1432 | } else { | ||
1433 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1434 | cout << "Malloc space for bootsector failed" << endl; | ||
1435 | #endif | ||
1436 | } | ||
1437 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1438 | dumpsector((const char*)sector_boot); | ||
1439 | #endif | ||
1440 | return sector_boot; | ||
1441 | } | ||
1442 | |||
1443 | unsigned char* hd24fs::readdriveusageinfo() | ||
1444 | { | ||
1445 | #if (HD24FSDEBUG==1)|| (HD24FSDEBUG_QUICKFORMAT==1) | ||
1446 | cout << "hd24fs::readdriveusageinfo()" << endl; | ||
1447 | #endif | ||
1448 | |||
1449 | // read file allocation table/disk usage table | ||
1450 | unsigned int driveusagecount=driveusagesectorcount(); | ||
1451 | if (sectors_driveusage==NULL) | ||
1452 | { | ||
1453 | |||
1454 | sectors_driveusage=(unsigned char *)memutils::mymalloc("readdriveusageinfo/sectors_driveusage",512*(driveusagecount+1),1); | ||
1455 | } | ||
1456 | //cout << "ptr=" << sectors_driveusage << endl; | ||
1457 | if (sectors_driveusage!=NULL) | ||
1458 | { | ||
1459 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1460 | cout << "hd24fs::readdriveusageinfo() reading " | ||
1461 | << driveusagecount << "sectors into buffer at " | ||
1462 | << §ors_driveusage << endl; | ||
1463 | #endif | ||
1464 | readsectors(devhd24,driveusagefirstsector(),sectors_driveusage,driveusagecount); | ||
1465 | fstfix(sectors_driveusage,512*driveusagecount); | ||
1466 | |||
1467 | } | ||
1468 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1469 | cout << "Dumping newly read sector to screen:" << endl ; | ||
1470 | dumpsector((const char*)sectors_driveusage); | ||
1471 | #endif | ||
1472 | return sectors_driveusage; | ||
1473 | } | ||
1474 | |||
1475 | unsigned char* hd24fs::resetsongusage() | ||
1476 | { | ||
1477 | // Reset song usage table. First we occupy all of it; | ||
1478 | // then we make only accessible entries available. | ||
1479 | if (sectors_songusage==NULL) | ||
1480 | { | ||
1481 | sectors_songusage=(unsigned char *)memutils::mymalloc("resetsongusage",512*3,1); | ||
1482 | if (sectors_songusage==NULL) | ||
1483 | { | ||
1484 | return NULL; | ||
1485 | } | ||
1486 | } | ||
1487 | |||
1488 | if (sectors_songusage!=NULL) | ||
1489 | { | ||
1490 | for (int i=0;i<512*3;i++) | ||
1491 | { | ||
1492 | sectors_songusage[i]=0xff; | ||
1493 | } | ||
1494 | } | ||
1495 | |||
1496 | __uint32 i; | ||
1497 | // table is initialized, now populate it. | ||
1498 | __uint32 maxprojs=this->maxprojects(); | ||
1499 | __uint32 maxsongcount=this->maxsongsperproject(); | ||
1500 | __uint32 totentries=maxprojs*maxsongcount; // 99 songs, 99 projects | ||
1501 | #if (HD24FSDEBUG==1) | ||
1502 | cout << "Clear song usage table..."<< endl; | ||
1503 | cout << "this=" << this << endl; | ||
1504 | #endif | ||
1505 | for (i=0;i<totentries;i++) { | ||
1506 | disablebit(i,sectors_songusage); | ||
1507 | // this is based on song sectors. | ||
1508 | // That is, entry 0=sec 0x77, | ||
1509 | // entry 1=sec 0x77+7, etc. | ||
1510 | } | ||
1511 | #if (HD24FSDEBUG==1) | ||
1512 | cout << "Usage table cleared." << endl; | ||
1513 | #endif | ||
1514 | return sectors_songusage; | ||
1515 | } | ||
1516 | |||
1517 | unsigned char* hd24fs::resetdriveusage() | ||
1518 | { | ||
1519 | #if (HD24FSDEBUG==1)||(HD24FSDEBUG_QUICKFORMAT==1) | ||
1520 | cout << "hd24fs::resetdriveusage()" << endl; | ||
1521 | #endif | ||
1522 | // Reset drive usage table. First we occupy all of it; | ||
1523 | // then we make only accessible entries available. | ||
1524 | |||
1525 | if (this->sectors_driveusage==NULL) | ||
1526 | { | ||
1527 | unsigned char* du=(unsigned char *)memutils::mymalloc("resetdriveusage/sectors_driveusage",512*15,1); | ||
1528 | sectors_driveusage=du; | ||
1529 | if (this->sectors_driveusage==NULL) | ||
1530 | { | ||
1531 | return NULL; | ||
1532 | } | ||
1533 | } | ||
1534 | |||
1535 | for (int i=0;i<512*15;i++) | ||
1536 | { | ||
1537 | sectors_driveusage[i]=0xff; | ||
1538 | } | ||
1539 | |||
1540 | if (formatting||(sector_boot==NULL) ) | ||
1541 | { | ||
1542 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1543 | cout << "hd24fs::resetdriveusage() - reloading boot info " << endl; | ||
1544 | #endif | ||
1545 | |||
1546 | this->readbootinfo(); | ||
1547 | } else { | ||
1548 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1549 | cout << "hd24fs::resetdriveusage() - using current (not reloading) boot info " << endl; | ||
1550 | #endif | ||
1551 | |||
1552 | } | ||
1553 | |||
1554 | __uint32 i; | ||
1555 | // table is initialized, now populate it. | ||
1556 | __uint32 totentries=Convert::getint32(sector_boot,FSINFO_FREE_CLUSTERS_ON_DISK); | ||
1557 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1558 | cout << "According to superblock, free clusters on disk=" << totentries << endl; | ||
1559 | dumpsector((const char*)sector_boot); | ||
1560 | #endif | ||
1561 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1562 | cout << "before reset, drive usage looks as follows: "<< endl; | ||
1563 | dumpsector((const char*)sectors_driveusage); | ||
1564 | #endif | ||
1565 | for (i=0;i<totentries;i++) { | ||
1566 | disablebit(i,sectors_driveusage); | ||
1567 | } | ||
1568 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1569 | cout << "after reset, drive usage looks as follows: "<< endl; | ||
1570 | dumpsector((const char*)sectors_driveusage); | ||
1571 | #endif | ||
1572 | |||
1573 | #if (HD24FSDEBUG==1) | ||
1574 | cout << "Drive usage table cleared." << endl; | ||
1575 | #endif | ||
1576 | return sectors_driveusage; | ||
1577 | } | ||
1578 | |||
1579 | unsigned char* hd24fs::calcsongusage() | ||
1580 | { | ||
1581 | resetsongusage(); | ||
1582 | |||
1583 | hd24project* currproj=NULL; | ||
1584 | __uint32 projcount=projectcount(); | ||
1585 | __uint32 i; | ||
1586 | __uint32 j; | ||
1587 | for (i=1; i<=projcount;i++) | ||
1588 | { | ||
1589 | if (currproj!=NULL) | ||
1590 | { | ||
1591 | delete(currproj); | ||
1592 | currproj=NULL; | ||
1593 | } | ||
1594 | currproj=getproject(i); | ||
1595 | if (currproj==NULL) | ||
1596 | { | ||
1597 | continue; | ||
1598 | } | ||
1599 | |||
1600 | // currproj!=NULL. | ||
1601 | __uint32 currsongcount=currproj->songcount(); | ||
1602 | for (j=1; j<=currsongcount;j++) | ||
1603 | { | ||
1604 | // get song sector info. | ||
1605 | __uint32 songsector = currproj->getsongsectornum(j); | ||
1606 | if (songsector==0) | ||
1607 | { | ||
1608 | // song at given entry is not in use | ||
1609 | // in this project, no need to mark it as used. | ||
1610 | continue; | ||
1611 | } | ||
1612 | |||
1613 | // mark the song used based on its entry number | ||
1614 | // (calculated from the sector where it lives) | ||
1615 | __uint32 songentry=songsector2entry(songsector); | ||
1616 | if (songentry!=INVALID_SONGENTRY) | ||
1617 | { | ||
1618 | enablebit(songentry,sectors_songusage); | ||
1619 | } | ||
1620 | } | ||
1621 | |||
1622 | if (currproj!=NULL) | ||
1623 | { | ||
1624 | delete(currproj); | ||
1625 | currproj=NULL; | ||
1626 | } | ||
1627 | } | ||
1628 | return sectors_songusage; | ||
1629 | } | ||
1630 | |||
1631 | void hd24fs::refreshsongusage() | ||
1632 | { | ||
1633 | unsigned char* songusage=calcsongusage(); | ||
1634 | __uint32 sectornum=2; /* TODO: get from fs */ | ||
1635 | __uint32 sectorcount=3; /* TODO: get from fs */ | ||
1636 | fstfix(songusage,sectorcount*512); | ||
1637 | setsectorchecksum(songusage, | ||
1638 | 0 /* startoffset */, | ||
1639 | sectornum /* sector */, | ||
1640 | sectorcount /*sectorcount */ | ||
1641 | ); | ||
1642 | this->writesectors(this->devhd24, | ||
1643 | sectornum, | ||
1644 | songusage, | ||
1645 | sectorcount); | ||
1646 | fstfix(songusage,sectorcount*512); | ||
1647 | |||
1648 | /* this also implies we need to update the superblock | ||
1649 | with the current song count */ | ||
1650 | __uint32 songcount=0; | ||
1651 | for (int i=0;i<99*99;i++) { | ||
1652 | if (!(isbitzero(i,songusage))) | ||
1653 | { | ||
1654 | songcount++; | ||
1655 | } | ||
1656 | }; | ||
1657 | songsondisk(songcount); | ||
1658 | fstfix(sector_boot,512); | ||
1659 | setsectorchecksum(sector_boot, | ||
1660 | 0 /* startoffset */, | ||
1661 | 0 /* sector */, | ||
1662 | 1 /*sectorcount */); | ||
1663 | this->writesectors(this->devhd24, | ||
1664 | 0, | ||
1665 | sector_boot, | ||
1666 | 1); | ||
1667 | fstfix(sector_boot,512); | ||
1668 | return; | ||
1669 | } | ||
1670 | |||
1671 | unsigned char* hd24fs::getsector_diskinfo() | ||
1672 | { | ||
1673 | getsector_bootinfo(); | ||
1674 | unsigned char* targetbuf=sector_diskinfo; | ||
1675 | if (/*formatting||*/(sector_diskinfo==NULL) ) | ||
1676 | { | ||
1677 | targetbuf=readdiskinfo(); | ||
1678 | } | ||
1679 | return sector_diskinfo; | ||
1680 | } | ||
1681 | |||
1682 | unsigned char* hd24fs::getsector_bootinfo() | ||
1683 | { | ||
1684 | unsigned char* targetbuf=sector_boot; | ||
1685 | if (/*formatting||*/(sector_boot==NULL) ) | ||
1686 | { | ||
1687 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1688 | cout << "Re-reading bootinfo now." << endl; | ||
1689 | #endif | ||
1690 | targetbuf=readbootinfo(); | ||
1691 | } | ||
1692 | return targetbuf; | ||
1693 | } | ||
1694 | |||
1695 | unsigned char* hd24fs::getsectors_driveusage() | ||
1696 | { | ||
1697 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1698 | cout << "hd24fs::getsectors_driveusage()" << endl; | ||
1699 | #endif | ||
1700 | |||
1701 | readbootinfo(); | ||
1702 | if (sectors_driveusage==NULL) | ||
1703 | { | ||
1704 | sectors_driveusage=readdriveusageinfo(); | ||
1705 | } | ||
1706 | return sectors_driveusage; | ||
1707 | } | ||
1708 | |||
1709 | unsigned char* hd24fs::getcopyofusagetable() | ||
1710 | { | ||
1711 | unsigned char* copyusagetable=(unsigned char*)memutils::mymalloc("copyusagetable",15*512,1); | ||
1712 | if (copyusagetable==NULL) | ||
1713 | { | ||
1714 | /* Out of memory */ | ||
1715 | return NULL; | ||
1716 | } | ||
1717 | |||
1718 | // copy current drive usage table to a copy; | ||
1719 | readdriveusageinfo(); | ||
1720 | int i; | ||
1721 | for (i=0;i<(512*15);i++) { | ||
1722 | copyusagetable[i]=sectors_driveusage[i]; | ||
1723 | } | ||
1724 | return copyusagetable; | ||
1725 | } | ||
1726 | |||
1727 | string* hd24fs::volumename() | ||
1728 | { | ||
1729 | if (!(isOpen())) | ||
1730 | { | ||
1731 | return new string(""); | ||
1732 | } | ||
1733 | getsector_diskinfo(); | ||
1734 | return Convert::readstring(sector_diskinfo,DRIVEINFO_VOLUME,64); | ||
1735 | } | ||
1736 | |||
1737 | void hd24fs::setvolumename(string newname) | ||
1738 | { | ||
1739 | if (sector_diskinfo==NULL) | ||
1740 | { | ||
1741 | readdiskinfo(); | ||
1742 | } | ||
1743 | this->setname(sector_diskinfo,newname,DRIVEINFO_VOLUME_8,DRIVEINFO_VOLUME); | ||
1744 | return; | ||
1745 | } | ||
1746 | |||
1747 | unsigned long hd24fs::driveusagesectorcount() | ||
1748 | { | ||
1749 | if (!(isOpen())) | ||
1750 | { | ||
1751 | cout << "FS not open!"; | ||
1752 | return 0; | ||
1753 | } | ||
1754 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1755 | cout << "Figuring out number of sectors used for drive usage" | ||
1756 | << endl; | ||
1757 | #endif | ||
1758 | |||
1759 | getsector_bootinfo(); | ||
1760 | return Convert::getint32(sector_boot,FSINFO_NUMSECTORS_DRIVEUSAGE); | ||
1761 | } | ||
1762 | |||
1763 | unsigned long hd24fs::clustercount() | ||
1764 | { | ||
1765 | /* | ||
1766 | Clustercount= | ||
1767 | (number of allocatable sectors on disk)/ | ||
1768 | ((sectors per audioblock)*(audioblocks per cluster)) | ||
1769 | */ | ||
1770 | if (!(isOpen())) | ||
1771 | { | ||
1772 | return 0; | ||
1773 | } | ||
1774 | getsector_bootinfo(); | ||
1775 | __uint32 allocatablesectorcount= | ||
1776 | Convert::getint32(sector_boot,FSINFO_ALLOCATABLE_SECTORCOUNT); | ||
1777 | __uint32 audioblocksize= | ||
1778 | Convert::getint32(sector_boot,FSINFO_BLOCKSIZE_IN_SECTORS); | ||
1779 | __uint32 clustersize= | ||
1780 | Convert::getint32(sector_boot,FSINFO_AUDIOBLOCKS_PER_CLUSTER) | ||
1781 | *audioblocksize; | ||
1782 | |||
1783 | allocatablesectorcount-=(allocatablesectorcount%clustersize); | ||
1784 | return allocatablesectorcount/clustersize; | ||
1785 | } | ||
1786 | |||
1787 | void hd24fs::dumpclusterusage(unsigned char* usagebuffer) | ||
1788 | { | ||
1789 | if (!(isOpen())) | ||
1790 | { | ||
1791 | return; | ||
1792 | } | ||
1793 | __uint32 clusters=clustercount(); | ||
1794 | for (__uint32 i=0;i<clusters;i++) { | ||
1795 | if (isfreecluster(i,usagebuffer)) { | ||
1796 | cout << "0"; | ||
1797 | } else { | ||
1798 | cout << "1"; | ||
1799 | } | ||
1800 | } | ||
1801 | cout <<endl; | ||
1802 | return; | ||
1803 | } | ||
1804 | |||
1805 | void hd24fs::dumpclusterusage2(unsigned char* usagebuffer) | ||
1806 | { | ||
1807 | __uint32 clusters=clustercount(); | ||
1808 | __uint32 currpos=0; | ||
1809 | cout << "DumpClusterUsage2" << endl; | ||
1810 | while (currpos<clusters) { | ||
1811 | __uint32 blockstart=currpos; | ||
1812 | while (isfreecluster(blockstart,usagebuffer) && (blockstart<clusters)) { | ||
1813 | blockstart++; | ||
1814 | } | ||
1815 | // cout << "Block starts at cluster " <<blockstart << endl; | ||
1816 | if (blockstart==clusters) { | ||
1817 | break; | ||
1818 | } | ||
1819 | |||
1820 | // blockstart now points to a nonfree cluster | ||
1821 | __uint32 blockend=blockstart; | ||
1822 | while (!isfreecluster(blockend,usagebuffer) && (blockend<clusters)) { | ||
1823 | blockend++; | ||
1824 | } | ||
1825 | // blockend now points to a free cluster | ||
1826 | currpos=blockend; | ||
1827 | __uint32 blocklen=blockend-blockstart; | ||
1828 | printf("%x %x\n",(unsigned int) cluster2sector(blockstart),(unsigned int)( getblockspercluster()*blocklen )); | ||
1829 | } | ||
1830 | } | ||
1831 | |||
1832 | unsigned long hd24fs::driveusagefirstsector() | ||
1833 | { | ||
1834 | if (!(isOpen())) | ||
1835 | { | ||
1836 | return 0; | ||
1837 | } | ||
1838 | getsector_bootinfo(); | ||
1839 | |||
1840 | return Convert::getint32(sector_boot,FSINFO_STARTSECTOR_DRIVEUSAGE); | ||
1841 | } | ||
1842 | |||
1843 | unsigned char* hd24fs::findorphanclusters() | ||
1844 | { | ||
1845 | if (!(isOpen())) | ||
1846 | { | ||
1847 | return NULL; | ||
1848 | } | ||
1849 | __uint32 driveusagecount=driveusagesectorcount(); | ||
1850 | getsectors_driveusage(); | ||
1851 | int numprojs=projectcount(); | ||
1852 | |||
1853 | if (sectors_orphan==NULL) { | ||
1854 | // only allocate once (free on object destruct) | ||
1855 | sectors_orphan=(unsigned char *)memutils::mymalloc("findorphanclusters",512*(driveusagecount+1),1); | ||
1856 | } | ||
1857 | readsectors(devhd24,driveusagefirstsector(),sectors_orphan,driveusagecount); | ||
1858 | fstfix(sectors_orphan,512*driveusagecount); | ||
1859 | |||
1860 | for (int proj=1; proj<=numprojs; proj++) { | ||
1861 | hd24project* currproj=this->getproject(proj); | ||
1862 | int numsongs=currproj->songcount(); | ||
1863 | for (int song=1; song<=numsongs; song++) { | ||
1864 | hd24song* currsong=currproj->getsong(song); | ||
1865 | if (currsong==NULL) continue; | ||
1866 | currsong->unmark_used_clusters(sectors_orphan); | ||
1867 | delete currsong; | ||
1868 | } | ||
1869 | if (currproj!=NULL) { | ||
1870 | delete currproj; | ||
1871 | currproj=NULL; | ||
1872 | } | ||
1873 | } | ||
1874 | return sectors_orphan; | ||
1875 | } | ||
1876 | |||
1877 | bool hd24fs::isbitzero(unsigned long i,unsigned char* usagebuffer) | ||
1878 | { | ||
1879 | int bitnum=i%32; | ||
1880 | i-=bitnum; | ||
1881 | i/=32; // i now is word num | ||
1882 | i*=4; // i now is offset | ||
1883 | __uint32 getword=Convert::getint32(usagebuffer,i); | ||
1884 | __uint32 mask=1; | ||
1885 | #if (HD24FSDEBUG_BITSET==1) | ||
1886 | cout << "bitnum=" << bitnum << " "; | ||
1887 | #endif | ||
1888 | mask=mask<<bitnum; | ||
1889 | __uint32 bitval=(getword & mask); | ||
1890 | #if (HD24FSDEBUG_BITSET==1) | ||
1891 | cout << "bitval=" << bitval << endl; | ||
1892 | #endif | ||
1893 | if (bitval == 0) return true; | ||
1894 | return false; | ||
1895 | } | ||
1896 | |||
1897 | void hd24fs::enablebit(__uint32 ibitnum,unsigned char* usagebuffer) | ||
1898 | { | ||
1899 | #if (HD24FSDEBUG_BITSET==1) | ||
1900 | cout << "enable bit " << ibitnum << endl; | ||
1901 | #endif | ||
1902 | int bitnum=ibitnum%32; | ||
1903 | ibitnum-=bitnum; | ||
1904 | ibitnum/=32; // i now is word num | ||
1905 | ibitnum*=4; // i now is byte offset of word | ||
1906 | __uint32 getword=Convert::getint32(usagebuffer,ibitnum); | ||
1907 | __uint32 mask=1; | ||
1908 | mask=mask<<bitnum; | ||
1909 | #if (HD24FSDEBUG_BITSET==1) | ||
1910 | cout << "getword=" << getword << "mask=" << mask << endl; | ||
1911 | #endif | ||
1912 | getword=getword|mask; | ||
1913 | Convert::setint32(usagebuffer,ibitnum,getword); | ||
1914 | } | ||
1915 | |||
1916 | void hd24fs::disablebit(__uint32 ibitnum,unsigned char* usagebuffer) | ||
1917 | { | ||
1918 | #if (HD24FSDEBUG_BITSET==1) | ||
1919 | cout << "disable bit " << ibitnum << endl; | ||
1920 | #endif | ||
1921 | int bitnum=ibitnum%32; | ||
1922 | ibitnum-=bitnum; | ||
1923 | ibitnum/=32; // i now is word num | ||
1924 | ibitnum*=4; // i now is offset | ||
1925 | __uint32 getword=Convert::getint32(usagebuffer,ibitnum); | ||
1926 | __uint32 mask=1; | ||
1927 | mask=mask<<bitnum; | ||
1928 | #if (HD24FSDEBUG_BITSET==1) | ||
1929 | cout << "getword=" << getword << "mask=" << mask << endl; | ||
1930 | #endif | ||
1931 | getword=getword& (0xFFFFFFFF ^ mask); | ||
1932 | #if (HD24FSDEBUG_BITSET==1) | ||
1933 | cout << "new getword=" << getword << endl; | ||
1934 | #endif | ||
1935 | Convert::setint32(usagebuffer,ibitnum,getword); | ||
1936 | } | ||
1937 | |||
1938 | bool hd24fs::isfreecluster(unsigned long i,unsigned char* usagebuffer) | ||
1939 | { | ||
1940 | return isbitzero(i,usagebuffer); | ||
1941 | } | ||
1942 | |||
1943 | void hd24fs::allocatecluster(__uint32 clusternum,unsigned char* usagebuffer) | ||
1944 | { | ||
1945 | enablebit(clusternum,usagebuffer); | ||
1946 | } | ||
1947 | |||
1948 | void hd24fs::freecluster(__uint32 clusternum,unsigned char* usagebuffer) | ||
1949 | { | ||
1950 | disablebit(clusternum,usagebuffer); | ||
1951 | } | ||
1952 | void hd24fs::allocatecluster(__uint32 clusternum) | ||
1953 | { | ||
1954 | allocatecluster(clusternum,sectors_driveusage); | ||
1955 | } | ||
1956 | |||
1957 | void hd24fs::freecluster(__uint32 clusternum) | ||
1958 | { | ||
1959 | freecluster(clusternum,sectors_driveusage); | ||
1960 | } | ||
1961 | |||
1962 | unsigned long hd24fs::freeclustercount() | ||
1963 | { | ||
1964 | if (!(isOpen())) | ||
1965 | { | ||
1966 | return 0; | ||
1967 | } | ||
1968 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1969 | cout << "hd24fs::freeclustercount()" << endl; | ||
1970 | #endif | ||
1971 | |||
1972 | sectors_driveusage=getsectors_driveusage(); | ||
1973 | |||
1974 | if (sectors_driveusage==NULL) | ||
1975 | { | ||
1976 | return 0; // cannot get driveusage sectors, 0 clusters free. | ||
1977 | } | ||
1978 | unsigned long i=0; | ||
1979 | __uint32 fsc=driveusagesectorcount(); | ||
1980 | |||
1981 | if (fsc>0xFF) return 0; | ||
1982 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1983 | cout << "Sectors used for drive usage=" << fsc << endl; | ||
1984 | #endif | ||
1985 | __uint32 clusters=((fsc /*sectors of alloc info*/ | ||
1986 | *512 /*bytes*/) | ||
1987 | -8 /* checksum bytes */) | ||
1988 | *8 /* bits per byte */; | ||
1989 | //unsigned long clusters=((512*fsc-1)+504)*8; | ||
1990 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1991 | cout << "Total clusters=" << clusters << endl; | ||
1992 | #endif | ||
1993 | |||
1994 | unsigned long freeclusters=0; | ||
1995 | for (i=0;i<clusters;i++) { | ||
1996 | if (isfreecluster(i,sectors_driveusage)) | ||
1997 | { | ||
1998 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
1999 | cout << "Cluster " << i << " is free" << endl; | ||
2000 | #endif | ||
2001 | freeclusters++; | ||
2002 | } | ||
2003 | } | ||
2004 | return freeclusters; | ||
2005 | } | ||
2006 | |||
2007 | string* hd24fs::freespace(unsigned long rate,unsigned long tracks) | ||
2008 | { | ||
2009 | if (!(isOpen())) | ||
2010 | { | ||
2011 | return new string(""); | ||
2012 | } | ||
2013 | |||
2014 | unsigned long freeclusters=freeclustercount(); | ||
2015 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2016 | cout << "free clusters=" << freeclusters << endl; | ||
2017 | #endif | ||
2018 | __uint64 freesectors=freeclusters*getblocksizeinsectors()*getblockspercluster(); | ||
2019 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2020 | cout << "free sectors=" << freesectors << endl; | ||
2021 | #endif | ||
2022 | __uint64 freebytes=freesectors*SECTORSIZE; | ||
2023 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2024 | cout << "free bytes=" << freesectors << endl; | ||
2025 | #endif | ||
2026 | __uint64 freesamples=(__uint64)(freebytes/3); | ||
2027 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2028 | cout << "free samples=" << freesamples << endl; | ||
2029 | #endif | ||
2030 | __uint64 freeseconds=(__uint64)(freesamples/rate/tracks); | ||
2031 | unsigned long freehours=(freeseconds-(freeseconds%3600))/3600; | ||
2032 | freeseconds-=(freehours*3600); | ||
2033 | unsigned long freeminutes=(freeseconds-(freeseconds%60))/60; | ||
2034 | freeseconds-=(freeminutes*60); | ||
2035 | string* newst=Convert::int2str(freehours); | ||
2036 | *newst+=" hr "; | ||
2037 | string* freemins=Convert::int2str(freeminutes,2,"0"); | ||
2038 | *newst+=*freemins; | ||
2039 | delete freemins; | ||
2040 | *newst+=" min "; | ||
2041 | string* freesecs=Convert::int2str(freeseconds,2,"0"); | ||
2042 | *newst+=*freesecs; | ||
2043 | delete freesecs; | ||
2044 | *newst+=" sec "; | ||
2045 | return newst; // throw exception? | ||
2046 | } | ||
2047 | |||
2048 | string* hd24fs::version() | ||
2049 | { | ||
2050 | if (!(isOpen())) | ||
2051 | { | ||
2052 | return new string(""); | ||
2053 | } | ||
2054 | getsector_bootinfo(); | ||
2055 | string* newst=Convert::readstring(sector_boot,FSINFO_VERSION_MAJOR,1); | ||
2056 | *newst+="."; | ||
2057 | string* dummy=Convert::readstring(sector_boot,FSINFO_VERSION_MINOR,2); | ||
2058 | *newst+=*dummy; | ||
2059 | delete dummy; | ||
2060 | return newst; | ||
2061 | } | ||
2062 | |||
2063 | unsigned long hd24fs::maxprojects() | ||
2064 | { | ||
2065 | if (!(isOpen())) | ||
2066 | { | ||
2067 | return 0; | ||
2068 | } | ||
2069 | getsector_bootinfo(); | ||
2070 | unsigned long maxprojs=Convert::getint32(sector_boot,FSINFO_MAXPROJECTS); | ||
2071 | if (maxprojs>99) { | ||
2072 | maxprojs=99; | ||
2073 | /* safety feature while no larger project | ||
2074 | counts are known to be valid; gives | ||
2075 | more stability when working with corrupt drives */ | ||
2076 | this->writeprotected=true; | ||
2077 | } | ||
2078 | return maxprojs; | ||
2079 | } | ||
2080 | |||
2081 | unsigned long hd24fs::getblocksizeinsectors() | ||
2082 | { | ||
2083 | if (!(isOpen())) | ||
2084 | { | ||
2085 | return 0; | ||
2086 | } | ||
2087 | getsector_bootinfo(); | ||
2088 | if (forcemode) { | ||
2089 | return 0x480; | ||
2090 | } | ||
2091 | unsigned long blocksize=Convert::getint32(sector_boot,FSINFO_BLOCKSIZE_IN_SECTORS); | ||
2092 | if (blocksize!=0x480) | ||
2093 | { | ||
2094 | this->writeprotected=true; | ||
2095 | } | ||
2096 | return blocksize; | ||
2097 | } | ||
2098 | |||
2099 | unsigned long hd24fs::getbytesperaudioblock() | ||
2100 | { | ||
2101 | return getblocksizeinsectors()*512; | ||
2102 | } | ||
2103 | |||
2104 | unsigned long hd24fs::getblockspercluster() | ||
2105 | { | ||
2106 | if (!(isOpen())) | ||
2107 | { | ||
2108 | return 0; | ||
2109 | } | ||
2110 | getsector_bootinfo(); | ||
2111 | unsigned long maxprojs=Convert::getint32(sector_boot,FSINFO_AUDIOBLOCKS_PER_CLUSTER); | ||
2112 | return maxprojs; | ||
2113 | } | ||
2114 | |||
2115 | unsigned long hd24fs::maxsongsperproject() | ||
2116 | { | ||
2117 | if (!(isOpen())) | ||
2118 | { | ||
2119 | return 0; | ||
2120 | } | ||
2121 | getsector_bootinfo(); | ||
2122 | unsigned long maxsongs=Convert::getint32(sector_boot,FSINFO_MAXSONGSPERPROJECT); | ||
2123 | return maxsongs; | ||
2124 | } | ||
2125 | |||
2126 | __uint32 hd24fs::getprojectsectornum(__uint32 i) | ||
2127 | { | ||
2128 | #if (HD24FSDEBUG==1) | ||
2129 | cout << "hd24fs::getprojectsectornum("<<i<<")"<< endl; | ||
2130 | #endif | ||
2131 | // 1-based project sectornum | ||
2132 | if (!(isOpen())) | ||
2133 | { | ||
2134 | return 0; | ||
2135 | } | ||
2136 | if (i<1) | ||
2137 | { | ||
2138 | return 0; | ||
2139 | } | ||
2140 | if (i>maxprojects()) | ||
2141 | { | ||
2142 | return 0; | ||
2143 | } | ||
2144 | getsector_diskinfo(); | ||
2145 | unsigned long projsec=Convert::getint32(sector_diskinfo, | ||
2146 | DRIVEINFO_PROJECTLIST+((i-1)*4)); | ||
2147 | |||
2148 | #if (HD24FSDEBUG==1) | ||
2149 | cout << "projsec = " << projsec << endl; | ||
2150 | #endif | ||
2151 | return projsec; | ||
2152 | } | ||
2153 | |||
2154 | void hd24fs::lastprojectid(signed long projectid) | ||
2155 | { | ||
2156 | if (!(isOpen())) | ||
2157 | { | ||
2158 | return; | ||
2159 | } | ||
2160 | getsector_diskinfo(); | ||
2161 | __uint32 lastprojsec=getprojectsectornum(projectid); | ||
2162 | if (lastprojsec==0) { | ||
2163 | return; | ||
2164 | } | ||
2165 | if (projectid==lastprojectid()) | ||
2166 | { | ||
2167 | // nothing changed- nothing to save | ||
2168 | return; | ||
2169 | } | ||
2170 | |||
2171 | Convert::setint32(sector_diskinfo,DRIVEINFO_LASTPROJ,lastprojsec); | ||
2172 | savedriveinfo(); | ||
2173 | return; | ||
2174 | } | ||
2175 | |||
2176 | signed long hd24fs::lastprojectid() | ||
2177 | { | ||
2178 | if (!(isOpen())) | ||
2179 | { | ||
2180 | return -1; | ||
2181 | } | ||
2182 | getsector_diskinfo(); | ||
2183 | unsigned long lastprojsec=Convert::getint32(sector_diskinfo,DRIVEINFO_LASTPROJ); | ||
2184 | if (lastprojsec==0) { | ||
2185 | // TODO: This differs from the real HD24 where even | ||
2186 | // on a freshly formatted drive there always is at least | ||
2187 | // one project. | ||
2188 | return -1; | ||
2189 | } | ||
2190 | int i; | ||
2191 | int maxprojs=maxprojects(); | ||
2192 | for (i=1;i<=maxprojs;i++) | ||
2193 | { | ||
2194 | unsigned long projsec=getprojectsectornum(i); | ||
2195 | |||
2196 | if (projsec==lastprojsec) | ||
2197 | { | ||
2198 | return i; | ||
2199 | } | ||
2200 | } | ||
2201 | // no default project. hm...... | ||
2202 | if (maxprojs>=1) { | ||
2203 | return 1; | ||
2204 | } | ||
2205 | return -1; | ||
2206 | } | ||
2207 | |||
2208 | __uint32 hd24fs::getunusedsongsector() | ||
2209 | { | ||
2210 | if (!(isOpen())) | ||
2211 | { | ||
2212 | return 0; // return 0- this is an invalid songsector | ||
2213 | // so error is detectable | ||
2214 | } | ||
2215 | |||
2216 | // generate an up-to-date song usage table. | ||
2217 | unsigned char* songusage=calcsongusage(); | ||
2218 | |||
2219 | int currsongentry=0; | ||
2220 | signed long foundentry=-1; | ||
2221 | int maxprojs=this->maxprojects(); | ||
2222 | int maxsongcount=this->maxsongsperproject(); | ||
2223 | int totentries=maxprojs*maxsongcount; // 99 songs, 99 projects | ||
2224 | while (currsongentry<totentries) // 99 sec, 99 proj | ||
2225 | { | ||
2226 | if (isbitzero(currsongentry,songusage)) { | ||
2227 | foundentry=currsongentry; | ||
2228 | break; | ||
2229 | } | ||
2230 | currsongentry++; | ||
2231 | } | ||
2232 | if (foundentry==-1) | ||
2233 | { | ||
2234 | return 0; | ||
2235 | } | ||
2236 | return songentry2sector(foundentry); | ||
2237 | } | ||
2238 | |||
2239 | void hd24fs::allocsongentry(unsigned long songentry) | ||
2240 | { | ||
2241 | enablebit(songentry,sectors_songusage); | ||
2242 | } | ||
2243 | |||
2244 | unsigned long hd24fs::projectcount() | ||
2245 | { | ||
2246 | if (!(isOpen())) | ||
2247 | { | ||
2248 | return 0; | ||
2249 | } | ||
2250 | getsector_diskinfo(); | ||
2251 | unsigned long lastprojsec=Convert::getint32(sector_diskinfo,DRIVEINFO_LASTPROJ); | ||
2252 | if (lastprojsec==0) | ||
2253 | { | ||
2254 | return 0; | ||
2255 | } | ||
2256 | __uint32 projcount=Convert::getint32(sector_diskinfo,DRIVEINFO_PROJECTCOUNT); | ||
2257 | if (projcount>maxprojects()) return maxprojects(); | ||
2258 | |||
2259 | return projcount; | ||
2260 | } | ||
2261 | |||
2262 | int hd24fs::mode() { | ||
2263 | return p_mode; | ||
2264 | } | ||
2265 | |||
2266 | hd24project* hd24fs::getproject(__sint32 projectid) | ||
2267 | { | ||
2268 | __uint32 projsec=getprojectsectornum(projectid); // 1-based | ||
2269 | if (projsec==0) { | ||
2270 | return NULL; | ||
2271 | } | ||
2272 | return new hd24project(this,projectid); | ||
2273 | } | ||
2274 | |||
2275 | hd24project* hd24fs::createproject(const char* projectname) | ||
2276 | { | ||
2277 | #if (HD24FSDEBUG==1) | ||
2278 | cout << "hd24fs::createproject(" << projectname << ")" << endl; | ||
2279 | // cout << "Driveusage before createproject=" << (int)(this->sectors_driveusage) << endl; | ||
2280 | #endif | ||
2281 | /* This creates a new project (with given project name) | ||
2282 | on the drive (if possible). | ||
2283 | NULL is returned when unsuccessful, a pointer to the | ||
2284 | project otherwise. | ||
2285 | */ | ||
2286 | #if (HD24FSDEBUG==1) | ||
2287 | cout << "hd24fs asked to create project " << projectname << endl; | ||
2288 | #endif | ||
2289 | int i; | ||
2290 | // find first project with project sector num 0! | ||
2291 | int maxprojs=maxprojects(); | ||
2292 | |||
2293 | getsector_bootinfo(); | ||
2294 | if (sector_boot==NULL) { | ||
2295 | // unknown cluster size. | ||
2296 | return 0; | ||
2297 | } | ||
2298 | __uint32 firstprojsec=Convert::getint32(sector_boot,FSINFO_FIRST_PROJECT_SECTOR); | ||
2299 | cout << "Firstprojsec="<< firstprojsec << endl; | ||
2300 | __uint32 secsperproj=Convert::getint32(sector_boot,FSINFO_SECTORS_PER_PROJECT); | ||
2301 | cout << "Sectors per project="<< secsperproj << endl; | ||
2302 | |||
2303 | // Let's calculate a list of unused project sectors | ||
2304 | char* projused=(char*)memutils::mymalloc("createproject",maxprojs,1); | ||
2305 | if (projused==NULL) { | ||
2306 | return 0; // out of memory | ||
2307 | } | ||
2308 | |||
2309 | for (i=0;i<maxprojs;i++) { | ||
2310 | projused[i]=0; | ||
2311 | } | ||
2312 | |||
2313 | for (i=1;i<=maxprojs;i++) { | ||
2314 | __uint32 projsec=getprojectsectornum(i); // 1-based | ||
2315 | if (projsec!=0) | ||
2316 | { | ||
2317 | /* projects do not necessarily have to | ||
2318 | be stored on disk in the same order | ||
2319 | as their project numbers- | ||
2320 | so project 1 can be at sector 0x15 | ||
2321 | while project 2 is at sector 0x14. | ||
2322 | This is why we have to convert project | ||
2323 | sector to project slot. The cast to int | ||
2324 | makes sure we don't accidentally end up | ||
2325 | with a float index that can be misinterpreted. */ | ||
2326 | projused[(int)((projsec-firstprojsec)/secsperproj)]=1; | ||
2327 | } | ||
2328 | } | ||
2329 | |||
2330 | int foundslotnum=0; | ||
2331 | for (i=1;i<=maxprojs;i++) | ||
2332 | { | ||
2333 | __uint32 projsec=getprojectsectornum(i); // 1-based | ||
2334 | |||
2335 | if (projsec==0) | ||
2336 | { | ||
2337 | foundslotnum=i; | ||
2338 | break; | ||
2339 | } | ||
2340 | } | ||
2341 | |||
2342 | // Now find an unused project sector | ||
2343 | __uint32 foundsecnum=0; | ||
2344 | for (i=0;i<maxprojs;i++) { | ||
2345 | if (projused[i]==0) { | ||
2346 | foundsecnum=(i*secsperproj)+firstprojsec; | ||
2347 | break; | ||
2348 | } | ||
2349 | } | ||
2350 | memutils::myfree("projused",projused); | ||
2351 | |||
2352 | if (foundslotnum==0) | ||
2353 | { | ||
2354 | // no unused slots. | ||
2355 | return NULL; | ||
2356 | } | ||
2357 | __uint32 projectid=foundslotnum; | ||
2358 | foundslotnum--; // use 0-based slot num | ||
2359 | |||
2360 | if (foundsecnum==0) { | ||
2361 | // no unsused project sectors found. | ||
2362 | // This is seriously fishy as there *are* | ||
2363 | // unused slots- so that should never happen. | ||
2364 | // Looks like we're dealing with a corrupt FS! | ||
2365 | this->writeprotected=true; | ||
2366 | return NULL; | ||
2367 | } | ||
2368 | // Now to assign the first unused project sector | ||
2369 | // to the first unused project slot. | ||
2370 | |||
2371 | // First, update the drive info. | ||
2372 | getsector_diskinfo(); | ||
2373 | |||
2374 | // Add the new project pointer to the disk info: | ||
2375 | Convert::setint32(sector_diskinfo,DRIVEINFO_PROJECTLIST+(foundslotnum*4),foundsecnum); | ||
2376 | Convert::setint32(sector_diskinfo,DRIVEINFO_LASTPROJ,foundsecnum); | ||
2377 | |||
2378 | Convert::setint32(sector_diskinfo,DRIVEINFO_PROJECTCOUNT, | ||
2379 | Convert::getint32(sector_diskinfo,DRIVEINFO_PROJECTCOUNT)+1); | ||
2380 | |||
2381 | bool isnew=true; | ||
2382 | hd24project* newproject=new hd24project(this,projectid,foundsecnum,projectname,isnew); | ||
2383 | savedriveinfo(); | ||
2384 | |||
2385 | return newproject; | ||
2386 | } | ||
2387 | |||
2388 | bool hd24fs::isallinput() | ||
2389 | { | ||
2390 | return this->allinput; | ||
2391 | } | ||
2392 | |||
2393 | void hd24fs::setallinput(bool p_allinput) | ||
2394 | { | ||
2395 | this->allinput=p_allinput; | ||
2396 | } | ||
2397 | |||
2398 | void hd24fs::setallinput(void) | ||
2399 | { | ||
2400 | this->setallinput(true); | ||
2401 | } | ||
2402 | |||
2403 | /* These three functions are for the 'auto input' button | ||
2404 | (having to do with automatic toggling of monitoring | ||
2405 | between 'tape' and inputs during a punch in */ | ||
2406 | bool hd24fs::isautoinput() | ||
2407 | { | ||
2408 | return this->autoinput; | ||
2409 | } | ||
2410 | |||
2411 | void hd24fs::setautoinput(bool p_autoinput) | ||
2412 | { | ||
2413 | this->autoinput=p_autoinput; | ||
2414 | } | ||
2415 | |||
2416 | void hd24fs::setautoinput(void) | ||
2417 | { | ||
2418 | this->setautoinput(true); | ||
2419 | } | ||
2420 | |||
2421 | void hd24fs::writebackupblock(__uint32 p_sector,__uint32 p_blocksize, | ||
2422 | __uint32 lastsec,bool fullcommit) | ||
2423 | { | ||
2424 | /** Used by commit. This writes a logical block | ||
2425 | of file system data to the end of the drive. */ | ||
2426 | unsigned char backbuf[1024]; | ||
2427 | |||
2428 | __uint32 i; | ||
2429 | __uint32 blocksize=p_blocksize; | ||
2430 | |||
2431 | if (fullcommit==false) | ||
2432 | { | ||
2433 | // we're doing a quick commit, so only backup | ||
2434 | // changed blocks. | ||
2435 | if (p_sector>highestFSsectorwritten) return; | ||
2436 | } | ||
2437 | |||
2438 | for (i=1;i<=blocksize;i++) { | ||
2439 | // read sector $sector+$i-1 | ||
2440 | // write to sector -($sector+1+$blocksize-$i) | ||
2441 | // (where -1= last sector) | ||
2442 | __uint32 currentsourcesector=p_sector+(i-1); | ||
2443 | |||
2444 | readsector_noheader(this, currentsourcesector, backbuf); | ||
2445 | __uint32 targetsector=(lastsec-(p_sector+1+blocksize-i))+1; | ||
2446 | // cout << "write sec " << targetsector << endl; | ||
2447 | writesector(this->devhd24,targetsector,backbuf); | ||
2448 | } | ||
2449 | } | ||
2450 | |||
2451 | bool hd24fs::commit() | ||
2452 | { | ||
2453 | // default commit is a quick commit rather than full commit. | ||
2454 | // A quick commit only commits sectors up to the last project/song | ||
2455 | // sector changed. | ||
2456 | return this->commit(false); | ||
2457 | } | ||
2458 | bool hd24fs::commit(bool fullcommit) | ||
2459 | { | ||
2460 | /** This creates a backup of the file system to the end of the drive. */ | ||
2461 | |||
2462 | |||
2463 | #if (HD24FSDEBUG==1) | ||
2464 | cout << "hd24fs::commit()" << endl; | ||
2465 | // cout << "Driveusage before commit=" << (int)(this->sectors_driveusage) << endl; | ||
2466 | #endif | ||
2467 | if (this->headersectors!=0) | ||
2468 | { | ||
2469 | // ehm. Obviously we're not going to overwrite the | ||
2470 | // end of the drive with header file information, | ||
2471 | // as that would defeat the purpose of header files | ||
2472 | // (which is to allow safe read-only operation). | ||
2473 | return true; | ||
2474 | }; | ||
2475 | __uint32 sector=0; | ||
2476 | __uint32 blocksize=1; | ||
2477 | __uint32 count=1; | ||
2478 | __uint32 lastsec=getlastsectornum(); | ||
2479 | writebackupblock(sector,blocksize,lastsec,fullcommit); // backup superblock | ||
2480 | |||
2481 | sector+=(blocksize*count); | ||
2482 | blocksize=1; | ||
2483 | count=1; | ||
2484 | |||
2485 | writebackupblock(sector,blocksize,lastsec,fullcommit); // backup drive info | ||
2486 | |||
2487 | sector+=(blocksize*count); | ||
2488 | blocksize=3; | ||
2489 | count=1; | ||
2490 | writebackupblock(sector,blocksize,lastsec,fullcommit); // Backup undo (?) usage | ||
2491 | |||
2492 | sector+=(blocksize*count); | ||
2493 | blocksize=15; | ||
2494 | count=1; | ||
2495 | writebackupblock(sector,blocksize,lastsec,fullcommit); // Backup drive usage table | ||
2496 | |||
2497 | sector+=(blocksize*count); | ||
2498 | blocksize=1; | ||
2499 | count=99; | ||
2500 | |||
2501 | __uint32 i; | ||
2502 | for (i=1;i<=count;i++) | ||
2503 | { | ||
2504 | #if (HD24FSDEBUG_COMMIT==1) | ||
2505 | cout <<"Going to write proj backup block no. " << i << endl; | ||
2506 | #endif | ||
2507 | writebackupblock(sector+(i-1),blocksize,lastsec,fullcommit); // Backup project | ||
2508 | } | ||
2509 | |||
2510 | sector+=(blocksize*count); | ||
2511 | count=99*99; | ||
2512 | for (i=1;i<=count;i++) | ||
2513 | { | ||
2514 | #if (HD24FSDEBUG_COMMIT==1) | ||
2515 | cout <<"Going to write song backup block no. " << i << endl; | ||
2516 | #endif | ||
2517 | blocksize=2; | ||
2518 | writebackupblock(sector+(7*(i-1)),blocksize,lastsec,fullcommit); // Backup song | ||
2519 | |||
2520 | blocksize=5; | ||
2521 | writebackupblock(sector+(7*(i-1))+2,blocksize,lastsec,fullcommit); // Backup song alloc info | ||
2522 | } | ||
2523 | #if (HD24FSDEBUG_COMMIT==1) | ||
2524 | cout <<"Wrote backup blocks" << endl; | ||
2525 | cout << "Driveusage after commit=" << (int)(this->sectors_driveusage) << endl; | ||
2526 | #endif | ||
2527 | highestFSsectorwritten=0; // reset | ||
2528 | return true; | ||
2529 | } | ||
2530 | |||
2531 | long unsigned int hd24fs::setsectorchecksum(unsigned char* buffer,unsigned int startoffset,unsigned int startsector,unsigned int sectors) | ||
2532 | { | ||
2533 | // Calculates and sets the checksum for a block of data. | ||
2534 | // Data must be in drive-native format. | ||
2535 | long unsigned int checksum32 = 0; | ||
2536 | unsigned long int totbytes=(SECTORSIZE*sectors); | ||
2537 | |||
2538 | buffer[startoffset+totbytes-8]=startsector%256; | ||
2539 | buffer[startoffset+totbytes-7]=(startsector>>8)%256; | ||
2540 | buffer[startoffset+totbytes-6]=255- buffer[startoffset+totbytes-8]; | ||
2541 | buffer[startoffset+totbytes-5]=255- buffer[startoffset+totbytes-7]; | ||
2542 | |||
2543 | for (unsigned long i = 0; i < totbytes; i += 4) | ||
2544 | { | ||
2545 | unsigned long num = Convert::getint32(buffer, i+startoffset); | ||
2546 | int byte1 = num % 256; | ||
2547 | int byte2 = (num >> 8) % 256; | ||
2548 | int byte3 = (num >> 16) % 256; | ||
2549 | int byte4 = (num >> 24) % 256; | ||
2550 | num = byte4 + (byte3 << 8) + (byte2 << 16) + (byte1 << 24); | ||
2551 | checksum32 += num; | ||
2552 | } | ||
2553 | unsigned long oldchecksum=0; | ||
2554 | oldchecksum+=((unsigned char)(buffer[startoffset+totbytes-1])); oldchecksum=oldchecksum <<8; | ||
2555 | oldchecksum+=((unsigned char)(buffer[startoffset+totbytes-2])); oldchecksum=oldchecksum <<8; | ||
2556 | oldchecksum+=((unsigned char)(buffer[startoffset+totbytes-3])); oldchecksum=oldchecksum <<8; | ||
2557 | oldchecksum+=((unsigned char)(buffer[startoffset+totbytes-4])); | ||
2558 | oldchecksum-=checksum32; | ||
2559 | buffer[startoffset+totbytes-4]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
2560 | buffer[startoffset+totbytes-3]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
2561 | buffer[startoffset+totbytes-2]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
2562 | buffer[startoffset+totbytes-1]=oldchecksum%256; oldchecksum=oldchecksum >> 8; | ||
2563 | return checksum32; | ||
2564 | } | ||
2565 | |||
2566 | void hd24fs::savedriveinfo() | ||
2567 | { | ||
2568 | // This is capable of handling only 1-sector-per-project projects | ||
2569 | __uint32 driveinfosector=1; | ||
2570 | if (sector_diskinfo==NULL) | ||
2571 | { | ||
2572 | // diskinfo is not available, nothing to do. | ||
2573 | return; | ||
2574 | } | ||
2575 | #if (HD24FSDEBUG==1) | ||
2576 | cout << "FSTFIX" << endl; | ||
2577 | #endif | ||
2578 | this->fstfix(sector_diskinfo,512); // sector is now once again in native format | ||
2579 | |||
2580 | #if (HD24FSDEBUG==1) | ||
2581 | cout << "set checksum" << endl; | ||
2582 | #endif | ||
2583 | this->setsectorchecksum(sector_diskinfo,0,driveinfosector,1); | ||
2584 | #if (HD24FSDEBUG==1) | ||
2585 | cout << "write sectors" << endl; | ||
2586 | #endif | ||
2587 | this->writesectors(this->devhd24, | ||
2588 | driveinfosector, | ||
2589 | sector_diskinfo,1); | ||
2590 | |||
2591 | #if (HD24FSDEBUG==1) | ||
2592 | cout << "unfix" << endl; | ||
2593 | #endif | ||
2594 | this->fstfix(sector_diskinfo,512); // sector is now in 'fixed' format | ||
2595 | #if (HD24FSDEBUG==1) | ||
2596 | cout << "commit" << endl; | ||
2597 | #endif | ||
2598 | this->commit(); | ||
2599 | } | ||
2600 | |||
2601 | void hd24fs::setname(unsigned char* namebuf,string newname,__uint32 shortnameoff,__uint32 longnameoff) | ||
2602 | { | ||
2603 | /** Used for setting song/project/drive names | ||
2604 | Long name is up to 64 characters; short name | ||
2605 | is up to 10 chars. | ||
2606 | */ | ||
2607 | #if (HD24FSDEBUG==1) | ||
2608 | cout << "hd24fs::setname(" | ||
2609 | << "*namebuf=" << *namebuf << "," | ||
2610 | << "newname=" << newname << "," | ||
2611 | << "shortnameoff="<<shortnameoff << "," | ||
2612 | << "longnameoff=" << longnameoff <<");" << endl; | ||
2613 | #endif | ||
2614 | bool foundzero=false; | ||
2615 | for (__uint32 i=0;i<64;i++) | ||
2616 | { | ||
2617 | if (!foundzero) | ||
2618 | { | ||
2619 | namebuf[longnameoff+i]=newname.c_str()[i]; | ||
2620 | if (namebuf[longnameoff+i]==0) { | ||
2621 | foundzero=true; | ||
2622 | #if (HD24FSDEBUG==1) | ||
2623 | cout << "Found zero at " << i << endl; | ||
2624 | #endif | ||
2625 | } | ||
2626 | } | ||
2627 | else | ||
2628 | { | ||
2629 | namebuf[longnameoff+i]=0; | ||
2630 | } | ||
2631 | } | ||
2632 | // Now set FST 1.0 short name | ||
2633 | unsigned char* target=namebuf+shortnameoff; | ||
2634 | foundzero=false; | ||
2635 | __uint32 count=0; | ||
2636 | for (__uint32 i=0;i<10;i++) | ||
2637 | { | ||
2638 | if (!foundzero) | ||
2639 | { | ||
2640 | target[count]=newname.c_str()[i]; | ||
2641 | if (target[count]==0) | ||
2642 | { | ||
2643 | foundzero=true; | ||
2644 | } | ||
2645 | } | ||
2646 | else | ||
2647 | { | ||
2648 | target[count]=0x20; /* short name is filled out | ||
2649 | with spaces */ | ||
2650 | |||
2651 | } | ||
2652 | count++; | ||
2653 | if (count==8) | ||
2654 | { | ||
2655 | count=0; | ||
2656 | target+=10; | ||
2657 | } | ||
2658 | } | ||
2659 | return; | ||
2660 | } | ||
2661 | |||
2662 | void hd24fs::savedriveusage() | ||
2663 | { | ||
2664 | __uint32 driveusagesector=5; | ||
2665 | __uint32 totsectors=15; | ||
2666 | this->fstfix(sectors_driveusage,totsectors*512); // sector is now once again in native format | ||
2667 | |||
2668 | this->setsectorchecksum(sectors_driveusage,0,driveusagesector,totsectors); | ||
2669 | this->writesectors(this->devhd24, | ||
2670 | driveusagesector, | ||
2671 | sectors_driveusage,totsectors); | ||
2672 | |||
2673 | this->fstfix(sectors_driveusage,totsectors*512); // sector is now in 'fixed' format | ||
2674 | #if (HD24FSDEBUG==1) | ||
2675 | cout << "free cluster count=" << freeclustercount() << endl; | ||
2676 | #endif | ||
2677 | unsigned char* bootrec=readbootinfo(); | ||
2678 | // update FSINFO_FREE_CLUSTERS_ON_DISK | ||
2679 | |||
2680 | Convert::setint32(bootrec,FSINFO_FREE_CLUSTERS_ON_DISK,freeclustercount()); | ||
2681 | fstfix(bootrec,512); // convert back into native format | ||
2682 | |||
2683 | /* Calculate the proper checksum for the bootinfo */ | ||
2684 | setsectorchecksum(bootrec, | ||
2685 | 0 /* startoffset */, | ||
2686 | 0 /* sector */, | ||
2687 | 1 /*sectorcount */ | ||
2688 | ); | ||
2689 | this->writesectors(this->devhd24, 0,bootrec,1); | ||
2690 | fstfix(bootrec,512); // convert back into fixed format | ||
2691 | this->commit(); | ||
2692 | } | ||
2693 | |||
2694 | |||
2695 | __uint32 hd24fs::writesuperblock(__uint32 lastsec) | ||
2696 | { | ||
2697 | // writes a new superblock to an unformatted drive. | ||
2698 | // | ||
2699 | // normal start of data area=1397f6 | ||
2700 | // size of 1 audio block=0x480 sectors | ||
2701 | // fs size=0x77+7*99 | ||
2702 | // so minimum usable drive is 0x1397f6+0x480+(0x77+(7*99*99)) | ||
2703 | // =0x14a8ec sectors | ||
2704 | if (lastsec<0x14a8ec) | ||
2705 | { | ||
2706 | // drive is smaller than the minimum needed for | ||
2707 | // storing at least 1 audio block. | ||
2708 | return RESULT_FAIL; | ||
2709 | } | ||
2710 | unsigned char superblock[512]; | ||
2711 | useinternalboot(superblock,lastsec); // this automatically sets sector checksum | ||
2712 | writesectors(this->devhd24,0,&superblock[0],1); | ||
2713 | #if (HD24FSDEBUG_QUICKFORMAT==1) | ||
2714 | |||
2715 | cout << "Writing superblock." << endl; | ||
2716 | dumpsector((const char*)superblock); | ||
2717 | |||
2718 | #endif | ||
2719 | |||
2720 | force_reload(); | ||
2721 | |||
2722 | readbootinfo(); | ||
2723 | |||
2724 | #if (HD24FSDEBUG_CLUSTERddCALC==1) | ||
2725 | cout << "Displaying sector after reload." << endl; | ||
2726 | dumpsector((const char*)sector_boot); | ||
2727 | #endif | ||
2728 | |||
2729 | return RESULT_SUCCESS; | ||
2730 | } | ||
2731 | |||
2732 | void hd24fs::force_reload() | ||
2733 | { | ||
2734 | #if (HD24FSDEBUG==1) | ||
2735 | cout << "Free superblock mem" << endl; | ||
2736 | #endif | ||
2737 | if (sector_boot!=NULL) | ||
2738 | { | ||
2739 | memutils::myfree("sectors_boot",sector_boot); | ||
2740 | sector_boot=NULL; | ||
2741 | } | ||
2742 | #if (HD24FSDEBUG==1) | ||
2743 | cout << "Free diskinfo mem" << endl; | ||
2744 | #endif | ||
2745 | if (sector_diskinfo!=NULL) | ||
2746 | { | ||
2747 | memutils::myfree("sectors_diskinfo",sector_diskinfo); | ||
2748 | sector_diskinfo=NULL; | ||
2749 | } | ||
2750 | #if (HD24FSDEBUG==1) | ||
2751 | cout << "Free drive usage mem" << endl; | ||
2752 | #endif | ||
2753 | if (sectors_driveusage!=NULL) | ||
2754 | { | ||
2755 | memutils::myfree("sectors_driveusage",sectors_driveusage); | ||
2756 | sectors_driveusage=NULL; | ||
2757 | } | ||
2758 | #if (HD24FSDEBUG==1) | ||
2759 | cout << "Free orphan sectors mem" << endl; | ||
2760 | #endif | ||
2761 | if (sectors_orphan!=NULL) | ||
2762 | { | ||
2763 | memutils::myfree("sectors_orphan",sectors_orphan); | ||
2764 | sectors_orphan=NULL; | ||
2765 | } | ||
2766 | #if (HD24FSDEBUG==1) | ||
2767 | cout << "Free song usage sectors mem" << endl; | ||
2768 | #endif | ||
2769 | if (sectors_songusage!=NULL) | ||
2770 | { | ||
2771 | memutils::myfree("sectors_songusage",sectors_songusage); | ||
2772 | sectors_songusage=NULL; | ||
2773 | }; | ||
2774 | |||
2775 | } | ||
2776 | __uint32 hd24fs::writedriveinfo() | ||
2777 | { | ||
2778 | readdiskinfo(); | ||
2779 | cleardriveinfo(sector_diskinfo); | ||
2780 | fstfix(sector_diskinfo,512); // back into native format | ||
2781 | writesectors(this->devhd24,1,sector_diskinfo,1); | ||
2782 | if (sector_diskinfo!=NULL) { | ||
2783 | memutils::myfree("sector_diskinfo",sector_diskinfo); | ||
2784 | sector_diskinfo=NULL; // force re-read | ||
2785 | } | ||
2786 | hd24project* firstproject=createproject("Proj Name"); | ||
2787 | memutils::myfree("firstproject",firstproject); | ||
2788 | |||
2789 | if (sector_diskinfo!=NULL) { | ||
2790 | memutils::myfree("sector_diskinfo",sector_diskinfo); | ||
2791 | sector_diskinfo=NULL; // force re-read | ||
2792 | } | ||
2793 | __uint32 psec=getprojectsectornum(1); | ||
2794 | if (sector_diskinfo!=NULL) { | ||
2795 | memutils::myfree("sector_diskinfo",sector_diskinfo); | ||
2796 | sector_diskinfo=NULL; // force re-read | ||
2797 | } | ||
2798 | readdiskinfo(); | ||
2799 | Convert::setint32(sector_diskinfo,DRIVEINFO_LASTPROJ,psec); | ||
2800 | savedriveinfo(); | ||
2801 | |||
2802 | return RESULT_SUCCESS; | ||
2803 | } | ||
2804 | |||
2805 | __uint32 hd24fs::writesongusage() | ||
2806 | { | ||
2807 | unsigned char* buffer=resetsongusage(); | ||
2808 | if (buffer==NULL) | ||
2809 | { | ||
2810 | return RESULT_FAIL; | ||
2811 | } | ||
2812 | __uint32 sectornum=2; | ||
2813 | __uint32 sectorcount=3; | ||
2814 | fstfix(buffer,sectorcount*512); | ||
2815 | setsectorchecksum(buffer, | ||
2816 | 0 /* startoffset */, | ||
2817 | sectornum /* sector */, | ||
2818 | sectorcount /*sectorcount */ | ||
2819 | ); | ||
2820 | this->writesectors(this->devhd24, | ||
2821 | sectornum, | ||
2822 | buffer, | ||
2823 | sectorcount); | ||
2824 | fstfix(buffer,sectorcount*512); | ||
2825 | return RESULT_SUCCESS; | ||
2826 | } | ||
2827 | |||
2828 | __uint32 hd24fs::writedriveusage() | ||
2829 | { | ||
2830 | if (sectors_driveusage!=NULL) | ||
2831 | { | ||
2832 | memutils::myfree("sectors_driveusage",sectors_driveusage); | ||
2833 | sectors_driveusage=NULL; | ||
2834 | } | ||
2835 | |||
2836 | unsigned char* buffer=resetdriveusage(); | ||
2837 | if (buffer==NULL) | ||
2838 | { | ||
2839 | return RESULT_FAIL; | ||
2840 | } | ||
2841 | __uint32 sectornum=5; | ||
2842 | __uint32 sectorcount=15; | ||
2843 | fstfix(buffer,sectorcount*512); | ||
2844 | setsectorchecksum(buffer, | ||
2845 | 0 /* startoffset */, | ||
2846 | sectornum /* sector */, | ||
2847 | sectorcount /*sectorcount */ | ||
2848 | ); | ||
2849 | |||
2850 | this->writesectors(this->devhd24, | ||
2851 | sectornum, | ||
2852 | buffer, | ||
2853 | sectorcount); | ||
2854 | fstfix(buffer,sectorcount*512); | ||
2855 | |||
2856 | return RESULT_SUCCESS; | ||
2857 | } | ||
2858 | |||
2859 | __uint32 hd24fs::quickformat(char* message) | ||
2860 | { | ||
2861 | // This procedure performs a quickformat on the current drive. | ||
2862 | // There is no need for the drive to be a valid HD24 drive | ||
2863 | // for this to work. | ||
2864 | // Safety confirmations etc. are considered to be the | ||
2865 | // responsibility of the caller. | ||
2866 | |||
2867 | gotlastsectornum=false; // force re-finding last sector num | ||
2868 | __uint32 lastsec=getlastsectornum(); | ||
2869 | |||
2870 | formatting=true; | ||
2871 | |||
2872 | if (lastsec==0) | ||
2873 | { | ||
2874 | if (message!=NULL) strcpy(message,(const char*)&"Lastsec=0"); | ||
2875 | return 0; | ||
2876 | } | ||
2877 | __uint32 result=writesuperblock(lastsec); | ||
2878 | |||
2879 | if (result==RESULT_FAIL) | ||
2880 | { | ||
2881 | if (message!=NULL) strcpy(message,(const char*)&"Write superblock failed"); | ||
2882 | return 0; // lastsec 0 means failed format | ||
2883 | } | ||
2884 | |||
2885 | result=writedriveinfo(); | ||
2886 | if (result==RESULT_FAIL) | ||
2887 | { | ||
2888 | if (message!=NULL) strcpy(message,(const char*)&"Write driveinfo failed"); | ||
2889 | return 0; // lastsec 0 means failed format | ||
2890 | } | ||
2891 | |||
2892 | result=writesongusage(); | ||
2893 | if (result==RESULT_FAIL) | ||
2894 | { | ||
2895 | if (message!=NULL) strcpy(message,(const char*)&"Write song usage failed"); | ||
2896 | return 0; // lastsec 0 means failed format | ||
2897 | } | ||
2898 | |||
2899 | result=writedriveusage(); | ||
2900 | if (result==RESULT_FAIL) | ||
2901 | { | ||
2902 | if (message!=NULL) strcpy(message,(const char*)&"Write drive usage failed"); | ||
2903 | return 0; // lastsec 0 means failed format | ||
2904 | } | ||
2905 | |||
2906 | // write empty song-entry usage table | ||
2907 | // write empty drive usage table | ||
2908 | // write 99 empty projects | ||
2909 | // create default project | ||
2910 | // (write 99*99 empty songs) | ||
2911 | // (empty audio space) | ||
2912 | // commit fs | ||
2913 | commit(); | ||
2914 | formatting=false; | ||
2915 | force_reload(); | ||
2916 | return lastsec; | ||
2917 | } | ||
2918 | |||
2919 | void hd24fs::setprojectsectornum(int i,__uint32 sector) | ||
2920 | { | ||
2921 | getsector_diskinfo(); | ||
2922 | Convert::setint32(sector_diskinfo, | ||
2923 | DRIVEINFO_PROJECTLIST + ((i - 1) * 4),sector); | ||
2924 | |||
2925 | return; | ||
2926 | } | ||
2927 | |||
2928 | __uint32 hd24fs::deleteproject(__sint32 projid) | ||
2929 | { | ||
2930 | if (projid<1) | ||
2931 | { | ||
2932 | /* Illegal project id; | ||
2933 | project IDs are set in base 1. */ | ||
2934 | return RESULT_FAIL; | ||
2935 | } | ||
2936 | |||
2937 | getsector_diskinfo(); // has list of pointers to project sectors | ||
2938 | __uint32 pcount = Convert::getint32(sector_diskinfo, DRIVEINFO_PROJECTCOUNT); | ||
2939 | |||
2940 | if (pcount<=1) | ||
2941 | { | ||
2942 | /* Attempt to delete last project on drive- | ||
2943 | not allowed, a drive must always contain | ||
2944 | at least 1 project */ | ||
2945 | return RESULT_FAIL; | ||
2946 | } | ||
2947 | |||
2948 | hd24project* projtodel=this->getproject(projid); | ||
2949 | if (projtodel==NULL) { | ||
2950 | return RESULT_FAIL; | ||
2951 | } | ||
2952 | |||
2953 | /* If there still all songs in the project, delete them */ | ||
2954 | __uint32 currsongcount=projtodel->songcount(); | ||
2955 | if (currsongcount>0) | ||
2956 | { | ||
2957 | for (__uint32 j=1; j<=currsongcount;j++) | ||
2958 | { | ||
2959 | projtodel->deletesong(1); // songs will shift | ||
2960 | projtodel->save(); | ||
2961 | } | ||
2962 | } | ||
2963 | |||
2964 | /* delete project from project list by shifting left | ||
2965 | all other projects... */ | ||
2966 | if (projid<99) | ||
2967 | { | ||
2968 | /* When project 99 is deleted no shifting is needed */ | ||
2969 | for (__uint32 i=projid;i<99;i++) | ||
2970 | { | ||
2971 | setprojectsectornum(i,getprojectsectornum(i+1)); | ||
2972 | } | ||
2973 | } | ||
2974 | |||
2975 | setprojectsectornum(99,0); // ...and clearing the last entry. | ||
2976 | |||
2977 | Convert::setint32(sector_diskinfo,DRIVEINFO_PROJECTCOUNT,pcount-1); | ||
2978 | |||
2979 | /* Set 'last accessed project' to first in list | ||
2980 | (the project being deleted needs to be accessed | ||
2981 | prior to deletion so this must always be updated) | ||
2982 | */ | ||
2983 | Convert::setint32(sector_diskinfo, DRIVEINFO_LASTPROJECT,getprojectsectornum(1)); | ||
2984 | #if (HD24FSDEBUG==1) | ||
2985 | cout << "save project." << endl; | ||
2986 | #endif | ||
2987 | |||
2988 | savedriveinfo(); | ||
2989 | delete projtodel; | ||
2990 | return RESULT_SUCCESS; | ||
2991 | } | ||
2992 | |||
2993 | void hd24fs::write_enable() | ||
2994 | { | ||
2995 | this->writeprotected=false; | ||
2996 | } | ||
2997 | |||
2998 | void hd24fs::write_disable() | ||
2999 | { | ||
3000 | this->writeprotected=true; | ||
3001 | } | ||
3002 | |||
diff --git a/src/lib/hd24fs.h b/src/lib/hd24fs.h new file mode 100755 index 0000000..b91d4c1 --- /dev/null +++ b/src/lib/hd24fs.h | |||
@@ -0,0 +1,432 @@ | |||
1 | #ifndef __hd24fs_h__ | ||
2 | #define __hd24fs_h__ | ||
3 | |||
4 | #include <config.h> | ||
5 | #include <stdio.h> | ||
6 | #include <string> | ||
7 | #include <hd24utils.h> | ||
8 | #include "memutils.h" | ||
9 | #include "convertlib.h" | ||
10 | #define CLUSTER_UNDEFINED (0xFFFFFFFF) | ||
11 | |||
12 | #if defined(LINUX) || defined(DARWIN) | ||
13 | # define FSHANDLE int | ||
14 | # define FSHANDLE_INVALID -1 | ||
15 | #endif | ||
16 | |||
17 | #ifdef WINDOWS | ||
18 | # include <windows.h> | ||
19 | # include <winioctl.h> | ||
20 | # define FSHANDLE HANDLE | ||
21 | # define FSHANDLE_INVALID INVALID_HANDLE_VALUE | ||
22 | #endif | ||
23 | |||
24 | using namespace std; | ||
25 | |||
26 | class hd24fs; | ||
27 | class hd24project; | ||
28 | class hd24raw; | ||
29 | class hd24song; | ||
30 | |||
31 | class AudioStorage | ||
32 | { | ||
33 | public: | ||
34 | virtual __uint32 samplerate() { return 0; }; | ||
35 | virtual void currentlocation(__uint32 newpos) { return; }; | ||
36 | virtual __uint32 currentlocation() { return 0; }; | ||
37 | virtual __uint32 getlocatepos(int locatepoint) { return 0; }; | ||
38 | virtual __uint32 setlocatepos(int locatepoint,__uint32 newpos) { return 0; }; | ||
39 | virtual bool trackarmed(__uint32 base1tracknum) { return false; } | ||
40 | virtual void trackarmed(__uint32 base1tracknum,bool arm) { return; } | ||
41 | virtual ~AudioStorage() { return; } ; | ||
42 | }; | ||
43 | |||
44 | class hd24song : public AudioStorage | ||
45 | { | ||
46 | friend class hd24project; | ||
47 | friend class hd24fs; | ||
48 | friend class hd24transferjob; | ||
49 | friend class hd24transferengine; | ||
50 | private: | ||
51 | __uint32 framespersec; | ||
52 | unsigned char* buffer; // for songinfo | ||
53 | unsigned char* audiobuffer; // for audio data | ||
54 | unsigned char* scratchbook; // for write-back audio data | ||
55 | __uint32* blocksector; | ||
56 | int evenodd; /* specifies if we are dealing with | ||
57 | even or odd samples in high speed mode. */ | ||
58 | bool lengthened; /* Indicate if reallocating song length change occured */ | ||
59 | bool busyrecording; | ||
60 | int mysongid; | ||
61 | int polling; | ||
62 | int currentreadmode; | ||
63 | int currcachebufnum; | ||
64 | bool rehearsemode; | ||
65 | bool lastallocentrynum; | ||
66 | hd24fs* parentfs; | ||
67 | unsigned char** cachebuf_ptr; | ||
68 | __uint32* cachebuf_blocknum; | ||
69 | hd24project* parentproject; | ||
70 | hd24song(hd24project* p_parent,__uint32 p_songid); | ||
71 | unsigned char* getcachedbuffer(long unsigned int); | ||
72 | void queuecacheblock(__uint32 blocknum); | ||
73 | void loadblockintocache(__uint32 blocknum); | ||
74 | void setblockcursor(__uint32 blocknum); | ||
75 | void memoizeblocksectors(__uint32 lastblock); | ||
76 | __uint32 memblocksector(__uint32 blocknum); | ||
77 | __uint32 blocktoqueue; // next block to cache | ||
78 | __uint32 songcursor; // current cursor pos within song, in samples | ||
79 | __uint32 allocentrynum; // which allocation entry is currently being used | ||
80 | __uint32 allocstartblock; // the first audioblock in given entry | ||
81 | __uint32 allocstartsector; // the sector pointed to by that entry | ||
82 | __uint32 allocaudioblocks; // the number of audioblocks in the block | ||
83 | __uint32 divider; | ||
84 | __uint32 lastreadblock; | ||
85 | __uint32 lastavailablecacheblock; | ||
86 | __uint32 mustreadblock; | ||
87 | __uint32 track_armed[24]; | ||
88 | __uint32 track_readenabled[24]; // used to speed up copy mode. | ||
89 | void unmark_used_clusters(unsigned char* sectors_orphan); | ||
90 | __uint32 used_alloctable_entries(); | ||
91 | __uint32 audioblocks_in_alloctable(); | ||
92 | void silenceaudioblocks(__uint32 allocsector,__uint32 blocks); | ||
93 | bool allocatenewblocks(long unsigned int, bool, char*, int*, int (*)()); | ||
94 | |||
95 | public: | ||
96 | ~hd24song(); | ||
97 | string* songname(); | ||
98 | __uint32 songid(); | ||
99 | hd24fs* fs(); | ||
100 | static void sectorinit(unsigned char* sectorbuf); | ||
101 | static void settrackcount(unsigned char* sectorbuf,__uint32 trackcount); | ||
102 | static void songname(unsigned char* sectorbuf,string newname); | ||
103 | void songname(string newname); | ||
104 | static string* songname(hd24fs* parentfs,unsigned char* sectorbuf); | ||
105 | void bufferpoll(); | ||
106 | |||
107 | void readenabletrack(__uint32 tracknum); | ||
108 | void readenabletrack(__uint32 tracknum,bool enable); | ||
109 | |||
110 | bool isrehearsemode(); | ||
111 | void setrehearsemode(bool p_rehearsemode); | ||
112 | bool recording(); | ||
113 | |||
114 | bool trackarmed(__uint32 tracknum); | ||
115 | void trackarmed(__uint32 tracknum,bool arm); | ||
116 | |||
117 | bool istrackmonitoringinput(__uint32 tracknum); | ||
118 | void startrecord(int record_mode); | ||
119 | void stoprecord(); | ||
120 | __uint32 samplerate(); | ||
121 | static void samplerate(unsigned char* sectorbuf,__uint32 samplerate); | ||
122 | void samplerate(__uint32 newrate); | ||
123 | static __uint32 samplerate(unsigned char* songbuf); | ||
124 | __uint32 bitdepth(); | ||
125 | __uint32 physical_channels(); | ||
126 | static __uint32 physical_channels(unsigned char* songbuf); | ||
127 | void physical_channels(__uint32 newchannelcount); | ||
128 | static void physical_channels(unsigned char* songbuf,__uint32 newchannelcount); | ||
129 | __uint32 logical_channels(); | ||
130 | static __uint32 logical_channels(unsigned char* songbuf); | ||
131 | void logical_channels(__uint32 newchannelcount); | ||
132 | static void logical_channels(unsigned char* songbuf,__uint32 channelcount); | ||
133 | __uint32 songlength_in_samples(); | ||
134 | __uint32 songlength_in_samples(__uint32 newlen); | ||
135 | __uint32 songlength_in_samples(__uint32 newlen,bool silence); | ||
136 | __uint32 songlength_in_samples(__uint32 newlen,bool silence,char* savemessage,int* cancel); | ||
137 | __uint32 songlength_in_samples(__uint32 newlen,bool silence,char* savemessage,int* cancel,int (*checkfunc)()); | ||
138 | |||
139 | __uint32 display_hours(); | ||
140 | __uint32 display_hours(__uint32 offset); | ||
141 | static __uint32 display_hours(__uint32 offset,__uint32 samrate); | ||
142 | |||
143 | __uint32 display_minutes(); | ||
144 | __uint32 display_minutes(__uint32 offset); | ||
145 | static __uint32 display_minutes(__uint32 offset,__uint32 samrate); | ||
146 | |||
147 | __uint32 display_seconds(); | ||
148 | __uint32 display_seconds(__uint32 offset); | ||
149 | static __uint32 display_seconds(__uint32 offset,__uint32 samrate); | ||
150 | |||
151 | __uint32 display_subseconds(); | ||
152 | __uint32 display_subseconds(__uint32 offset); | ||
153 | static __uint32 display_subseconds(__uint32 offset,__uint32 samrate); | ||
154 | |||
155 | string* display_duration(); | ||
156 | string* display_duration(__uint32 offset); | ||
157 | string* display_duration(__uint32 offset,__uint32 samrate); | ||
158 | |||
159 | string* display_cursor(); | ||
160 | __uint32 cursorpos(); | ||
161 | __uint32 locatepointcount(); | ||
162 | __uint32 getlocatepos(int locatepoint); | ||
163 | |||
164 | __uint32 currentlocation(); | ||
165 | void currentlocation(__uint32 offset); | ||
166 | __uint32 golocatepos(__uint32 offset); | ||
167 | |||
168 | __uint32 setlocatepos(int locatepoint,__uint32 offset); | ||
169 | void setlocatename(int locatepoint,string newname); | ||
170 | string* getlocatename(int locatepoint); | ||
171 | bool iswriteprotected(); | ||
172 | void setwriteprotected(bool prot); | ||
173 | void getmultitracksample(long* mtsample,int readmode); | ||
174 | int getmtrackaudiodata(__uint32 firstsamnum,__uint32 samples,unsigned char* buffer,int readmode); | ||
175 | int putmtrackaudiodata(__uint32 firstsamnum,__uint32 samples,unsigned char* buffer,int writemode); | ||
176 | void deinterlaceblock(unsigned char* buffer,unsigned char* targetbuffer); | ||
177 | void interlaceblock(unsigned char* buffer,unsigned char* targetbuffer); | ||
178 | static const int LOCATEPOS_SONGSTART; | ||
179 | static const int LOCATEPOS_LOOPSTART; | ||
180 | static const int LOCATEPOS_LOOPEND; | ||
181 | static const int LOCATEPOS_PUNCHIN; | ||
182 | static const int LOCATEPOS_PUNCHOUT; | ||
183 | static const int LOCATEPOS_EDITIN; | ||
184 | static const int LOCATEPOS_EDITOUT; | ||
185 | static const int LOCATEPOS_LAST; | ||
186 | static const int READMODE_COPY; | ||
187 | static const int READMODE_REALTIME; | ||
188 | static const int WRITEMODE_COPY; | ||
189 | static const int WRITEMODE_REALTIME; | ||
190 | |||
191 | __uint32 getnextfreesector(__uint32 allocsector); | ||
192 | bool has_unexpected_end(); // indicates if there is an 'unexpected end of song' error | ||
193 | bool is_fixable_unexpected_end(); // ...and if so, if we know how to fix it. | ||
194 | bool setallocinfo(bool silencenew); | ||
195 | bool setallocinfo(bool silencenew,char* message,int* cancel,int (*checkfunc)()); | ||
196 | __uint32 requiredaudioblocks(__uint32 songlen); | ||
197 | void appendorphanclusters(unsigned char*,bool allowsongresize); | ||
198 | void save(); | ||
199 | }; | ||
200 | |||
201 | class hd24project | ||
202 | { | ||
203 | friend class hd24fs; | ||
204 | friend class hd24song; | ||
205 | |||
206 | private: | ||
207 | unsigned char* buffer; | ||
208 | hd24fs* parentfs; | ||
209 | __sint32 myprojectid; | ||
210 | hd24song* songlist; | ||
211 | hd24project(hd24fs* p_parent,__sint32 projectid); | ||
212 | hd24project(hd24fs* p_parent,__sint32 projectid,__uint32 projsector,const char* projectname,bool isnew); | ||
213 | __uint32 getsongsectornum(int i); | ||
214 | void setsongsectornum(int i,__uint32 newsector); | ||
215 | void save(__uint32 projsector); | ||
216 | void populatesongusagetable(unsigned char* songused); | ||
217 | __uint32 getunusedsongslot(); | ||
218 | void initvars(hd24fs* p_parent,__sint32 p_projectid); | ||
219 | public: | ||
220 | ~hd24project(); | ||
221 | string* projectname(); | ||
222 | void projectname(string newname); | ||
223 | __sint32 lastsongid(); | ||
224 | void lastsongid(signed long songid); | ||
225 | __uint32 songcount(); | ||
226 | __uint32 maxsongs(); | ||
227 | __sint32 projectid(); | ||
228 | hd24song* getsong(__uint32 songid); | ||
229 | hd24song* createsong(const char* songname,__uint32 trackcount,__uint32 samplerate); | ||
230 | __uint32 deletesong(__uint32 songid); | ||
231 | void save(); | ||
232 | void sort(); | ||
233 | }; | ||
234 | |||
235 | class hd24fs | ||
236 | { | ||
237 | friend class hd24project; | ||
238 | friend class hd24song; | ||
239 | friend class hd24raw; | ||
240 | friend class hd24utils; | ||
241 | |||
242 | private: | ||
243 | const char* imagedir; | ||
244 | int transportstatus; | ||
245 | bool writeprotected; | ||
246 | bool allinput; | ||
247 | bool autoinput; | ||
248 | bool forcemode; | ||
249 | bool formatting; // true during a format operation | ||
250 | bool headermode; | ||
251 | bool maintenancemode; | ||
252 | bool wavefixmode; | ||
253 | __uint32 highestFSsectorwritten; | ||
254 | |||
255 | __uint32 nextfreeclusterword; // memoization cache for write allocation | ||
256 | |||
257 | FSHANDLE devhd24; // device handle | ||
258 | FSHANDLE hd24header; // header device handle | ||
259 | bool m_isOpen; | ||
260 | bool gotlastsectornum; | ||
261 | __uint32 foundlastsectornum; | ||
262 | int p_mode; | ||
263 | hd24project* projlist; | ||
264 | string* devicename; | ||
265 | unsigned char* sector_boot; | ||
266 | unsigned char* sector_diskinfo; | ||
267 | unsigned char* sectors_driveusage; | ||
268 | unsigned char* sectors_orphan; | ||
269 | unsigned char* sectors_songusage; | ||
270 | long readsectors(FSHANDLE handle, __uint32 secnum, unsigned char* buffer,int sectors); | ||
271 | long readsector(FSHANDLE handle, __uint32 secnum, unsigned char* buffer); | ||
272 | long readsector_noheader(FSHANDLE handle, __uint32 secnum, unsigned char* buffer); | ||
273 | long readsector_noheader(hd24fs* currenthd24, __uint32 secnum, unsigned char* buffer); | ||
274 | long writesectors(FSHANDLE handle, __uint32 secnum, unsigned char* buffer,int sectors); | ||
275 | long writesector(FSHANDLE handle, __uint32 secnum, unsigned char* buffer); | ||
276 | |||
277 | string* gethd24currentdir(int, char**); | ||
278 | void hd24close(); | ||
279 | void hd24closedevice(FSHANDLE handle); | ||
280 | static void hd24seek(FSHANDLE handle,__uint64 seekpos); | ||
281 | void clearbuffer(unsigned char* buffer); | ||
282 | void clearbuffer(unsigned char* buffer,unsigned int bytes); | ||
283 | FSHANDLE findhd24device(); | ||
284 | FSHANDLE findhd24device(int mode); | ||
285 | FSHANDLE findhd24device(int mode, int base0devnum); | ||
286 | FSHANDLE findhd24device(int mode, string* dev,bool force,bool tryharder); | ||
287 | static bool isinvalidhandle(FSHANDLE handle); | ||
288 | unsigned char* readbootinfo(); | ||
289 | unsigned char* readdiskinfo(); | ||
290 | unsigned char* readdriveusageinfo(); | ||
291 | unsigned char* resetsongusage(); | ||
292 | unsigned char* resetdriveusage(); | ||
293 | unsigned char* calcsongusage(); | ||
294 | void refreshsongusage(); | ||
295 | unsigned char* getsector_bootinfo(); | ||
296 | unsigned char* getsector_diskinfo(); | ||
297 | unsigned char* getsectors_driveusage(); | ||
298 | unsigned char* getcopyofusagetable(); // allocates memory and fills it up with a copy of the current usage table | ||
299 | void initvars(); | ||
300 | __uint32 driveusagesectorcount(); | ||
301 | __uint32 clustercount(); | ||
302 | __uint32 driveusagefirstsector(); | ||
303 | __uint32 getblockspercluster(); | ||
304 | __uint32 getprojectsectornum(__uint32 base1proj); | ||
305 | bool isfreecluster(__uint32 clusternum); | ||
306 | bool isfreecluster(__uint32 clusternum,unsigned char* usagebuffer); | ||
307 | __uint32 freeclustercount(); | ||
308 | __uint32 getlastsectornum(); | ||
309 | __uint32 getlastsectornum(FSHANDLE handle); | ||
310 | __uint32 headersectors; | ||
311 | void writebackupblock(__uint32 sector,__uint32 blocksize, | ||
312 | __uint32 lastsec,bool fullcommit); | ||
313 | __uint32 getnextfreesectorword(); | ||
314 | __uint32 getnextfreeclusterword(); | ||
315 | __uint32 getnextfreesector(__uint32 cluster); | ||
316 | void enablebit(__uint32 ibit,unsigned char* usagebuffer); | ||
317 | void disablebit(__uint32 ibit,unsigned char* usagebuffer); | ||
318 | bool isbitzero(__uint32 ibit,unsigned char* usagebuffer); | ||
319 | long unsigned int songentry2songsector(long unsigned int entry); | ||
320 | long unsigned int songsector2songentry(long unsigned int entry); | ||
321 | void allocsongentry(__uint32 entrynum); | ||
322 | void allocatecluster(__uint32 clusternum); | ||
323 | void allocatecluster(__uint32 clusternum,unsigned char* usagebuffer); | ||
324 | void freecluster(__uint32 clusternum); | ||
325 | void freecluster(__uint32 clusternum,unsigned char* usagebuffer); | ||
326 | signed long nextunusedsongentry(); | ||
327 | void useinternalboot(unsigned char*, long unsigned int); | ||
328 | __uint32 getunusedsongsector(); | ||
329 | __uint32 songsondisk(); | ||
330 | void songsondisk(__uint32 songsondisk); | ||
331 | void setprojectsectornum(int i,__uint32 newsector); | ||
332 | void setimagedir(const char* newdir); | ||
333 | int deviceid; | ||
334 | public: | ||
335 | __uint32 lasterror; | ||
336 | void force_reload(); | ||
337 | static void setname(unsigned char* namebuf,string newname,__uint32 shortnameoff,__uint32 longnameoff); | ||
338 | void dumpclusterusage(); | ||
339 | void dumpclusterusage(unsigned char* buffer); | ||
340 | void dumpclusterusage2(); | ||
341 | void dumpclusterusage2(unsigned char* buffer); | ||
342 | unsigned char* findorphanclusters(); | ||
343 | static const int TRANSPORTSTATUS_PLAY; | ||
344 | static const int TRANSPORTSTATUS_STOP; | ||
345 | static const int TRANSPORTSTATUS_REC; | ||
346 | __uint32 cluster2sector(__uint32 clusternum); | ||
347 | __uint32 sector2cluster(__uint32 sectornum); | ||
348 | __uint32 songentry2sector(__uint32 entrynum); | ||
349 | __uint32 songsector2entry(__uint32 sectornum); | ||
350 | void settransportstatus(int newstatus); | ||
351 | int gettransportstatus(); | ||
352 | bool isallinput(); | ||
353 | void setallinput(bool p_allinput); | ||
354 | void setallinput(void); | ||
355 | bool isautoinput(); | ||
356 | void setautoinput(bool p_autoinput); | ||
357 | void setautoinput(void); | ||
358 | |||
359 | hd24fs(const char* imagedir); | ||
360 | hd24fs(const char* imagedir,int mode); | ||
361 | hd24fs(const char* imagedir,int mode,int base0devnum); | ||
362 | hd24fs(const char* imagedir,int mode,string* dev,bool force); | ||
363 | ~hd24fs(); | ||
364 | __uint32 getblocksizeinsectors(); | ||
365 | __uint32 getbytesperaudioblock(); | ||
366 | static void fstfix(unsigned char* bootblock,int fixsize); | ||
367 | bool isOpen(); | ||
368 | int mode(); | ||
369 | string* volumename(); | ||
370 | string* getdevicename(); | ||
371 | int getdeviceid(); | ||
372 | void setdevicename(const char* orig,string* newname); | ||
373 | void setvolumename(string newname); | ||
374 | string* version(); | ||
375 | __uint32 hd24devicecount(); | ||
376 | __sint32 lastprojectid(); | ||
377 | void lastprojectid(signed long projectid); | ||
378 | __uint32 projectcount(); | ||
379 | __uint32 maxprojects(); | ||
380 | __uint32 maxsongsperproject(); | ||
381 | hd24project* getproject(__sint32 projectid); | ||
382 | hd24project* createproject(const char* projectname); | ||
383 | void setmaintenancemode(int mode); | ||
384 | int getmaintenancemode(); | ||
385 | void setwavefixmode(int mode); | ||
386 | int getwavefixmode(); | ||
387 | string* gethd24currentdir(); | ||
388 | static const int MODE_RDONLY; | ||
389 | static const int MODE_RDWR; | ||
390 | string* freespace(__uint32 rate,__uint32 tracks); | ||
391 | bool useheaderfile(string headerfilename); | ||
392 | bool isexistingdevice(string *devname); | ||
393 | bool commit(bool fullcommit); | ||
394 | bool commit(); | ||
395 | long unsigned int setsectorchecksum(unsigned char* buffer,unsigned int startoffset,unsigned int startsector,unsigned int sectors); | ||
396 | void savedriveinfo(); | ||
397 | void savedriveusage(); | ||
398 | __uint32 writesuperblock(__uint32 lastsectornum); | ||
399 | void cleardriveinfo(unsigned char* buffer); | ||
400 | __uint32 writedriveinfo(); | ||
401 | __uint32 writesongusage(); | ||
402 | __uint32 writedriveusage(); | ||
403 | __uint32 quickformat(char* lasterror); | ||
404 | __uint32 deleteproject(__sint32 projid); | ||
405 | void write_enable(); | ||
406 | void write_disable(); | ||
407 | }; | ||
408 | |||
409 | /* Provides sector level access to hd24 disks | ||
410 | * (functionality which is private in hd24fs) | ||
411 | */ | ||
412 | class hd24raw | ||
413 | { | ||
414 | friend class hd24fs; | ||
415 | |||
416 | private: | ||
417 | hd24fs* fsys; | ||
418 | |||
419 | public: | ||
420 | hd24raw(hd24fs* fsys); | ||
421 | hd24raw(hd24fs* fsys,bool notranslate); | ||
422 | ~hd24raw() {}; | ||
423 | long readsectors(__uint32 secnum, unsigned char* buffer,int sectors); | ||
424 | long writesectors(__uint32 secnum, unsigned char* buffer,int sectors); | ||
425 | __uint32 getnextfreesector(__uint32 cluster); | ||
426 | __uint32 getprojectsectornum(__uint32 projectid); | ||
427 | __uint32 getlastsectornum(); | ||
428 | __uint32 songsondisk(); | ||
429 | __uint32 quickformat(char* lasterror); | ||
430 | }; | ||
431 | |||
432 | #endif | ||
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 | } | ||
diff --git a/src/lib/hd24sndfile.cpp b/src/lib/hd24sndfile.cpp new file mode 100644 index 0000000..470a465 --- /dev/null +++ b/src/lib/hd24sndfile.cpp | |||
@@ -0,0 +1,270 @@ | |||
1 | #include "hd24sndfile.h" | ||
2 | #include <sndfile.h> | ||
3 | #include <fstream> | ||
4 | #include <iostream> | ||
5 | #include <convertlib.h> | ||
6 | using std::ofstream; | ||
7 | using std::cout; | ||
8 | using std::endl; | ||
9 | hd24sndfile::hd24sndfile(int p_format,SoundFileWrapper* p_soundfile) | ||
10 | { | ||
11 | sndfilehandle=(SNDFILE*)NULL; | ||
12 | outfilehandle=(ofstream*)NULL; | ||
13 | _handletype=0; // default is 0=libsndfile, 1=native file | ||
14 | sf_format=p_format; | ||
15 | soundfile=p_soundfile; | ||
16 | } | ||
17 | |||
18 | hd24sndfile::~hd24sndfile() | ||
19 | { | ||
20 | //if (sndfilehandle!=NULL) | ||
21 | //{ | ||
22 | // delete sndfilehandle; | ||
23 | //} | ||
24 | //if (outfilehandle!=NULL) | ||
25 | //{ | ||
26 | // /delete outfilehandle; | ||
27 | //} | ||
28 | } | ||
29 | |||
30 | int hd24sndfile::handletype() | ||
31 | { | ||
32 | return _handletype; | ||
33 | } | ||
34 | |||
35 | void* hd24sndfile::handle() | ||
36 | { | ||
37 | if (_handletype==0) | ||
38 | { | ||
39 | return (void*)sndfilehandle; | ||
40 | } | ||
41 | return (void*)outfilehandle; | ||
42 | } | ||
43 | |||
44 | void hd24sndfile::handle(SNDFILE* newhandle) | ||
45 | { | ||
46 | sndfilehandle=newhandle; | ||
47 | _handletype=0; | ||
48 | } | ||
49 | |||
50 | void hd24sndfile::handle(ofstream* newhandle) | ||
51 | { | ||
52 | outfilehandle=newhandle; | ||
53 | |||
54 | _handletype=1; | ||
55 | // TODO: Write empty header (for filling in later) | ||
56 | } | ||
57 | |||
58 | void hd24sndfile::handle(void* newhandle,int htype) | ||
59 | { | ||
60 | _handletype=htype; | ||
61 | if (htype==1) { | ||
62 | outfilehandle=(ofstream*)newhandle; | ||
63 | return; | ||
64 | } | ||
65 | |||
66 | sndfilehandle=(SNDFILE*)newhandle; | ||
67 | } | ||
68 | |||
69 | void hd24sndfile::open(const char* filename,int filemode,SF_INFO* infoblock,SoundFileWrapper* _soundfile) | ||
70 | { | ||
71 | _handletype=0; // soundfile | ||
72 | soundfile=_soundfile; | ||
73 | sfinfo=infoblock; | ||
74 | sndfilehandle=soundfile->sf_open(filename,filemode,infoblock); | ||
75 | outfilehandle=NULL; | ||
76 | |||
77 | if (!sndfilehandle) | ||
78 | { | ||
79 | cout << "Problem opening file with the following specs: " << endl; | ||
80 | cout << "rate=" << infoblock->samplerate << endl; | ||
81 | cout << "frames=" << infoblock->frames << endl; | ||
82 | cout << "channels=" << infoblock->channels << endl; | ||
83 | cout << "sections=" << infoblock->sections << endl; | ||
84 | cout << "seekable=" << infoblock->seekable << endl; | ||
85 | cout << "format=" << infoblock->format << endl; | ||
86 | } | ||
87 | } | ||
88 | |||
89 | void hd24sndfile::open(const char* filename,int filemode,SF_INFO* infoblock) | ||
90 | { | ||
91 | _handletype=1; // iostream | ||
92 | sfinfo=infoblock; | ||
93 | sndfilehandle=NULL; | ||
94 | outfilehandle=new ofstream(filename,ios_base::out|ios_base::trunc|ios_base::binary); | ||
95 | |||
96 | if ((sf_format & 0xFF0000) ==SF_FORMAT_WAV) | ||
97 | { | ||
98 | char buf[44]={ | ||
99 | 'R','I','F','F', 0,0,0,0, 'W','A','V','E', 'f','m','t',' ', | ||
100 | 16,0,0,0, 1,0,1,0, 0,0,0,0, 0,0,0,0, | ||
101 | 3,0,24,0, 'd','a','t','a', 0,0,0,0 | ||
102 | }; | ||
103 | |||
104 | // samplerate follows | ||
105 | long rate=sfinfo->samplerate; // FIXME: Get proper rate from sfinfo | ||
106 | buf[24]=(char)((rate)%256); | ||
107 | buf[25]=(char)(((rate)>>8)%256); | ||
108 | buf[26]=(char)(((rate)>>16)%256); | ||
109 | buf[27]=(char)(((rate)>>24)%256); | ||
110 | |||
111 | rate*=3; | ||
112 | buf[28]=(char)((rate)%256); | ||
113 | buf[29]=(char)(((rate)>>8)%256); | ||
114 | buf[30]=(char)(((rate)>>16)%256); | ||
115 | buf[31]=(char)(((rate)>>24)%256); | ||
116 | |||
117 | outfilehandle->write(buf,44); | ||
118 | return; | ||
119 | |||
120 | } | ||
121 | |||
122 | if ((sf_format & 0xFF0000) ==SF_FORMAT_AIFF) | ||
123 | { | ||
124 | char buf[54]={ | ||
125 | 'F','O','R','M', | ||
126 | 0,0,0,0, /* Bytes that follow in this file */ | ||
127 | 'A','I','F','F', 'C','O','M','M', | ||
128 | 0,0,0,18, /* chunksize */ | ||
129 | 0,1, /*numchannels*/ | ||
130 | 0,0,0,0, /*sampleframes */ | ||
131 | 0,24, /* Samplesize in bits */ | ||
132 | 0,0,0,0,0,0,0,0,0,0, /* sample rate as 80 bit IEEE float */ | ||
133 | 'S','S','N','D', | ||
134 | 0,0,0,0, /* sound block datalen, to be filled afterwards */ | ||
135 | 0,0,0,0, /* offset */ | ||
136 | 0,0,0,0 /* blocksize */ /* -> data follows */ | ||
137 | }; | ||
138 | |||
139 | // samplerate follows | ||
140 | long rate=sfinfo->samplerate; // FIXME: Get proper rate from sfinfo | ||
141 | Convert::setfloat80((unsigned char*)buf,28,rate); | ||
142 | |||
143 | outfilehandle->write(buf,54); | ||
144 | return; | ||
145 | |||
146 | } | ||
147 | } | ||
148 | void hd24sndfile::writerawbuf(unsigned char* buf,__uint32 subblockbytes) | ||
149 | { | ||
150 | if ((sf_format & 0xFF0000) ==SF_FORMAT_AIFF) | ||
151 | { | ||
152 | // and we're doing 24 bits. | ||
153 | for (__uint32 i=0;i<subblockbytes;i+=3) | ||
154 | { | ||
155 | char a=buf[i]; | ||
156 | buf[i]=buf[i+2]; | ||
157 | buf[i+2]=a; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | // maybe we want to do 24->16 bit conversion here | ||
162 | |||
163 | if (sndfilehandle != NULL) | ||
164 | { | ||
165 | #if (HD24DEBUG==1) | ||
166 | cout << "soundfile=" << soundfile <<endl; | ||
167 | #endif | ||
168 | #if (HD24DEBUG==1) | ||
169 | cout << "soundfile->sf_write_raw(sndfilehandle,buf,subblockbytes);" << endl; | ||
170 | #endif | ||
171 | soundfile->sf_write_raw(sndfilehandle,buf,subblockbytes); | ||
172 | return; | ||
173 | } | ||
174 | if (outfilehandle!=NULL) | ||
175 | { | ||
176 | outfilehandle->write((const char*)buf,subblockbytes); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | void hd24sndfile::close() | ||
181 | { | ||
182 | if (sndfilehandle != NULL) | ||
183 | { | ||
184 | soundfile->sf_close(sndfilehandle); | ||
185 | return; | ||
186 | } | ||
187 | if (outfilehandle == NULL) return; | ||
188 | |||
189 | |||
190 | switch (sf_format & 0xFF0000) | ||
191 | { | ||
192 | case SF_FORMAT_WAV: | ||
193 | { | ||
194 | // TODO: set sample rate, len, etc. in header | ||
195 | long pos=outfilehandle->tellp(); | ||
196 | char bufword[4]; | ||
197 | bufword[0]=(char)((pos-8)%256); | ||
198 | bufword[1]=(char)(((pos-8)>>8)%256); | ||
199 | bufword[2]=(char)(((pos-8)>>16)%256); | ||
200 | bufword[3]=(char)(((pos-8)>>24)%256); | ||
201 | outfilehandle->seekp(4); | ||
202 | outfilehandle->write(bufword,4); | ||
203 | |||
204 | bufword[0]=(char)((pos-44)%256); | ||
205 | bufword[1]=(char)(((pos-44)>>8)%256); | ||
206 | bufword[2]=(char)(((pos-44)>>16)%256); | ||
207 | bufword[3]=(char)(((pos-44)>>24)%256); | ||
208 | outfilehandle->seekp(40); | ||
209 | outfilehandle->write(bufword,4); | ||
210 | |||
211 | outfilehandle->close(); | ||
212 | break; | ||
213 | } | ||
214 | case SF_FORMAT_AIFF: | ||
215 | { | ||
216 | long pos=outfilehandle->tellp(); | ||
217 | char bufword[4]; | ||
218 | bufword[3]=(char)((pos-8)%256); | ||
219 | bufword[2]=(char)(((pos-8)>>8)%256); | ||
220 | bufword[1]=(char)(((pos-8)>>16)%256); | ||
221 | bufword[0]=(char)(((pos-8)>>24)%256); | ||
222 | |||
223 | outfilehandle->seekp(4); | ||
224 | outfilehandle->write(bufword,4); | ||
225 | |||
226 | long chunksize=(pos-46); | ||
227 | long sambytes=chunksize-8; | ||
228 | |||
229 | |||
230 | long samframes=sambytes/3; // Bytes per sample. TODO: Not hardcode this | ||
231 | bufword[3]=(char)(samframes%256); | ||
232 | bufword[2]=(char)((samframes>>8)%256); | ||
233 | bufword[1]=(char)((samframes>>16)%256); | ||
234 | bufword[0]=(char)((samframes>>24)%256); | ||
235 | outfilehandle->seekp(22); | ||
236 | outfilehandle->write(bufword,4); | ||
237 | |||
238 | |||
239 | bufword[3]=(char)(chunksize%256); | ||
240 | bufword[2]=(char)((chunksize>>8)%256); | ||
241 | bufword[1]=(char)((chunksize>>16)%256); | ||
242 | bufword[0]=(char)((chunksize>>24)%256); | ||
243 | outfilehandle->seekp(42); | ||
244 | outfilehandle->write(bufword,4); | ||
245 | |||
246 | |||
247 | |||
248 | outfilehandle->close(); | ||
249 | break; | ||
250 | |||
251 | } | ||
252 | default: | ||
253 | { | ||
254 | outfilehandle->close(); | ||
255 | break; | ||
256 | |||
257 | } | ||
258 | } | ||
259 | } | ||
260 | |||
261 | void hd24sndfile::write_float(float* buf,__uint32 frames) | ||
262 | { | ||
263 | if (sndfilehandle != NULL) | ||
264 | { | ||
265 | soundfile->sf_write_float(sndfilehandle,buf,frames); | ||
266 | } | ||
267 | return; | ||
268 | } | ||
269 | |||
270 | |||
diff --git a/src/lib/hd24sndfile.h b/src/lib/hd24sndfile.h new file mode 100644 index 0000000..bd31145 --- /dev/null +++ b/src/lib/hd24sndfile.h | |||
@@ -0,0 +1,37 @@ | |||
1 | #ifndef __hd24sndfile_h__ | ||
2 | #define __hd24sndfile_h__ | ||
3 | class SoundFileWrapper; | ||
4 | #include <config.h> | ||
5 | #include <fstream> | ||
6 | using std::ofstream; | ||
7 | #include <sharedlibs.h> | ||
8 | #include <sndfile.h> | ||
9 | |||
10 | class hd24sndfile | ||
11 | { | ||
12 | private: | ||
13 | |||
14 | SF_INFO* sfinfo; | ||
15 | int _handletype; | ||
16 | SoundFileWrapper* soundfile; /* runtime loading wrapper for libsndfile */ | ||
17 | int sf_format; | ||
18 | public: | ||
19 | SNDFILE* sndfilehandle; | ||
20 | ofstream *outfilehandle; | ||
21 | |||
22 | hd24sndfile(int p_format,SoundFileWrapper* p_soundfile); | ||
23 | ~hd24sndfile(); | ||
24 | int handletype(); | ||
25 | void* handle(); | ||
26 | void handle(SNDFILE* newhandle); | ||
27 | void handle(ofstream* newhandle); | ||
28 | void handle(void* newhandle,int htype); | ||
29 | void open(const char* filename,int filemode,SF_INFO* infoblock, | ||
30 | SoundFileWrapper* _soundfile); | ||
31 | void open(const char* filename,int filemode,SF_INFO* infoblock); | ||
32 | void writerawbuf(unsigned char* buf,__uint32 subblockbytes); | ||
33 | void close(); | ||
34 | void write_float(float* buf,__uint32 frames); | ||
35 | }; | ||
36 | |||
37 | #endif | ||
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 | ||
42 | const int hd24song::LOCATEPOS_SONGSTART =0; | ||
43 | const int hd24song::LOCATEPOS_LOOPSTART =1; | ||
44 | const int hd24song::LOCATEPOS_LOOPEND =2; | ||
45 | const int hd24song::LOCATEPOS_PUNCHIN =21; | ||
46 | const int hd24song::LOCATEPOS_PUNCHOUT =22; | ||
47 | const int hd24song::LOCATEPOS_EDITIN =23; | ||
48 | const int hd24song::LOCATEPOS_EDITOUT =24; | ||
49 | const int hd24song::LOCATEPOS_LAST =24; | ||
50 | const int hd24song::READMODE_COPY =0; | ||
51 | const int hd24song::READMODE_REALTIME =1; | ||
52 | const int hd24song::WRITEMODE_COPY =2; | ||
53 | const int hd24song::WRITEMODE_REALTIME =3; | ||
54 | void 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 | |||
100 | void 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 | |||
138 | string* 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 | |||
150 | void 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 | } | ||
164 | void 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 | |||
204 | bool 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 | |||
231 | bool 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 | |||
298 | bool 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 | |||
432 | void 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 | |||
514 | void 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 | |||
532 | void 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 | } | ||
607 | void 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 | |||
693 | hd24song::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 | |||
828 | bool 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 | |||
851 | bool 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 | |||
936 | hd24song::~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 | |||
981 | void 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 | |||
1001 | string* 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 | |||
1024 | string* hd24song::songname() | ||
1025 | { | ||
1026 | return songname(this->parentfs,buffer); | ||
1027 | } | ||
1028 | |||
1029 | void hd24song::songname(string newname) | ||
1030 | { | ||
1031 | songname(buffer,newname); | ||
1032 | } | ||
1033 | |||
1034 | void hd24song::songname(unsigned char* songbuf,string newname) | ||
1035 | { | ||
1036 | hd24fs::setname(songbuf,newname,SONGINFO_SONGNAME_8,SONGINFO_SONGNAME); | ||
1037 | return; | ||
1038 | } | ||
1039 | |||
1040 | bool 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 | |||
1048 | void 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 | |||
1060 | void 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 | |||
1066 | void 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 | |||
1104 | void 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 | |||
1124 | void 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 | |||
1132 | void 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 | |||
1160 | hd24fs* 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 | |||
1225 | string* hd24song::display_cursor() | ||
1226 | { | ||
1227 | return (display_duration(songcursor)); | ||
1228 | } | ||
1229 | __uint32 hd24song::cursorpos() | ||
1230 | { | ||
1231 | return songcursor; | ||
1232 | } | ||
1233 | |||
1234 | |||
1235 | string* 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 | |||
1267 | string* hd24song::display_duration(__uint32 offset) | ||
1268 | { | ||
1269 | return display_duration(offset,samplerate()); | ||
1270 | } | ||
1271 | |||
1272 | string* 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 | |||
1334 | void 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 | |||
1429 | unsigned 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 | |||
1495 | void 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 | |||
1552 | void 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 | |||
1739 | int 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 | |||
1827 | void 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 | |||
1857 | void 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 | |||
1887 | int 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 | |||
1992 | void hd24song::startrecord(int recordmode) | ||
1993 | { | ||
1994 | // TODO: recordmode to distinguish between realtime and copy mode | ||
1995 | recordmode=recordmode; | ||
1996 | this->busyrecording=true; | ||
1997 | } | ||
1998 | |||
1999 | void hd24song::stoprecord() | ||
2000 | { | ||
2001 | this->busyrecording=false; | ||
2002 | } | ||
2003 | |||
2004 | bool hd24song::recording() | ||
2005 | { | ||
2006 | return (this->busyrecording); | ||
2007 | } | ||
2008 | |||
2009 | |||
2010 | void 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 | |||
2018 | void hd24song::readenabletrack(__uint32 tracknum) | ||
2019 | { | ||
2020 | readenabletrack(tracknum,true); | ||
2021 | } | ||
2022 | |||
2023 | bool hd24song::isrehearsemode() | ||
2024 | { | ||
2025 | return this->rehearsemode; | ||
2026 | } | ||
2027 | |||
2028 | void hd24song::setrehearsemode(bool p_rehearsemode) | ||
2029 | { | ||
2030 | this->rehearsemode=p_rehearsemode; | ||
2031 | return; | ||
2032 | } | ||
2033 | |||
2034 | void 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 | |||
2043 | bool 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 | |||
2050 | bool 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 | |||
2157 | void 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 | } | ||
diff --git a/src/lib/hd24transferengine.cpp b/src/lib/hd24transferengine.cpp new file mode 100644 index 0000000..32db2d8 --- /dev/null +++ b/src/lib/hd24transferengine.cpp | |||
@@ -0,0 +1,2143 @@ | |||
1 | #include "hd24transferengine.h" | ||
2 | #include <config.h> | ||
3 | #include <hd24fs.h> | ||
4 | #include <hd24sndfile.h> | ||
5 | |||
6 | #define HD24TRANSFERDEBUG 0 | ||
7 | #define MAXCHANNELS 24 | ||
8 | #define TRACKACTION_UNDEF -1 | ||
9 | |||
10 | hd24transferjob::hd24transferjob() | ||
11 | { | ||
12 | #if (HD24TRANSFERDEBUG==1) | ||
13 | cout << "hd24transferjob::hd24transferjob();" << endl; | ||
14 | #endif | ||
15 | init_vars(); | ||
16 | } | ||
17 | |||
18 | hd24transferjob::~hd24transferjob() | ||
19 | { | ||
20 | #if (HD24TRANSFERDEBUG==1) | ||
21 | cout << "hd24transferjob::~hd24transferjob();" << endl; | ||
22 | #endif | ||
23 | |||
24 | if (trackselected!=NULL) | ||
25 | { | ||
26 | delete trackselected; | ||
27 | trackselected=NULL; | ||
28 | } | ||
29 | usecustomrate=0; // by default, match export samrate with song rate | ||
30 | if (m_projectdir!=NULL) | ||
31 | { | ||
32 | delete m_projectdir; | ||
33 | m_projectdir=NULL; | ||
34 | } | ||
35 | } | ||
36 | |||
37 | void hd24transferjob::init_vars() | ||
38 | { | ||
39 | #if (HD24TRANSFERDEBUG==1) | ||
40 | cout << "hd24transferjob::init_vars()" << endl; | ||
41 | #endif | ||
42 | this->wantsplit=1; | ||
43 | trackselected=new int[MAXCHANNELS]; | ||
44 | for (int i=0;i<MAXCHANNELS;i++) | ||
45 | { | ||
46 | trackselected[i]=0; | ||
47 | } | ||
48 | m_projectdir=NULL; | ||
49 | llsizelimit=1024*1024*1024; | ||
50 | mixleft=0; | ||
51 | mixright=0; | ||
52 | m_selectedformat=0; | ||
53 | usecustomrate=0; | ||
54 | stamprate=48000; | ||
55 | wantsplit=1; | ||
56 | |||
57 | jobsourcesong=NULL; | ||
58 | jobtargetsong=NULL; | ||
59 | jobsourcefs=NULL; | ||
60 | jobtargetfs=NULL; | ||
61 | have_smpte=false; | ||
62 | |||
63 | m_startoffset=0; | ||
64 | m_endoffset=0; | ||
65 | for (int i=0;i<24;i++) | ||
66 | { | ||
67 | this->filepath[i]=NULL; | ||
68 | this->filehandle[i]=NULL; | ||
69 | this->m_trackaction[i]=TRACKACTION_UNDEF; // undefined trackaction | ||
70 | } | ||
71 | return; | ||
72 | } | ||
73 | |||
74 | void hd24transferjob::trackaction(int base1tracknum,int action) | ||
75 | { | ||
76 | #if (HD24TRANSFERDEBUG==1) | ||
77 | cout << "hd24transferjob::trackaction(base1track=" | ||
78 | << base1tracknum << ", action=" << action << ")" << endl; | ||
79 | #endif | ||
80 | |||
81 | m_trackaction[base1tracknum-1]=action; | ||
82 | } | ||
83 | |||
84 | int hd24transferjob::trackaction(int base1tracknum) | ||
85 | { | ||
86 | #if (HD24TRANSFERDEBUG==1) | ||
87 | cout << "returning hd24transferjob::trackaction(base1track=" | ||
88 | << base1tracknum << ")=" << m_trackaction[base1tracknum-1] | ||
89 | << endl; | ||
90 | #endif | ||
91 | return m_trackaction[base1tracknum-1]; | ||
92 | } | ||
93 | |||
94 | void hd24transferengine::trackaction(int base1tracknum,int action) | ||
95 | { | ||
96 | job->trackaction(base1tracknum,action); | ||
97 | } | ||
98 | |||
99 | int hd24transferengine::trackaction(int base1tracknum) | ||
100 | { | ||
101 | return job->trackaction(base1tracknum); | ||
102 | } | ||
103 | |||
104 | char* hd24transferjob::sourcefilename(int base1tracknum) | ||
105 | { | ||
106 | if (base1tracknum<1) return NULL; | ||
107 | if (base1tracknum>24) return NULL; | ||
108 | return filepath[base1tracknum-1]; | ||
109 | } | ||
110 | |||
111 | void hd24transferjob::sourcefilename(int base1tracknum,const char* filename) | ||
112 | { | ||
113 | /* set nth filename to the given char string */ | ||
114 | if (base1tracknum<1) return; | ||
115 | if (base1tracknum>24) return; | ||
116 | |||
117 | if (filepath[base1tracknum-1]!=NULL) | ||
118 | { | ||
119 | free(filepath[base1tracknum-1]); | ||
120 | } | ||
121 | __uint32 n=strlen(filename); | ||
122 | char* tmpbuf=(char*)malloc(n); | ||
123 | filepath[base1tracknum-1]=tmpbuf; | ||
124 | strncpy(tmpbuf,filename,n+1); | ||
125 | return; | ||
126 | } | ||
127 | |||
128 | void hd24transferengine::sourcefilename(int base1tracknum,const char* filename) | ||
129 | { | ||
130 | job->sourcefilename(base1tracknum,filename); | ||
131 | } | ||
132 | |||
133 | char* hd24transferengine::sourcefilename(int base1tracknum) | ||
134 | { | ||
135 | return job->sourcefilename(base1tracknum); | ||
136 | } | ||
137 | |||
138 | void hd24transferjob::startoffset(__uint32 newoff) | ||
139 | { | ||
140 | m_startoffset=newoff; | ||
141 | } | ||
142 | |||
143 | void hd24transferjob::endoffset(__uint32 newoff) | ||
144 | { | ||
145 | m_endoffset=newoff; | ||
146 | } | ||
147 | |||
148 | __uint32 hd24transferjob::startoffset() | ||
149 | { | ||
150 | return m_startoffset; | ||
151 | } | ||
152 | |||
153 | __uint32 hd24transferjob::endoffset() | ||
154 | { | ||
155 | return m_endoffset; | ||
156 | } | ||
157 | |||
158 | hd24fs* hd24transferjob::sourcefs() | ||
159 | { | ||
160 | return this->jobsourcefs; | ||
161 | } | ||
162 | |||
163 | hd24song* hd24transferjob::sourcesong() | ||
164 | { | ||
165 | return this->jobsourcesong; | ||
166 | } | ||
167 | |||
168 | void hd24transferjob::sourcefs(hd24fs* fs) | ||
169 | { | ||
170 | this->jobsourcefs=fs; | ||
171 | } | ||
172 | |||
173 | void hd24transferjob::sourcesong(hd24song* song) | ||
174 | { | ||
175 | this->jobsourcesong=song; | ||
176 | this->jobsourcefs=jobsourcesong->parentfs; | ||
177 | } | ||
178 | |||
179 | hd24fs* hd24transferjob::targetfs() | ||
180 | { | ||
181 | return this->jobtargetfs; | ||
182 | } | ||
183 | |||
184 | hd24song* hd24transferjob::targetsong() | ||
185 | { | ||
186 | return this->jobtargetsong; | ||
187 | } | ||
188 | |||
189 | void hd24transferjob::targetfs(hd24fs* fs) | ||
190 | { | ||
191 | this->jobtargetfs=fs; | ||
192 | } | ||
193 | |||
194 | void hd24transferjob::targetsong(hd24song* song) | ||
195 | { | ||
196 | this->jobtargetsong=song; | ||
197 | this->jobtargetfs=jobtargetsong->parentfs; | ||
198 | } | ||
199 | |||
200 | void hd24transferjob::projectdir(const char* projdir) | ||
201 | { | ||
202 | #if (HD24TRANSFERDEBUG==1) | ||
203 | cout << "hd24transferjob::projectdir("<<projdir<< ")"<<endl; | ||
204 | #endif | ||
205 | if (m_projectdir!=NULL) | ||
206 | { | ||
207 | delete m_projectdir; | ||
208 | m_projectdir=NULL; | ||
209 | } | ||
210 | m_projectdir=new string(projdir); | ||
211 | return; | ||
212 | } | ||
213 | |||
214 | const char* hd24transferjob::projectdir() | ||
215 | { | ||
216 | #if (HD24TRANSFERDEBUG==1) | ||
217 | cout << "returning hd24transferjob::projectdir()="; | ||
218 | if (m_projectdir==NULL) | ||
219 | { | ||
220 | cout <<" NULL " << endl; | ||
221 | } else { | ||
222 | cout <<*m_projectdir<<endl; | ||
223 | } | ||
224 | #endif | ||
225 | return m_projectdir->c_str(); | ||
226 | } | ||
227 | |||
228 | void hd24transferengine::lasterror(const char* errormessage) | ||
229 | { | ||
230 | if (m_lasterror!=NULL) | ||
231 | { | ||
232 | delete m_lasterror; | ||
233 | } | ||
234 | m_lasterror=new string(errormessage); | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | string* hd24transferengine::lasterror() | ||
239 | { | ||
240 | return m_lasterror; | ||
241 | } | ||
242 | |||
243 | |||
244 | int hd24transferengine::format_outputchannels(int format) | ||
245 | { | ||
246 | return m_format_outputchannels[format]; | ||
247 | } | ||
248 | |||
249 | const char* hd24transferengine::projectdir() | ||
250 | { | ||
251 | cout << "returning hd24transferengine::projectdir()"<<endl; | ||
252 | return job->projectdir(); | ||
253 | } | ||
254 | |||
255 | void hd24transferengine::projectdir(const char* projdir) | ||
256 | { | ||
257 | #if (HD24TRANSFERDEBUG==1) | ||
258 | cout << "hd24transferengine::projectdir("<<projdir<< ")"<<endl; | ||
259 | #endif | ||
260 | job->projectdir(projdir); | ||
261 | return; | ||
262 | } | ||
263 | |||
264 | hd24transferengine::hd24transferengine() | ||
265 | { | ||
266 | #if (HD24TRANSFERDEBUG==1) | ||
267 | cout <<"hd24transferengine::hd24transferengine()" << endl; | ||
268 | #endif | ||
269 | init_vars(); | ||
270 | } | ||
271 | |||
272 | hd24transferengine::~hd24transferengine() | ||
273 | { | ||
274 | #if (HD24TRANSFERDEBUG==1) | ||
275 | cout <<"hd24transferengine::~hd24transferengine()" << endl; | ||
276 | #endif | ||
277 | if (m_lasterror!=NULL) | ||
278 | { | ||
279 | delete m_lasterror; | ||
280 | m_lasterror=NULL; | ||
281 | } | ||
282 | if (job!=NULL) | ||
283 | { | ||
284 | delete job; | ||
285 | job=NULL; | ||
286 | } | ||
287 | } | ||
288 | |||
289 | void hd24transferengine::init_vars() | ||
290 | { | ||
291 | songnum=0; | ||
292 | totsongs=0; | ||
293 | ui=NULL; | ||
294 | totbytestotransfer=0; | ||
295 | totbytestransferred=0; | ||
296 | prefix=0; | ||
297 | transfer_cancel=0; | ||
298 | trackspergroup=0; | ||
299 | transfermixer=NULL; | ||
300 | job=NULL; | ||
301 | m_lasterror=NULL; | ||
302 | job=new hd24transferjob(); | ||
303 | this->uiconfirmfunction=NULL; | ||
304 | this->setstatusfunction=NULL; | ||
305 | soundfile=NULL; | ||
306 | #if (HD24TRANSFERDEBUG==1) | ||
307 | cout << "hd24transferengine::init_vars() - job="<<job<<endl; | ||
308 | #endif | ||
309 | m_format_outputextension=new vector<string>; | ||
310 | m_format_shortdesc=new vector<string>; | ||
311 | populate_formatlist(); | ||
312 | } | ||
313 | |||
314 | void hd24transferengine::populate_formatlist() | ||
315 | { | ||
316 | #if (HD24TRANSFERDEBUG==1) | ||
317 | cout << "hd24transferengine::populate_formatlist()" << endl; | ||
318 | #endif | ||
319 | /* Set up transfer format list */ | ||
320 | formatcount=0; | ||
321 | m_format_shortdesc->push_back("WAV (24 bit), mono"); | ||
322 | m_format_outputformat[formatcount]=SF_FORMAT_WAV|SF_FORMAT_PCM_24|SF_ENDIAN_LITTLE; | ||
323 | m_format_outputchannels[formatcount]=1; // mono | ||
324 | m_format_bitdepth[formatcount]=24; | ||
325 | m_format_sndfile[formatcount]=false; // do not use libsndfile for this file format. | ||
326 | m_format_outputextension->push_back(".wav"); | ||
327 | formatcount++; | ||
328 | |||
329 | m_format_shortdesc->push_back("WAV (24 bit), stereo"); | ||
330 | m_format_outputformat[formatcount]=SF_FORMAT_WAV|SF_FORMAT_PCM_24|SF_ENDIAN_LITTLE; | ||
331 | m_format_outputchannels[formatcount]=2; // stereo | ||
332 | m_format_bitdepth[formatcount]=24; | ||
333 | m_format_sndfile[formatcount]=true; | ||
334 | m_format_outputextension->push_back(".wav"); | ||
335 | formatcount++; | ||
336 | |||
337 | m_format_shortdesc->push_back("WAV (24 bit), multi"); | ||
338 | m_format_outputformat[formatcount]=SF_FORMAT_WAV|SF_FORMAT_PCM_24|SF_ENDIAN_LITTLE; | ||
339 | m_format_outputchannels[formatcount]=0; // multi | ||
340 | m_format_bitdepth[formatcount]=24; | ||
341 | m_format_sndfile[formatcount]=true; | ||
342 | m_format_outputextension->push_back(".wav"); | ||
343 | formatcount++; | ||
344 | |||
345 | m_format_shortdesc->push_back("AIF (24 bit), mono"); | ||
346 | m_format_outputformat[formatcount]=SF_FORMAT_AIFF|SF_FORMAT_PCM_24; | ||
347 | m_format_outputchannels[formatcount]=1; // mono | ||
348 | m_format_bitdepth[formatcount]=24; | ||
349 | m_format_sndfile[formatcount]=false; | ||
350 | m_format_outputextension->push_back(".aif"); | ||
351 | formatcount++; | ||
352 | |||
353 | m_format_shortdesc->push_back("AIF (24 bit), stereo"); | ||
354 | m_format_outputformat[formatcount]=SF_FORMAT_AIFF|SF_FORMAT_PCM_24; | ||
355 | m_format_outputchannels[formatcount]=2; // stereo | ||
356 | m_format_bitdepth[formatcount]=24; | ||
357 | m_format_sndfile[formatcount]=true; | ||
358 | m_format_outputextension->push_back(".aif"); | ||
359 | formatcount++; | ||
360 | |||
361 | m_format_shortdesc->push_back("AIF (24 bit), multi"); | ||
362 | m_format_outputformat[formatcount]=SF_FORMAT_AIFF|SF_FORMAT_PCM_24; | ||
363 | m_format_outputchannels[formatcount]=0; // stereo | ||
364 | m_format_bitdepth[formatcount]=24; | ||
365 | m_format_sndfile[formatcount]=true; | ||
366 | m_format_outputextension->push_back(".aif"); | ||
367 | formatcount++; | ||
368 | selectedformat(0); | ||
369 | } | ||
370 | |||
371 | const char* hd24transferengine::getformatdesc(int formatnum) | ||
372 | { | ||
373 | return ((*m_format_shortdesc)[formatnum]).c_str(); | ||
374 | } | ||
375 | |||
376 | int hd24transferengine::supportedformatcount() | ||
377 | { | ||
378 | return formatcount; | ||
379 | } | ||
380 | |||
381 | void hd24transferengine::trackselected(__uint32 base0tracknum,bool selected) | ||
382 | { | ||
383 | if (base0tracknum<0) return; | ||
384 | if (base0tracknum>=MAXCHANNELS) return; | ||
385 | |||
386 | if (selected) | ||
387 | { | ||
388 | job->trackselected[base0tracknum]=1; | ||
389 | } else { | ||
390 | job->trackselected[base0tracknum]=0; | ||
391 | } | ||
392 | return; | ||
393 | } | ||
394 | |||
395 | bool hd24transferengine::trackselected(__uint32 base0tracknum) | ||
396 | { | ||
397 | if (base0tracknum<0) return false; | ||
398 | if (base0tracknum>=MAXCHANNELS) return false; | ||
399 | |||
400 | return ((job->trackselected[base0tracknum])==1); | ||
401 | } | ||
402 | |||
403 | |||
404 | void hd24transferengine::openbuffers(unsigned char** audiobuf, | ||
405 | unsigned int channels, | ||
406 | unsigned int bufsize) | ||
407 | { | ||
408 | #if (HD24TRANSFERDEBUG==1) | ||
409 | cout << "hd24transferengine::openbuffers" << endl; | ||
410 | #endif | ||
411 | |||
412 | for (unsigned int handle=0;handle<channels;handle++) | ||
413 | { | ||
414 | if (!trackselected(handle)) { | ||
415 | // channel not selected for export | ||
416 | continue; | ||
417 | } | ||
418 | audiobuf[handle]= | ||
419 | (unsigned char *)memutils::mymalloc("openbuffers", | ||
420 | bufsize,1); | ||
421 | } | ||
422 | #if (HD24TRANSFERDEBUG==1) | ||
423 | cout << "opened buffers" << endl; | ||
424 | #endif | ||
425 | } | ||
426 | |||
427 | void hd24transferengine::closebuffers(unsigned char** audiobuf,unsigned int channels) | ||
428 | { | ||
429 | #if (HD24TRANSFERDEBUG==1) | ||
430 | cout << "hd24transferengine::closebuffers" << endl; | ||
431 | #endif | ||
432 | for (__uint32 handle=0;handle<channels;handle++) | ||
433 | { | ||
434 | if (!trackselected(handle)) { | ||
435 | // channel not selected for export | ||
436 | continue; | ||
437 | } | ||
438 | if (audiobuf[handle]!=NULL) | ||
439 | { | ||
440 | memutils::myfree("closebuffers",audiobuf[handle]); | ||
441 | } | ||
442 | } | ||
443 | } | ||
444 | |||
445 | void hd24transferengine::writerawbuf(hd24sndfile* filehandle,unsigned char* buf,long subblockbytes) | ||
446 | { | ||
447 | #if (HD24TRANSFERDEBUG==2) | ||
448 | cout << "writerawbuf (filehandle="<<filehandle<<", buf="<<buf<<", subblockbytes="<<subblockbytes<<endl; | ||
449 | #endif | ||
450 | filehandle->writerawbuf(buf,subblockbytes); | ||
451 | #if (HD24TRANSFERDEBUG==2 ) | ||
452 | cout << "end writerawbuf (filehandle="<<filehandle<<", buf="<<buf<<", subblockbytes="<<subblockbytes<<endl; | ||
453 | #endif | ||
454 | } | ||
455 | |||
456 | bool hd24transferengine::openinputfiles(SNDFILE** filehandle,SF_INFO* sfinfoin,unsigned int channels) | ||
457 | { | ||
458 | int cannotopen=0; | ||
459 | cout << "TODO: hd24transferengine::openinputfiles" << endl; | ||
460 | if (job==NULL) | ||
461 | { | ||
462 | lasterror("No job found, transfer aborted."); | ||
463 | return false; | ||
464 | } | ||
465 | |||
466 | int trackcount=0; | ||
467 | for (unsigned int handle=0;handle<channels;handle++) | ||
468 | { | ||
469 | #if (HD24TRANSFERDEBUG!=0) | ||
470 | cout << "Openinputfiles - handle=" << handle << endl; | ||
471 | #endif | ||
472 | if (job->sourcefilename(handle+1)==NULL) { | ||
473 | #if (HD24TRANSFERDEBUG!=0) | ||
474 | cout << "Channel not selected for transfer, skipping" << endl; | ||
475 | #endif | ||
476 | continue; | ||
477 | } | ||
478 | if (strlen(job->sourcefilename(handle+1))==0) { | ||
479 | #if (HD24TRANSFERDEBUG!=0) | ||
480 | cout << "Channel not selected for transfer, skipping" << endl; | ||
481 | #endif | ||
482 | continue; | ||
483 | } | ||
484 | trackcount++; | ||
485 | |||
486 | #if (HD24TRANSFERDEBUG!=0) | ||
487 | cout << "Channel selected for transfer" << endl; | ||
488 | cout << "That brings the total track count to " | ||
489 | << trackcount << endl; | ||
490 | cout << "job=" << job << endl; | ||
491 | cout << "soundfile=" << soundfile << endl; | ||
492 | cout << "sourcefilename=" << job->sourcefilename(handle+1) | ||
493 | << endl; | ||
494 | #endif | ||
495 | |||
496 | job->filehandle[handle]=soundfile->sf_open(job->sourcefilename(handle+1),SFM_READ,&sfinfoin[handle]); | ||
497 | if (!(job->filehandle[handle])) | ||
498 | { | ||
499 | cannotopen=1; | ||
500 | continue; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | return (cannotopen==0); // return true if successful, flase otherwise | ||
505 | } | ||
506 | |||
507 | bool hd24transferengine::openoutputfiles(hd24sndfile** filehandle,unsigned int channels,unsigned int partnum,int prefix) | ||
508 | { | ||
509 | trackspergroup=0; | ||
510 | |||
511 | SF_INFO sfinfoout; | ||
512 | bool uselibsndfile=m_format_sndfile[selectedformat()]; | ||
513 | sfinfoout.format=m_format_outputformat[selectedformat()]; | ||
514 | int chcount=0; | ||
515 | if (m_format_outputchannels[selectedformat()]==0) { | ||
516 | // count channels | ||
517 | for (unsigned int handle=0;handle<channels;handle++) | ||
518 | { | ||
519 | if (job->trackselected[handle]!=0) { | ||
520 | chcount++; | ||
521 | } | ||
522 | } | ||
523 | sfinfoout.channels=chcount; | ||
524 | } else { | ||
525 | sfinfoout.channels=m_format_outputchannels[selectedformat()]; | ||
526 | } | ||
527 | if (job->usecustomrate==1) { | ||
528 | long samrate=job->stamprate; | ||
529 | sfinfoout.samplerate=samrate; | ||
530 | } else { | ||
531 | sfinfoout.samplerate=job->sourcesong()->samplerate(); | ||
532 | } | ||
533 | // chcount and lasthandle are intended to allow | ||
534 | // support for writing multichannel files. | ||
535 | int lasthandle=0; | ||
536 | int lasttrack=-1; | ||
537 | int trackcount=0; | ||
538 | int cannotopen=0; | ||
539 | chcount=0; | ||
540 | for (unsigned int handle=0;handle<channels;handle++) | ||
541 | { | ||
542 | |||
543 | islastchanofgroup[handle]=false; | ||
544 | isfirstchanofgroup[handle]=false; | ||
545 | |||
546 | if (job->trackselected[handle]==0) { | ||
547 | // channel not selected for export | ||
548 | continue; | ||
549 | } | ||
550 | trackcount++; | ||
551 | lasttrack=handle; | ||
552 | |||
553 | string* fname=generate_filename(handle,partnum,prefix); | ||
554 | if (fname==NULL) | ||
555 | { | ||
556 | /* cannot generate filename. Most likely cause is | ||
557 | no song set */ | ||
558 | return false; // problem opening files. | ||
559 | } | ||
560 | if (chcount==0) { | ||
561 | isfirstchanofgroup[handle]=true; | ||
562 | if (uselibsndfile) | ||
563 | { | ||
564 | filehandle[handle]->sndfilehandle=NULL; | ||
565 | if (soundfile->sf_open) { | ||
566 | filehandle[handle]->open(fname->c_str(),(int)SFM_WRITE,&sfinfoout,soundfile); | ||
567 | } | ||
568 | if (!(filehandle[handle]->handle())) | ||
569 | { | ||
570 | cannotopen=1; | ||
571 | } | ||
572 | } | ||
573 | else | ||
574 | { | ||
575 | filehandle[handle]->open(fname->c_str(),(int)SFM_WRITE,&sfinfoout); | ||
576 | } | ||
577 | lasthandle=handle; | ||
578 | } else { | ||
579 | // copy handle of previously opened file to current track | ||
580 | filehandle[handle]->handle(filehandle[lasthandle]->handle(),filehandle[lasthandle]->handletype()); | ||
581 | if (!(filehandle[handle]->handle())) | ||
582 | { | ||
583 | cannotopen=1; | ||
584 | } | ||
585 | } | ||
586 | chcount++; | ||
587 | if ((sfinfoout.channels)!=0) | ||
588 | { | ||
589 | // sfinfoout.channels=0 means full multitrack file | ||
590 | // so only a single file will be opened. | ||
591 | chcount=chcount%(sfinfoout.channels); | ||
592 | if (chcount==0) { | ||
593 | islastchanofgroup[handle]=true; | ||
594 | if (trackspergroup==0) { | ||
595 | trackspergroup=trackcount; | ||
596 | } | ||
597 | } | ||
598 | } | ||
599 | |||
600 | delete fname; | ||
601 | } | ||
602 | if (lasttrack>=0) | ||
603 | { | ||
604 | if (trackspergroup==0) { | ||
605 | trackspergroup=trackcount; | ||
606 | } | ||
607 | |||
608 | islastchanofgroup[lasttrack]=true; | ||
609 | } | ||
610 | return (cannotopen==0); // return true if successful, false otherwise | ||
611 | } | ||
612 | |||
613 | void hd24transferengine::closeinputfiles(SNDFILE** filehandle,unsigned int channels) | ||
614 | { | ||
615 | SNDFILE* lasthandle=NULL; | ||
616 | for (unsigned int handle=0;handle<channels;handle++) | ||
617 | { | ||
618 | if (job->trackselected[handle]==0) continue; | ||
619 | if (filehandle[handle]!=lasthandle) { | ||
620 | soundfile->sf_close(filehandle[handle]); | ||
621 | lasthandle=filehandle[handle]; | ||
622 | filehandle[handle]=NULL; | ||
623 | } | ||
624 | } | ||
625 | } | ||
626 | |||
627 | void hd24transferengine::closeoutputfiles(hd24sndfile** filehandle,unsigned int channels) | ||
628 | { | ||
629 | void* lasthandle=NULL; | ||
630 | |||
631 | for (unsigned int handle=0;handle<channels;handle++) | ||
632 | { | ||
633 | if (job->trackselected[handle]==0) continue; | ||
634 | if (filehandle[handle]->handle()!=lasthandle) { | ||
635 | lasthandle=(void*)filehandle[handle]->handle(); | ||
636 | if (lasthandle!=NULL) { | ||
637 | filehandle[handle]->close(); | ||
638 | } | ||
639 | } | ||
640 | } | ||
641 | } | ||
642 | |||
643 | bool hd24transferengine::confirmfileoverwrite() | ||
644 | { | ||
645 | if (this->uiconfirmfunction==NULL) | ||
646 | { | ||
647 | lasterror("Output files already exist, transfer aborted."); | ||
648 | return false; | ||
649 | } | ||
650 | |||
651 | return uiconfirmfunction(ui,"One or more output files already exist. " | ||
652 | "Do you want to overwrite them?"); | ||
653 | } | ||
654 | |||
655 | bool hd24transferengine::overwritegivesproblems(hd24song* thesong,int partnum) | ||
656 | { | ||
657 | /* this function will return TRUE if overwriting | ||
658 | existing files causes a problem, FALSE otherwise. | ||
659 | |||
660 | Overwriting files does NOT cause problems if | ||
661 | - no files are going to be overwritten | ||
662 | or | ||
663 | - Files are going to be overwritten but the user | ||
664 | permits us to do so. | ||
665 | |||
666 | */ | ||
667 | |||
668 | if (anyfilesexist(thesong)) | ||
669 | { | ||
670 | return (!(confirmfileoverwrite())); | ||
671 | } | ||
672 | return false; | ||
673 | } | ||
674 | |||
675 | bool hd24transferengine::dontopenoutputfiles(hd24sndfile** filehandle,unsigned int channels,unsigned int partnum,int prefix) | ||
676 | { | ||
677 | // HACK | ||
678 | trackspergroup=0; | ||
679 | |||
680 | SF_INFO sfinfoout; | ||
681 | //bool uselibsndfile=m_format_sndfile[selectedformat()]; | ||
682 | sfinfoout.format=m_format_outputformat[selectedformat()]; | ||
683 | int chcount=0; | ||
684 | if (m_format_outputchannels[selectedformat()]==0) { | ||
685 | // count channels | ||
686 | for (unsigned int handle=0;handle<channels;handle++) | ||
687 | { | ||
688 | if (job->trackselected[handle]!=0) { | ||
689 | chcount++; | ||
690 | } | ||
691 | } | ||
692 | sfinfoout.channels=chcount; | ||
693 | } else { | ||
694 | sfinfoout.channels=m_format_outputchannels[selectedformat()]; | ||
695 | } | ||
696 | if (job->usecustomrate==1) { | ||
697 | long samrate=job->stamprate; | ||
698 | sfinfoout.samplerate=samrate; | ||
699 | } else { | ||
700 | sfinfoout.samplerate=job->sourcesong()->samplerate(); | ||
701 | } | ||
702 | // chcount and lasthandle are intended to allow | ||
703 | // support for writing multichannel files. | ||
704 | int lasthandle=0; | ||
705 | int lasttrack=-1; | ||
706 | int trackcount=0; | ||
707 | int cannotopen=0; | ||
708 | chcount=0; | ||
709 | for (unsigned int handle=0;handle<channels;handle++) | ||
710 | { | ||
711 | |||
712 | islastchanofgroup[handle]=false; | ||
713 | isfirstchanofgroup[handle]=false; | ||
714 | |||
715 | if (job->trackselected[handle]==0) { | ||
716 | // channel not selected for export | ||
717 | continue; | ||
718 | } | ||
719 | trackcount++; | ||
720 | lasttrack=handle; | ||
721 | |||
722 | string* fname=generate_filename(handle,partnum,prefix); | ||
723 | if (fname==NULL) | ||
724 | { | ||
725 | // Cannot generate filename. No song set? | ||
726 | return false; // problem (not) opening files. | ||
727 | } | ||
728 | if (chcount==0) { | ||
729 | isfirstchanofgroup[handle]=true; | ||
730 | // if (uselibsndfile) | ||
731 | // { | ||
732 | // filehandle[handle]->sndfilehandle=NULL; | ||
733 | // if (soundfile->sf_open) { | ||
734 | // filehandle[handle]->open(fname->c_str(),(int)SFM_WRITE,&sfinfoout,soundfile); | ||
735 | // } | ||
736 | // if (!(filehandle[handle]->handle())) | ||
737 | // { | ||
738 | // cannotopen=1; | ||
739 | // } | ||
740 | // } | ||
741 | // else | ||
742 | // { | ||
743 | // filehandle[handle]->open(fname->c_str(),(int)SFM_WRITE,&sfinfoout); | ||
744 | // } | ||
745 | lasthandle=handle; | ||
746 | } else { | ||
747 | // copy handle of previously opened file to current track | ||
748 | // filehandle[handle]->handle(filehandle[lasthandle]->handle(),filehandle[lasthandle]->handletype()); | ||
749 | // if (!(filehandle[handle]->handle())) | ||
750 | // { | ||
751 | // cannotopen=1; | ||
752 | // } | ||
753 | } | ||
754 | chcount++; | ||
755 | // if ((sfinfoout.channels)!=0) | ||
756 | // { | ||
757 | // // sfinfoout.channels=0 means full multitrack file | ||
758 | // // so only a single file will be opened. | ||
759 | // chcount=chcount%(sfinfoout.channels); | ||
760 | // if (chcount==0) { | ||
761 | // islastchanofgroup[handle]=true; | ||
762 | // if (trackspergroup==0) { | ||
763 | // trackspergroup=trackcount; | ||
764 | // } | ||
765 | // } | ||
766 | // } | ||
767 | |||
768 | delete fname; | ||
769 | } | ||
770 | |||
771 | if (lasttrack>=0) | ||
772 | { | ||
773 | if (trackspergroup==0) { | ||
774 | trackspergroup=trackcount; | ||
775 | } | ||
776 | |||
777 | islastchanofgroup[lasttrack]=true; | ||
778 | } | ||
779 | return (cannotopen==0); // return true if successful, false otherwise | ||
780 | } | ||
781 | void hd24transferengine::flushbuffer(hd24sndfile** filehandle,unsigned char** buffer,__uint32 flushbytes,unsigned int channels) | ||
782 | { | ||
783 | #if (HD24TRANSFERDEBUG==1) | ||
784 | cout << "Flushbuffer " << flushbytes << " bytes" <<endl; | ||
785 | #endif | ||
786 | for (unsigned int handle=0;handle<channels;handle++) | ||
787 | { | ||
788 | if (job->trackselected[handle]==0) continue; | ||
789 | |||
790 | writerawbuf(&(*filehandle)[handle],buffer[handle],flushbytes); | ||
791 | } | ||
792 | #if (HD24TRANSFERDEBUG==1) | ||
793 | cout << "Flushed" << endl; | ||
794 | #endif | ||
795 | } | ||
796 | |||
797 | void hd24transferengine::prepare_transfer_to_pc(__uint32 songnum, | ||
798 | __uint32 totsongs,__sint64 totbytestotransfer, | ||
799 | __sint64 totbytestransferred, | ||
800 | int wantsplit,__uint32 prefix) | ||
801 | { | ||
802 | // set properties as needed | ||
803 | cout << "prepare transfer to pc:" << endl; | ||
804 | cout << "song "<< songnum<< "/" << totsongs << ", "; | ||
805 | cout << totbytestotransfer << " total bytes to transfer" << endl; | ||
806 | cout << totbytestransferred << " transferred so far" << endl; | ||
807 | cout << "wantsplit=" << wantsplit ; | ||
808 | cout << ", prefix=" << prefix << endl; | ||
809 | this->totbytestotransfer=totbytestotransfer; | ||
810 | // this->transfer_to_pc(); | ||
811 | } | ||
812 | |||
813 | void hd24transferengine::transfer_in_progress(bool active) | ||
814 | { | ||
815 | // TODO: callback function | ||
816 | // stop_transfer->show(); | ||
817 | } | ||
818 | |||
819 | void hd24transferengine::mixleft(bool select) | ||
820 | { | ||
821 | if (select) { job->mixleft=1; } | ||
822 | } | ||
823 | |||
824 | bool hd24transferengine::mixleft() | ||
825 | { | ||
826 | if (job->mixleft==1) | ||
827 | { | ||
828 | return true; | ||
829 | } | ||
830 | return false; | ||
831 | } | ||
832 | |||
833 | void hd24transferengine::mixright(bool select) | ||
834 | { | ||
835 | if (select) { job->mixright=1; } | ||
836 | } | ||
837 | |||
838 | bool hd24transferengine::mixright() | ||
839 | { | ||
840 | if (job->mixright==1) | ||
841 | { | ||
842 | return true; | ||
843 | } | ||
844 | return false; | ||
845 | } | ||
846 | |||
847 | |||
848 | __sint64 hd24transferengine::transfer_to_pc() | ||
849 | { | ||
850 | // function returns bytes transferred for the transfer of only the current file. | ||
851 | |||
852 | __sint64 totsamcount; /* Total number of samples exported */ | ||
853 | __sint64 partsamcount; /* When splitting up the song into multiple parts, | ||
854 | number of samples exported to current part */ | ||
855 | __sint64 blockcount; /* Allows us to keep a write buffer as cache for | ||
856 | better export performance */ | ||
857 | if (job->sourcesong()==NULL) | ||
858 | { | ||
859 | return 0; | ||
860 | } | ||
861 | if (transfer_cancel==1) | ||
862 | { | ||
863 | return 0; | ||
864 | } | ||
865 | |||
866 | // limit which tracks need to be actually read from HD24 disk | ||
867 | for (__uint32 i=1;i<=MAXCHANNELS;i++) | ||
868 | { | ||
869 | if (job->trackselected[i-1]==1) | ||
870 | { | ||
871 | job->sourcesong()->readenabletrack(i,true); | ||
872 | } else { | ||
873 | job->sourcesong()->readenabletrack(i,false); | ||
874 | } | ||
875 | } | ||
876 | bool mustmixdown=false; | ||
877 | if (job->mixleft==1) | ||
878 | { | ||
879 | mustmixdown=true; | ||
880 | } | ||
881 | if (job->mixright==1) | ||
882 | { | ||
883 | mustmixdown=true; | ||
884 | } | ||
885 | if (transfermixer==NULL) | ||
886 | { | ||
887 | /* as much as we'd like, there is no mixer so we can't mix. */ | ||
888 | mustmixdown=false; | ||
889 | } | ||
890 | |||
891 | #if (HD24TRANSFERDEBUG==1) | ||
892 | cout << "start export 1" << endl; | ||
893 | #endif | ||
894 | __uint32 lastremain=0xffffffff; //a | ||
895 | __uint64 songlen_sam=job->sourcesong()->songlength_in_samples()*(job->sourcesong()->physical_channels()/job->sourcesong()->logical_channels()); | ||
896 | __uint32 channels=job->sourcesong()->logical_channels(); | ||
897 | __uint32 bytespersam=(job->sourcesong()->bitdepth()/8); | ||
898 | int mustdeinterlace=0; | ||
899 | if ((job->sourcesong()->samplerate())>=88200) | ||
900 | { | ||
901 | mustdeinterlace=1; | ||
902 | } | ||
903 | __uint32 oldmixersamplerate=0; | ||
904 | if (mustmixdown) | ||
905 | { | ||
906 | if (transfermixer!=NULL) { | ||
907 | oldmixersamplerate=transfermixer->samplerate(); | ||
908 | transfermixer->samplerate(job->sourcesong()->samplerate()); | ||
909 | } | ||
910 | } | ||
911 | |||
912 | #if (HD24TRANSFERDEBUG==1) | ||
913 | cout << "Channels="<<channels << endl; | ||
914 | cout << "Songlen="<<songlen_sam << endl; | ||
915 | #endif | ||
916 | double oldpct=0; | ||
917 | #if (HD24TRANSFERDEBUG==1) | ||
918 | cout << "start export 2" << endl; | ||
919 | #endif | ||
920 | |||
921 | //SNDFILE* filehandle[channels]; | ||
922 | hd24sndfile* filehandle[24]; | ||
923 | |||
924 | for (int i=0;i<MAXCHANNELS;i++) | ||
925 | { | ||
926 | filehandle[i]=new hd24sndfile(m_format_outputformat[selectedformat()],soundfile); | ||
927 | } | ||
928 | |||
929 | __uint32 partnum=0; | ||
930 | __uint64 MAXBYTES=job->sizelimit(); | ||
931 | |||
932 | /* | ||
933 | if total number of samples is likely to overflow | ||
934 | max allowable length, ask if user wants to split up | ||
935 | the files. | ||
936 | */ | ||
937 | if (job->wantsplit==1) { | ||
938 | partnum=1; // count part numbers in filename | ||
939 | } else { | ||
940 | partnum=0; // do not count part numbers in filename | ||
941 | MAXBYTES=songlen_sam*bytespersam; // allow the full song length in a single file | ||
942 | } | ||
943 | |||
944 | /* Start location 0 is absolute, all other offsets | ||
945 | are relative to the start offset. The only difference | ||
946 | is in the timecode. | ||
947 | Because of this, if startoffset>0 is given, we | ||
948 | can ignore this. */ | ||
949 | __uint64 translen; | ||
950 | __uint64 tottranslen=0; // for percentage calc in multi-song exports | ||
951 | signed int stepsize; | ||
952 | if (job->startoffset()>job->endoffset()) | ||
953 | { | ||
954 | __uint32 tempoffset=job->startoffset(); | ||
955 | job->startoffset(job->endoffset()); | ||
956 | job->endoffset(tempoffset); | ||
957 | } | ||
958 | |||
959 | translen=(job->endoffset()-job->startoffset())*(job->sourcesong()->physical_channels()/job->sourcesong()->logical_channels()); | ||
960 | #if (HD24TRANSFERDEBUG==1) | ||
961 | cout << "startoffset=" << job->startoffset() << endl; | ||
962 | cout << "endoffset=" << job->endoffset() << endl; | ||
963 | #endif | ||
964 | |||
965 | if (translen==0) | ||
966 | { | ||
967 | lasterror("Start offset equals end offset- nothing to do!"); | ||
968 | } | ||
969 | stepsize=1; | ||
970 | |||
971 | bool canopen=true; | ||
972 | MixerChannelControl* mixerchannel[24]; | ||
973 | for (unsigned int tracknum=0;tracknum<MAXCHANNELS;tracknum++) | ||
974 | { | ||
975 | mixerchannel[tracknum]=NULL; | ||
976 | } | ||
977 | |||
978 | if (mustmixdown) | ||
979 | { | ||
980 | for (unsigned int tracknum=0;tracknum<MAXCHANNELS;tracknum++) | ||
981 | { | ||
982 | mixerchannel[tracknum]=transfermixer->parentui()->mixerchannel[tracknum]->control; | ||
983 | } | ||
984 | // HACK | ||
985 | canopen=dontopenoutputfiles( | ||
986 | (hd24sndfile**)&filehandle[0], | ||
987 | channels, | ||
988 | partnum, | ||
989 | prefix); // partnum is for splitting large files | ||
990 | } else { | ||
991 | canopen=openoutputfiles( | ||
992 | (hd24sndfile**)&filehandle[0], | ||
993 | channels, | ||
994 | partnum, | ||
995 | prefix); // partnum is for splitting large files | ||
996 | } | ||
997 | |||
998 | if (!canopen) | ||
999 | { | ||
1000 | #if (HD24TRANSFERDEBUG==1) | ||
1001 | cout << "error opening output files" << endl; | ||
1002 | #endif | ||
1003 | transfer_cancel=1; | ||
1004 | return 0; | ||
1005 | } else { | ||
1006 | transfer_cancel=0; | ||
1007 | } | ||
1008 | |||
1009 | this->transfer_in_progress(true); | ||
1010 | time (&starttime); | ||
1011 | |||
1012 | partsamcount=0; totsamcount=0; | ||
1013 | int trackwithingroup=0; | ||
1014 | #if (HD24TRANSFERDEBUG==1) | ||
1015 | cout << "songlen in samples=" << songlen_sam << endl; | ||
1016 | #endif | ||
1017 | blockcount=0; // for buffered writing. | ||
1018 | hd24fs* currenthd24=job->sourcefs(); | ||
1019 | if (currenthd24==NULL) | ||
1020 | { | ||
1021 | cout << "Critical error- current FS not defined." << endl; | ||
1022 | } | ||
1023 | int blocksize=currenthd24->getbytesperaudioblock(); | ||
1024 | // to hold normally read audio data: | ||
1025 | unsigned char* audiodata=(unsigned char*)memutils::mymalloc("ftransfer_to_pc",blocksize,1); | ||
1026 | |||
1027 | // for high-samplerate block deinterlacing: | ||
1028 | unsigned char* deinterlacedata=(unsigned char*)memutils::mymalloc("ftransfer_to_pc",blocksize,1); | ||
1029 | |||
1030 | // for interlacing multi-track data: | ||
1031 | unsigned char* interlacedata=(unsigned char*)memutils::mymalloc("ftransfer_to_pc",blocksize,1); | ||
1032 | |||
1033 | |||
1034 | __uint32 samplesperblock=(blocksize/channels)/bytespersam; | ||
1035 | float* outputBuffer=NULL; | ||
1036 | SF_INFO infoblock; | ||
1037 | hd24sndfile* mixdownfile=NULL; | ||
1038 | if (mustmixdown) | ||
1039 | { | ||
1040 | outputBuffer=(float*)malloc(2*samplesperblock*sizeof(float)); // 2 because it is stereo | ||
1041 | mixdownfile=new hd24sndfile(SF_FORMAT_WAV|SF_FORMAT_PCM_32 | ||
1042 | |SF_FORMAT_FLOAT,soundfile); | ||
1043 | infoblock.channels=2; | ||
1044 | infoblock.samplerate=job->sourcesong()->samplerate(); | ||
1045 | infoblock.format=SF_FORMAT_WAV|SF_FORMAT_PCM_32|SF_FORMAT_FLOAT; | ||
1046 | |||
1047 | int mixdownfilenum=0; | ||
1048 | int fileopensuccess=0; | ||
1049 | do { | ||
1050 | string* mixdownfilename=new string(""); | ||
1051 | *mixdownfilename+=*job->m_projectdir; | ||
1052 | string* currsongname=job->sourcesong()->songname(); | ||
1053 | *mixdownfilename+=*currsongname; | ||
1054 | delete currsongname; | ||
1055 | *mixdownfilename+="_mixdown"; | ||
1056 | if (mixdownfilenum>0) | ||
1057 | { | ||
1058 | *mixdownfilename+="_"; | ||
1059 | string* mixnumstr=Convert::int2str(mixdownfilenum); | ||
1060 | *mixdownfilename+=*mixnumstr; | ||
1061 | delete mixnumstr; | ||
1062 | } | ||
1063 | *mixdownfilename+=".wav"; | ||
1064 | if (!hd24utils::fileExists(mixdownfilename->c_str())) | ||
1065 | { | ||
1066 | mixdownfile->open(mixdownfilename->c_str(),SFM_WRITE,&infoblock,soundfile); | ||
1067 | fileopensuccess=1; | ||
1068 | } | ||
1069 | mixdownfilenum++; | ||
1070 | delete mixdownfilename; | ||
1071 | } while (fileopensuccess==0); | ||
1072 | } | ||
1073 | |||
1074 | |||
1075 | __uint32 samplesinfirstblock=samplesperblock; | ||
1076 | if (job->startoffset()!=0) { | ||
1077 | if (job->startoffset()>=samplesperblock) { | ||
1078 | samplesinfirstblock=samplesperblock-(job->startoffset()%samplesperblock); | ||
1079 | } else { | ||
1080 | samplesinfirstblock=samplesperblock-(job->startoffset()); | ||
1081 | } | ||
1082 | } | ||
1083 | #if (HD24TRANSFERDEBUG==1) | ||
1084 | cout << "go to startoffset " << job->startoffset() << endl; | ||
1085 | #endif | ||
1086 | job->sourcesong()->golocatepos(job->startoffset()); | ||
1087 | #if (HD24TRANSFERDEBUG==1) | ||
1088 | cout << "got to startoffset " << job->startoffset() << endl; | ||
1089 | cout << "translen= " << translen << endl; | ||
1090 | #endif | ||
1091 | __uint32 subblocksize=samplesperblock*bytespersam; | ||
1092 | __uint32 samplesinblock=samplesinfirstblock; | ||
1093 | if (translen<samplesperblock) | ||
1094 | { | ||
1095 | samplesinfirstblock=translen; | ||
1096 | } | ||
1097 | |||
1098 | __sint64 difseconds=0; | ||
1099 | __sint64 olddifseconds=0; | ||
1100 | __uint64 bytestransferred=0; | ||
1101 | |||
1102 | for (__uint32 samplenum=0; | ||
1103 | samplenum<translen; | ||
1104 | samplenum+=samplesinblock) | ||
1105 | { | ||
1106 | if (transfer_cancel==1) | ||
1107 | { | ||
1108 | break; | ||
1109 | } | ||
1110 | __uint32 subblockbytes=subblocksize; | ||
1111 | if (translen==samplesinfirstblock) | ||
1112 | { | ||
1113 | #if (HD24TRANSFERDEBUG==1) | ||
1114 | cout << "translen==samplesinfirstblock" << endl; | ||
1115 | subblockbytes=translen*bytespersam; | ||
1116 | samplesinblock=samplesinfirstblock; | ||
1117 | #endif | ||
1118 | } else { | ||
1119 | if (samplenum==0) { | ||
1120 | samplesinblock=samplesinfirstblock; | ||
1121 | } | ||
1122 | else | ||
1123 | { | ||
1124 | samplesinblock=samplesperblock; | ||
1125 | } | ||
1126 | |||
1127 | if (samplenum+samplesinblock>=translen) | ||
1128 | { | ||
1129 | subblockbytes=((translen-samplesinfirstblock) % samplesperblock ) *bytespersam; | ||
1130 | } else { | ||
1131 | if (samplesinblock!=samplesperblock) | ||
1132 | { | ||
1133 | subblockbytes=samplesinblock*bytespersam; | ||
1134 | } | ||
1135 | } | ||
1136 | } | ||
1137 | |||
1138 | #if (HD24TRANSFERDEBUG==1) | ||
1139 | cout << "samplenum=" << samplenum << ", sams in block=" << samplesinblock << endl; | ||
1140 | #endif | ||
1141 | |||
1142 | int skipsams=job->sourcesong()->getmtrackaudiodata(samplenum+job->startoffset(),samplesinblock,&audiodata[0],hd24song::READMODE_COPY); | ||
1143 | unsigned char* whattowrite=&audiodata[0]; | ||
1144 | if (mustdeinterlace==1) | ||
1145 | { | ||
1146 | job->sourcesong()->deinterlaceblock(&audiodata[0],&deinterlacedata[0]); | ||
1147 | whattowrite=&deinterlacedata[0]; | ||
1148 | } | ||
1149 | |||
1150 | #if (HD24TRANSFERDEBUG==1) | ||
1151 | cout << "check for split" << endl; | ||
1152 | #endif | ||
1153 | if (job->wantsplit==1) | ||
1154 | { | ||
1155 | __uint64 filesize=partsamcount; | ||
1156 | filesize+=samplesinblock; | ||
1157 | filesize*=bytespersam; | ||
1158 | if (filesize>MAXBYTES) /// total filesize reached for current part | ||
1159 | { | ||
1160 | closeoutputfiles((hd24sndfile**)&filehandle[0],channels); | ||
1161 | partnum++; | ||
1162 | openoutputfiles((hd24sndfile**)&filehandle[0],channels,partnum,prefix); // partnum is for splitting large files | ||
1163 | partsamcount=0; | ||
1164 | } | ||
1165 | } | ||
1166 | |||
1167 | // check if we need to save a mixdown | ||
1168 | if (mustmixdown) | ||
1169 | { | ||
1170 | #if (HD24TRANSFERDEBUG==1) | ||
1171 | cout << "Mixing " << endl; | ||
1172 | #endif | ||
1173 | |||
1174 | for (__uint32 tracknum=0;tracknum<channels;tracknum++) | ||
1175 | { | ||
1176 | unsigned char* currsam=&whattowrite[tracknum*subblocksize | ||
1177 | +((mustdeinterlace+1)*skipsams*bytespersam)]; | ||
1178 | for (__uint32 samnum=0;samnum<subblockbytes;samnum+=3) | ||
1179 | { | ||
1180 | float subsamval=currsam[samnum+0] | ||
1181 | +(currsam[samnum+1]<<8) | ||
1182 | +(currsam[samnum+2]<<16); | ||
1183 | |||
1184 | if (subsamval>=(1<<23)) { | ||
1185 | subsamval-=(1<<24); | ||
1186 | } | ||
1187 | subsamval=(subsamval/(double)0x800000); | ||
1188 | mixerchannel[tracknum]->sample(samnum/3,subsamval); | ||
1189 | } | ||
1190 | } | ||
1191 | transfermixer->mix(subblockbytes/3); | ||
1192 | |||
1193 | if (outputBuffer!=NULL) | ||
1194 | { | ||
1195 | // if stereo output, interlace (TODO: check if this is what we want) | ||
1196 | for (__uint32 i=0;i<(subblockbytes/3);i++) | ||
1197 | { | ||
1198 | ((float*)outputBuffer)[i*2] = transfermixer->masterout(0,i); // left | ||
1199 | ((float*)outputBuffer)[i*2+1] = transfermixer->masterout(1,i); // right | ||
1200 | } | ||
1201 | mixdownfile->write_float(outputBuffer,(subblockbytes/3)*infoblock.channels); | ||
1202 | } | ||
1203 | } | ||
1204 | // when mixing down, let's not export raw files as well. | ||
1205 | |||
1206 | for (__uint32 tracknum=0;tracknum<channels;tracknum++) | ||
1207 | { | ||
1208 | if (job->trackselected[tracknum]==0) | ||
1209 | { | ||
1210 | // track not selected for export | ||
1211 | #if (HD24TRANSFERDEBUG==1) | ||
1212 | cout << "Track " << tracknum+1 << " not selected for export " << endl; | ||
1213 | #endif | ||
1214 | continue; | ||
1215 | } | ||
1216 | |||
1217 | if (transfer_cancel==1) | ||
1218 | { | ||
1219 | #if (HD24TRANSFERDEBUG==1) | ||
1220 | cout << "Transfer cancelled by user. " << endl; | ||
1221 | #endif | ||
1222 | break; | ||
1223 | } | ||
1224 | |||
1225 | // Mono files or multiple tracks? | ||
1226 | if ( | ||
1227 | (isfirstchanofgroup[tracknum]) | ||
1228 | &&(islastchanofgroup[tracknum]) | ||
1229 | ) { | ||
1230 | // file is mono | ||
1231 | if (!mustmixdown) { | ||
1232 | writerawbuf(filehandle[tracknum],&whattowrite[tracknum*subblocksize+((mustdeinterlace+1)*skipsams*bytespersam)],subblockbytes); | ||
1233 | } | ||
1234 | bytestransferred+=subblockbytes; | ||
1235 | } else { | ||
1236 | if (isfirstchanofgroup[tracknum]) { | ||
1237 | // first channel of group, clear interlace buffer | ||
1238 | trackwithingroup=0; | ||
1239 | #if (HD24TRANSFERDEBUG==1) | ||
1240 | cout << "first track " << samplenum << endl; | ||
1241 | #endif | ||
1242 | } else { | ||
1243 | trackwithingroup++; | ||
1244 | #if (HD24TRANSFERDEBUG==1) | ||
1245 | cout << "nonfirst track " << samplenum << endl; | ||
1246 | #endif | ||
1247 | } | ||
1248 | // interlace channel onto multi channel file buffer | ||
1249 | if (!mustmixdown) { | ||
1250 | hd24utils::interlacetobuffer(&whattowrite[tracknum*subblocksize+((mustdeinterlace+1)*skipsams*bytespersam)],&interlacedata[0],subblockbytes,bytespersam,trackwithingroup,trackspergroup); | ||
1251 | } | ||
1252 | |||
1253 | if (islastchanofgroup[tracknum]) { | ||
1254 | // last channel of group, write interlace buffer to file | ||
1255 | #if (HD24TRANSFERDEBUG==1) | ||
1256 | cout << "write track " << samplenum << endl; | ||
1257 | #endif | ||
1258 | //soundfile->sf_write_raw(filehandle[tracknum],&interlacedata[0],subblockbytes*trackspergroup); | ||
1259 | if (!mustmixdown) { | ||
1260 | writerawbuf(filehandle[tracknum],&interlacedata[0],subblockbytes*trackspergroup); | ||
1261 | } | ||
1262 | bytestransferred+=subblockbytes*trackspergroup; | ||
1263 | } | ||
1264 | } | ||
1265 | } | ||
1266 | partsamcount+=(subblockbytes/bytespersam); | ||
1267 | // totsamcount+=subblockbytes; | ||
1268 | |||
1269 | __uint32 pct; // to use for display percentage | ||
1270 | double dblpct; // to use for ETA calculation | ||
1271 | #if (HD24TRANSFERDEBUG==1) | ||
1272 | cout << "about to calc pct" << endl; | ||
1273 | cout << "totbytestransferred=" << totbytestransferred; | ||
1274 | cout << ", currbytestransferred=" << bytestransferred; | ||
1275 | cout << ", totbytestotransfer=" << totbytestotransfer; | ||
1276 | cout << endl; | ||
1277 | #endif | ||
1278 | |||
1279 | /* following two calculations give the same mathematical result | ||
1280 | but help keep the required word length narrow for large numbers | ||
1281 | and reduce floating point rounding errors for small numbers. | ||
1282 | */ | ||
1283 | if (tottranslen<100000) | ||
1284 | { | ||
1285 | dblpct=( | ||
1286 | ( | ||
1287 | ( | ||
1288 | (double)totbytestransferred | ||
1289 | +(double)bytestransferred | ||
1290 | ) | ||
1291 | *(double)100 | ||
1292 | ) | ||
1293 | / | ||
1294 | (double)totbytestotransfer | ||
1295 | ); | ||
1296 | } | ||
1297 | else | ||
1298 | { | ||
1299 | dblpct=( | ||
1300 | ( | ||
1301 | (double)totbytestransferred | ||
1302 | +(double)bytestransferred | ||
1303 | ) | ||
1304 | / | ||
1305 | (double) | ||
1306 | ( | ||
1307 | (double)totbytestotransfer | ||
1308 | / | ||
1309 | (double)100 | ||
1310 | ) | ||
1311 | ); | ||
1312 | } | ||
1313 | pct=(__uint32)(dblpct); | ||
1314 | |||
1315 | #if (HD24TRANSFERDEBUG==1) | ||
1316 | cout << "about to calc pct2" << endl; | ||
1317 | #endif | ||
1318 | |||
1319 | #if (HD24TRANSFERDEBUG==1) | ||
1320 | cout << "computed pct " << samplenum << endl; | ||
1321 | #endif | ||
1322 | time (&endtime); | ||
1323 | olddifseconds=difseconds; | ||
1324 | difseconds=(long long int)difftime(endtime,starttime); | ||
1325 | |||
1326 | if (((dblpct-oldpct)>=1) || ((difseconds-olddifseconds)>=1)) | ||
1327 | { | ||
1328 | /* update on percentage change, and also every | ||
1329 | so many samples (to allow frequent enough | ||
1330 | screen updates with large audio files) */ | ||
1331 | oldpct=dblpct; | ||
1332 | |||
1333 | string pctmsg="Transferring audio to PC... "; | ||
1334 | if (totsongs>1) | ||
1335 | { | ||
1336 | pctmsg+="Song "; | ||
1337 | string* cursongnum=Convert::int2str(songnum); | ||
1338 | pctmsg+=*cursongnum+"/"; | ||
1339 | delete cursongnum; | ||
1340 | string* totsongnum=Convert::int2str(totsongs); | ||
1341 | pctmsg+=*totsongnum+", "; | ||
1342 | delete totsongnum; | ||
1343 | } | ||
1344 | string* strpct=Convert::int2str(pct); | ||
1345 | pctmsg+=*strpct+"%"; | ||
1346 | |||
1347 | if (pct>0) | ||
1348 | { | ||
1349 | __uint32 estimated_seconds=(__uint32)((difseconds*100)/dblpct); | ||
1350 | __uint32 remaining_seconds=estimated_seconds-difseconds; | ||
1351 | |||
1352 | lastremain=remaining_seconds; | ||
1353 | |||
1354 | __uint32 seconds=(lastremain%60); | ||
1355 | __uint32 minutes=(lastremain-seconds)/60; | ||
1356 | __uint32 hours=0; | ||
1357 | |||
1358 | pctmsg+=" Time remaining: "; | ||
1359 | |||
1360 | if (minutes>59) { | ||
1361 | hours=(minutes/60); | ||
1362 | minutes=(minutes%60); | ||
1363 | string* strhours=Convert::int2str(hours,2,"0"); | ||
1364 | pctmsg+=*strhours; | ||
1365 | pctmsg+=":"; | ||
1366 | delete(strhours); | ||
1367 | } | ||
1368 | |||
1369 | string* minsec=Convert::int2str(minutes,2,"0"); | ||
1370 | |||
1371 | *minsec+=":"; | ||
1372 | |||
1373 | string* strsecs=Convert::int2str(seconds,2,"0"); | ||
1374 | *minsec+=*strsecs; | ||
1375 | delete(strsecs); | ||
1376 | |||
1377 | pctmsg+=*minsec; | ||
1378 | delete(minsec); | ||
1379 | } | ||
1380 | |||
1381 | delete (strpct); | ||
1382 | setstatus(ui,&pctmsg,dblpct); | ||
1383 | } | ||
1384 | } | ||
1385 | |||
1386 | closeoutputfiles((hd24sndfile**)&filehandle[0],channels); | ||
1387 | for (int i=0;i<MAXCHANNELS;i++) { | ||
1388 | if (filehandle[i]!=NULL) | ||
1389 | { | ||
1390 | delete filehandle[i]; | ||
1391 | } | ||
1392 | } | ||
1393 | // from now on we'll read all tracks again | ||
1394 | for (__uint32 i=1;i<=MAXCHANNELS;i++) | ||
1395 | { | ||
1396 | if (job->trackselected[i-1]==1) | ||
1397 | { | ||
1398 | job->sourcesong()->readenabletrack(i,true); | ||
1399 | } | ||
1400 | } | ||
1401 | if (audiodata!=NULL) | ||
1402 | { | ||
1403 | free (audiodata); | ||
1404 | } | ||
1405 | if (deinterlacedata!=NULL) | ||
1406 | { | ||
1407 | free (deinterlacedata); | ||
1408 | } | ||
1409 | if (interlacedata!=NULL) | ||
1410 | { | ||
1411 | free (interlacedata); | ||
1412 | } | ||
1413 | if (outputBuffer!=NULL) | ||
1414 | { | ||
1415 | free (outputBuffer); | ||
1416 | } | ||
1417 | if (mixdownfile!=NULL) | ||
1418 | { | ||
1419 | mixdownfile->close(); | ||
1420 | } | ||
1421 | if (transfermixer!=NULL) { | ||
1422 | transfermixer->samplerate(oldmixersamplerate); | ||
1423 | } | ||
1424 | |||
1425 | return bytestransferred; | ||
1426 | } | ||
1427 | |||
1428 | void hd24transferengine::selectedformat(int i) | ||
1429 | { | ||
1430 | if (i>=formatcount) return; | ||
1431 | job->selectedformat(i); | ||
1432 | } | ||
1433 | void hd24transferjob::selectedformat(int i) | ||
1434 | { | ||
1435 | m_selectedformat=i; | ||
1436 | } | ||
1437 | |||
1438 | int hd24transferengine::selectedformat() | ||
1439 | { | ||
1440 | return job->selectedformat(); | ||
1441 | } | ||
1442 | int hd24transferjob::selectedformat() | ||
1443 | { | ||
1444 | return m_selectedformat; | ||
1445 | } | ||
1446 | |||
1447 | void hd24transferengine::mixer(MixerControl* m_mixer) | ||
1448 | { | ||
1449 | this->transfermixer=m_mixer; | ||
1450 | } | ||
1451 | |||
1452 | MixerControl* hd24transferengine::mixer() | ||
1453 | { | ||
1454 | return this->transfermixer; | ||
1455 | } | ||
1456 | |||
1457 | string* hd24transferengine::generate_filename(int tracknum,int partnum,int prefix) | ||
1458 | { | ||
1459 | #if (HD24TRANSFERDEBUG==1) | ||
1460 | cout << "hd24transferengine::generate_filename(track=" << tracknum << ",part="<<partnum<<",prefix="<<prefix<<endl; | ||
1461 | cout << "Selected format="<<selectedformat() << endl; | ||
1462 | #endif | ||
1463 | #if (HD24TRANSFERDEBUG==1) | ||
1464 | cout << "Job="<<job<<endl; | ||
1465 | #endif | ||
1466 | #if (HD24TRANSFERDEBUG==1) | ||
1467 | cout << "Projdir="<<job->m_projectdir<<endl; | ||
1468 | #endif | ||
1469 | if (job->m_projectdir==NULL) | ||
1470 | { | ||
1471 | cout << "No project dir set!" << endl; | ||
1472 | return NULL; | ||
1473 | } | ||
1474 | const char* pdir=job->m_projectdir->c_str(); //projectdir(); | ||
1475 | #if (HD24TRANSFERDEBUG==1) | ||
1476 | cout << "Projdir (const char*)="<<pdir << endl; | ||
1477 | #endif | ||
1478 | |||
1479 | if (pdir==NULL) | ||
1480 | { | ||
1481 | cout << "No project dir set!" << endl; | ||
1482 | return NULL; | ||
1483 | } | ||
1484 | string* dirname=new string(pdir); | ||
1485 | if (dirname->substr(dirname->length()-1,1)!="/") { | ||
1486 | *dirname+="/"; | ||
1487 | } | ||
1488 | #if (HD24TRANSFERDEBUG==1) | ||
1489 | cout << "filename so far is just dir with slash=" << *dirname << endl; | ||
1490 | #endif | ||
1491 | string* fname=new string(dirname->c_str()); | ||
1492 | delete dirname; | ||
1493 | if (prefix!=0) | ||
1494 | { | ||
1495 | string* strsongnum=Convert::int2str(prefix,2,"0"); | ||
1496 | *fname+="Song"; | ||
1497 | *fname+=*strsongnum; | ||
1498 | *fname+="-"; | ||
1499 | delete (strsongnum); | ||
1500 | } | ||
1501 | #if (HD24TRANSFERDEBUG==1) | ||
1502 | cout << "filename so far is " << *fname << endl; | ||
1503 | cout << "About to add songname" << endl; | ||
1504 | #endif | ||
1505 | if (job->sourcesong()==NULL) | ||
1506 | { | ||
1507 | #if (HD24TRANSFERDEBUG==1) | ||
1508 | cout << "No song set!" << endl; | ||
1509 | #endif | ||
1510 | return NULL; | ||
1511 | } | ||
1512 | |||
1513 | string* strsongname=job->sourcesong()->songname(); | ||
1514 | *fname+=*strsongname; | ||
1515 | delete (strsongname); | ||
1516 | |||
1517 | #if (HD24TRANSFERDEBUG==1) | ||
1518 | cout << "filename so far is " << *fname << endl; | ||
1519 | cout << "About to add track constant" << endl; | ||
1520 | #endif | ||
1521 | *fname+="-Track"; | ||
1522 | #if (HD24TRANSFERDEBUG==1) | ||
1523 | cout << "filename so far is " << *fname << endl; | ||
1524 | cout << "About to add tracknum" << (tracknum+2) << endl; | ||
1525 | #endif | ||
1526 | string* strtracknum=Convert::int2str(tracknum+1,2,"0"); | ||
1527 | *fname+=*strtracknum; | ||
1528 | delete (strtracknum); | ||
1529 | if (partnum>0) { | ||
1530 | /* partnum 0 implies no splitting and thus no partnum | ||
1531 | added to the filename. In other words, we either use | ||
1532 | partnum 0 (invisible in filename), or partnum 1-n. */ | ||
1533 | *fname+="_part"; | ||
1534 | *fname+=*Convert::int2str(partnum); | ||
1535 | } | ||
1536 | string* extension=new string((*m_format_outputextension)[selectedformat()]); | ||
1537 | *fname+=*extension; | ||
1538 | delete extension; | ||
1539 | #if (HD24TRANSFERDEBUG==1) | ||
1540 | cout << "Generated filename="<<fname<<endl; | ||
1541 | #endif | ||
1542 | return fname; | ||
1543 | } | ||
1544 | |||
1545 | void hd24transferjob::sizelimit(__sint64 p_sizelimit) | ||
1546 | { | ||
1547 | this->llsizelimit=p_sizelimit; | ||
1548 | } | ||
1549 | |||
1550 | __sint64 hd24transferjob::sizelimit() | ||
1551 | { | ||
1552 | return this->llsizelimit; | ||
1553 | } | ||
1554 | |||
1555 | void hd24transferengine::sizelimit(__sint64 p_sizelimit) | ||
1556 | { | ||
1557 | job->sizelimit(p_sizelimit); | ||
1558 | } | ||
1559 | |||
1560 | __sint64 hd24transferengine::sizelimit() | ||
1561 | { | ||
1562 | return job->sizelimit(); | ||
1563 | } | ||
1564 | |||
1565 | bool hd24transferengine::anyfilesexist(hd24song* thesong) | ||
1566 | { | ||
1567 | bool anyexist=false; | ||
1568 | struct stat fi; | ||
1569 | __uint32 channels=thesong->logical_channels(); | ||
1570 | for (unsigned int q=0; q<100; q++) | ||
1571 | { | ||
1572 | for (unsigned int handle=0;handle<channels;handle++) | ||
1573 | { | ||
1574 | if (job->trackselected[handle]==0) | ||
1575 | { | ||
1576 | // channel not selected for export | ||
1577 | continue; | ||
1578 | } | ||
1579 | string* fname=this->generate_filename(handle,0,q); | ||
1580 | if (fname==NULL) | ||
1581 | { | ||
1582 | // cannot generate filename (no song set?) | ||
1583 | break; | ||
1584 | } | ||
1585 | #if (HD24TRANSFERDEBUG==1) | ||
1586 | cout << "check if file exists:" << *fname << endl; | ||
1587 | #endif | ||
1588 | if ((stat (fname->c_str(), &fi) != -1) && ((fi.st_mode & S_IFDIR) == 0)) | ||
1589 | { | ||
1590 | anyexist=true; | ||
1591 | #if (HD24TRANSFERDEBUG==1) | ||
1592 | cout << "yes, exists" << *fname << endl; | ||
1593 | #endif | ||
1594 | delete fname; | ||
1595 | break; | ||
1596 | } | ||
1597 | |||
1598 | fname=this->generate_filename(handle,1,q); | ||
1599 | if (fname==NULL) | ||
1600 | { | ||
1601 | // cannot generate filename (no song set?) | ||
1602 | break; | ||
1603 | } | ||
1604 | #if (HD24TRANSFERDEBUG==1) | ||
1605 | cout << "check if file exists:" << *fname << endl; | ||
1606 | #endif | ||
1607 | if ((stat (fname->c_str(), &fi) != -1) && ((fi.st_mode & S_IFDIR) == 0)) | ||
1608 | { | ||
1609 | anyexist=true; | ||
1610 | #if (HD24TRANSFERDEBUG==1) | ||
1611 | cout << "yes, exists" << *fname << endl; | ||
1612 | #endif | ||
1613 | delete fname; | ||
1614 | break; | ||
1615 | } | ||
1616 | #if (HD24TRANSFERDEBUG==1) | ||
1617 | cout << "no, doesnt exist" << endl; | ||
1618 | #endif | ||
1619 | |||
1620 | delete fname; | ||
1621 | } | ||
1622 | if (anyexist==true) break; | ||
1623 | } | ||
1624 | return anyexist; | ||
1625 | } | ||
1626 | |||
1627 | void hd24transferengine::setstatus(void* ui,string* message,double percentage) | ||
1628 | { | ||
1629 | #if (HD24TRANSFERDEBUG==1) | ||
1630 | printf(message->c_str(),percentage); | ||
1631 | cout << endl; | ||
1632 | #endif | ||
1633 | if (setstatusfunction!=NULL) | ||
1634 | { | ||
1635 | setstatusfunction(ui,message->c_str(),percentage); | ||
1636 | } | ||
1637 | return; | ||
1638 | } | ||
1639 | |||
1640 | void hd24transferengine::set_ui(void* p_ui) | ||
1641 | { | ||
1642 | this->ui=p_ui; | ||
1643 | } | ||
1644 | |||
1645 | void hd24transferengine::sourcesong(hd24song* song) | ||
1646 | { | ||
1647 | #if (HD24TRANSFERDEBUG==1) | ||
1648 | cout << "hd24transferengine::sourcesong(" << song << ")" << endl; | ||
1649 | #endif | ||
1650 | if (this->job==NULL) | ||
1651 | { | ||
1652 | return; | ||
1653 | } | ||
1654 | this->job->sourcesong(song); | ||
1655 | } | ||
1656 | |||
1657 | hd24song* hd24transferengine::sourcesong() | ||
1658 | { | ||
1659 | #if (HD24TRANSFERDEBUG==1) | ||
1660 | cout << "hd24transferengine::sourcesong()=" | ||
1661 | << this->job->sourcesong()<< endl; | ||
1662 | #endif | ||
1663 | if (this->job==NULL) | ||
1664 | { | ||
1665 | return NULL; | ||
1666 | } | ||
1667 | return this->job->sourcesong(); | ||
1668 | } | ||
1669 | |||
1670 | void hd24transferengine::startoffset(__uint32 newoff) | ||
1671 | { | ||
1672 | job->startoffset(newoff); | ||
1673 | } | ||
1674 | |||
1675 | void hd24transferengine::endoffset(__uint32 newoff) | ||
1676 | { | ||
1677 | job->endoffset(newoff); | ||
1678 | } | ||
1679 | |||
1680 | __uint32 hd24transferengine::startoffset() | ||
1681 | { | ||
1682 | return job->startoffset(); | ||
1683 | } | ||
1684 | |||
1685 | __uint32 hd24transferengine::endoffset() | ||
1686 | { | ||
1687 | return job->endoffset(); | ||
1688 | } | ||
1689 | |||
1690 | void hd24transferengine::targetsong(hd24song* song) | ||
1691 | { | ||
1692 | if (job==NULL) | ||
1693 | { | ||
1694 | return; | ||
1695 | } | ||
1696 | job->targetsong(song); | ||
1697 | } | ||
1698 | |||
1699 | hd24song* hd24transferengine::targetsong() | ||
1700 | { | ||
1701 | if (job==NULL) | ||
1702 | { | ||
1703 | return NULL; | ||
1704 | } | ||
1705 | return job->targetsong(); | ||
1706 | } | ||
1707 | |||
1708 | __sint64 hd24transferengine::transfer_to_hd24() | ||
1709 | { | ||
1710 | if (job->targetsong()==NULL) | ||
1711 | { | ||
1712 | lasterror("No target song selected, transfer aborted."); | ||
1713 | return 0; | ||
1714 | } | ||
1715 | if (soundfile==NULL) | ||
1716 | { | ||
1717 | lasterror("soundfile library not defined, transfer aborted"); | ||
1718 | return 0; | ||
1719 | } | ||
1720 | job->targetsong()->golocatepos(0); | ||
1721 | job->targetsong()->startrecord(hd24song::WRITEMODE_COPY); | ||
1722 | |||
1723 | //mustdisplaytimer=false; | ||
1724 | __sint64 bytestransferred=0; | ||
1725 | |||
1726 | for (unsigned int currchan=0;currchan<MAXCHANNELS;currchan++) { | ||
1727 | job->filehandle[currchan]=NULL; | ||
1728 | audiobuf[currchan]=NULL; | ||
1729 | } | ||
1730 | SF_INFO sfinfoin[24]; | ||
1731 | bool canopen=this->openinputfiles((SNDFILE**)&(job->filehandle[0]),(SF_INFO*)&sfinfoin[0],job->targetsong()->logical_channels()); | ||
1732 | if (!canopen) | ||
1733 | { | ||
1734 | return 0; | ||
1735 | } | ||
1736 | // Find file with largest number of samples; | ||
1737 | // if song is shorter than that, lengthen song to fit it. | ||
1738 | __sint64 translen=job->targetsong()->songlength_in_samples(); | ||
1739 | __uint32 maxlen=(__uint32)translen; | ||
1740 | bool mustlengthensong=false; | ||
1741 | for (int i=0;i<MAXCHANNELS;i++) { | ||
1742 | if (job->filehandle[i]==NULL) continue; | ||
1743 | if (((__sint64)sfinfoin[i].frames) > (__sint64)maxlen) { | ||
1744 | maxlen=sfinfoin[i].frames; | ||
1745 | mustlengthensong=true; | ||
1746 | } | ||
1747 | } | ||
1748 | if (mustlengthensong) { | ||
1749 | string* lengthening=new string("Transferring audio to HD24... "); | ||
1750 | setstatus(ui,lengthening,0); | ||
1751 | delete lengthening; | ||
1752 | #if (HD24TRANSFERDEBUG==1) | ||
1753 | cout << "about to start lengthening song to maxlen=" << maxlen << endl; | ||
1754 | #endif | ||
1755 | bool clearnew=false; // do not silence newly allocated part | ||
1756 | // (it is done automatically during transfer) | ||
1757 | translen=job->targetsong()->songlength_in_samples(maxlen,clearnew); | ||
1758 | #if (HD24TRANSFERDEBUG==1) | ||
1759 | cout << "verifying actual song length " << endl; | ||
1760 | cout << "new len=" << translen << endl; | ||
1761 | #endif | ||
1762 | if (translen!=maxlen) | ||
1763 | { | ||
1764 | #if (HD24TRANSFERDEBUG==1) | ||
1765 | cout << "new len<> maxlen so not enough space." << endl; | ||
1766 | #endif | ||
1767 | this->lasterror("Not enough space on HD24 drive."); | ||
1768 | return 0; | ||
1769 | } | ||
1770 | job->targetsong()->save(); | ||
1771 | // ui_refresh("tohd24"); | ||
1772 | #if (HD24TRANSFERDEBUG==1) | ||
1773 | cout << "translen is now " << translen << endl; | ||
1774 | #endif | ||
1775 | |||
1776 | } | ||
1777 | hd24fs* currenthd24=job->targetfs(); | ||
1778 | int blocksize=currenthd24->getbytesperaudioblock(); | ||
1779 | // to hold normally read audio data: | ||
1780 | unsigned char* audiodata=NULL; | ||
1781 | transfer_cancel=0; | ||
1782 | // ui->stop_transfer->show(); | ||
1783 | |||
1784 | audiodata=(unsigned char*)memutils::mymalloc("button_transfertohd24",blocksize,1); | ||
1785 | __uint32 channels=job->targetsong()->logical_channels(); | ||
1786 | __uint32 bytespersam=(job->targetsong()->bitdepth()/8); | ||
1787 | __uint32 samplesperblock=(blocksize/channels)/bytespersam; | ||
1788 | job->smptegen=new SMPTEgenerator(job->targetsong()->samplerate()); | ||
1789 | |||
1790 | for (unsigned int fh=0;fh<MAXCHANNELS;fh++) { | ||
1791 | int action=job->trackaction(fh+1); | ||
1792 | if ((job->filehandle[fh]!=NULL)||(action<=1 /* erase, SMPTE stripe */)) { | ||
1793 | __uint32 chans=((action==0)||(action==1))?(1):(sfinfoin[fh].channels); | ||
1794 | __uint32 bytestoalloc=chans*samplesperblock*sizeof(int); | ||
1795 | audiobuf[fh]=(int*)memutils::mymalloc( | ||
1796 | "button_transfertohd24 audiobuf",bytestoalloc,1 | ||
1797 | ); | ||
1798 | |||
1799 | if (action == 0) { | ||
1800 | // clear erase buffer once | ||
1801 | int* buf=audiobuf[fh]; | ||
1802 | for (__uint32 samnum=0;samnum<samplesperblock;samnum++) { | ||
1803 | buf[samnum]=0; | ||
1804 | } | ||
1805 | } | ||
1806 | if (action == 1) { | ||
1807 | // clear SMPTE buffer once (mostly for debugging purposes) | ||
1808 | int* buf=audiobuf[fh]; | ||
1809 | for (__uint32 samnum=0;samnum<samplesperblock;samnum++) { | ||
1810 | buf[samnum]=1; | ||
1811 | } | ||
1812 | } | ||
1813 | // if action==1, we need to repopulate the buffer while striping | ||
1814 | } else { | ||
1815 | audiobuf[fh]=NULL; | ||
1816 | } | ||
1817 | } | ||
1818 | |||
1819 | // number of samples in current block- equal to block samples for full song | ||
1820 | // transfer | ||
1821 | __uint32 subblocksize=samplesperblock*bytespersam; | ||
1822 | |||
1823 | int mustinterlace=0; | ||
1824 | if ((job->targetsong()->samplerate())>=88200) | ||
1825 | { | ||
1826 | mustinterlace=1; | ||
1827 | } | ||
1828 | #if (HD24TRANSFERDEBUG==1) | ||
1829 | cout << "Channels="<<channels << endl; | ||
1830 | #endif | ||
1831 | __uint32 startoffset=0; | ||
1832 | //__uint32 endoffset=currsong->songlength_in_samples(); | ||
1833 | __uint32 samplesinfirstblock=samplesperblock; | ||
1834 | |||
1835 | job->targetsong()->getlocatepos(25); // 25= virtual endpoint of song | ||
1836 | // calc number of samples to transfer. | ||
1837 | // for high samplerate songs, this is twice the songlength. | ||
1838 | // (for partial transfers, which are not supported at this time, the | ||
1839 | // number of samples is based on (endoffset-startoffset) instead of songlength | ||
1840 | translen=job->targetsong()->songlength_in_samples()*(job->targetsong()->physical_channels()/job->targetsong()->logical_channels()); | ||
1841 | __uint64 totbytestotransfer=translen*bytespersam; | ||
1842 | //transfer_to_hd24(); | ||
1843 | |||
1844 | if (startoffset!=0) { | ||
1845 | if (startoffset>=samplesperblock) { | ||
1846 | samplesinfirstblock=samplesperblock-(startoffset%samplesperblock); | ||
1847 | } else { | ||
1848 | samplesinfirstblock=samplesperblock-startoffset; | ||
1849 | } | ||
1850 | } | ||
1851 | #if (HD24TRANSFERDEBUG==1) | ||
1852 | cout << "go to startoffset " << startoffset << endl; | ||
1853 | #endif | ||
1854 | job->targetsong()->golocatepos(startoffset); | ||
1855 | #if (HD24TRANSFERDEBUG==1) | ||
1856 | cout << "got to startoffset " << startoffset << endl; | ||
1857 | cout << "translen= " << translen << endl; | ||
1858 | #endif | ||
1859 | |||
1860 | __uint32 samplesinblock=samplesinfirstblock; | ||
1861 | if (translen<samplesperblock) | ||
1862 | { | ||
1863 | samplesinfirstblock=translen; | ||
1864 | } | ||
1865 | |||
1866 | __sint64 difseconds=0; | ||
1867 | __sint64 olddifseconds=0; | ||
1868 | __uint64 totbytestransferred=0; // only for multi song transfer- does not apply. | ||
1869 | //deactivate_ui(); | ||
1870 | for (__uint32 samplenum=0; | ||
1871 | samplenum<translen; | ||
1872 | samplenum+=samplesinblock) | ||
1873 | { | ||
1874 | if (transfer_cancel==1) | ||
1875 | { | ||
1876 | //ui_refresh("tohd24_cancel"); | ||
1877 | break; | ||
1878 | } | ||
1879 | #if (HD24TRANSFERDEBUG==1) | ||
1880 | cout << "samnum= " << samplenum << endl; | ||
1881 | #endif | ||
1882 | __uint32 subblockbytes=subblocksize; | ||
1883 | if (translen==samplesinfirstblock) | ||
1884 | { | ||
1885 | #if (HD24TRANSFERDEBUG==1) | ||
1886 | cout << "translen==samplesinfirstblock" << endl; | ||
1887 | subblockbytes=translen*bytespersam; | ||
1888 | samplesinblock=samplesinfirstblock; | ||
1889 | #endif | ||
1890 | } else { | ||
1891 | if (samplenum==0) { | ||
1892 | samplesinblock=samplesinfirstblock; | ||
1893 | } | ||
1894 | else | ||
1895 | { | ||
1896 | samplesinblock=samplesperblock; | ||
1897 | } | ||
1898 | |||
1899 | if (samplenum+samplesinblock>=translen) | ||
1900 | { | ||
1901 | subblockbytes=((translen-samplesinfirstblock) % samplesperblock ) *bytespersam; | ||
1902 | } else { | ||
1903 | if (samplesinblock!=samplesperblock) | ||
1904 | { | ||
1905 | subblockbytes=samplesinblock*bytespersam; | ||
1906 | } | ||
1907 | } | ||
1908 | } | ||
1909 | |||
1910 | #if (HD24TRANSFERDEBUG==1) | ||
1911 | cout << "samplenum=" << samplenum << ", sams in block=" << samplesinblock << endl; | ||
1912 | #endif | ||
1913 | |||
1914 | /* | ||
1915 | // disable multipart files for now (this function transfers TO HD24 drives) | ||
1916 | if (wantsplit==1) | ||
1917 | { | ||
1918 | if (((partsamcount+samplesinblock)*bytespersam)>MAXBYTES) /// total filesize reached for current part | ||
1919 | { | ||
1920 | this->closeoutputfiles((SNDFILE**)&filehandle[0],channels); | ||
1921 | partnum++; | ||
1922 | this->openoutputfiles((SNDFILE**)&filehandle[0],channels,partnum,prefix); // partnum is for splitting large files | ||
1923 | partsamcount=0; | ||
1924 | } | ||
1925 | } | ||
1926 | */ | ||
1927 | for (__uint32 tracknum=0;tracknum<channels;tracknum++) | ||
1928 | { | ||
1929 | if (!(job->targetsong()->trackarmed(tracknum+1))) | ||
1930 | { | ||
1931 | // track not selected for export | ||
1932 | continue; | ||
1933 | } | ||
1934 | __uint32 samsread=0; | ||
1935 | int action=job->trackaction(tracknum+1); | ||
1936 | unsigned int trackchans=1; | ||
1937 | |||
1938 | if (action==0) { /* 0=ERASE */ | ||
1939 | #if (HD24TRANSFERDEBUG==1) | ||
1940 | cout << "track " << tracknum+1 << " marked for erase" << endl; | ||
1941 | |||
1942 | #endif | ||
1943 | samsread=samplesinblock; | ||
1944 | } else { | ||
1945 | if (action==1) | ||
1946 | { | ||
1947 | #if (HD24TRANSFERDEBUG==1) | ||
1948 | cout << "track " << tracknum+1 << " marked for stripe" << endl; | ||
1949 | |||
1950 | #endif | ||
1951 | /* Stripe track with SMPTE/LTC here */ | ||
1952 | |||
1953 | int* buf=audiobuf[tracknum]; | ||
1954 | |||
1955 | for (__uint32 samnum=0;samnum<samplesinblock;samnum++) { | ||
1956 | // smpte stripe: | ||
1957 | buf[samnum]=((job->smptegen->getbit(samplenum+samnum)*2)-1)*2000000; | ||
1958 | } | ||
1959 | /* End of stripe */ | ||
1960 | samsread=samplesinblock; | ||
1961 | } else { | ||
1962 | trackchans=sfinfoin[tracknum].channels; | ||
1963 | if (job->filehandle[tracknum] == NULL) { | ||
1964 | continue; | ||
1965 | } | ||
1966 | samsread=soundfile->sf_read_int( | ||
1967 | job->filehandle[tracknum], | ||
1968 | audiobuf[tracknum], | ||
1969 | samplesinblock*trackchans); | ||
1970 | #if (HD24TRANSFERDEBUG==1) | ||
1971 | cout << "sams read=" | ||
1972 | << samsread | ||
1973 | << endl; | ||
1974 | #endif | ||
1975 | } | ||
1976 | } | ||
1977 | // we replace the deinterlaced data with file audio | ||
1978 | //sf_write_raw(filehandle[tracknum],&whattowrite[tracknum*subblocksize+((mustdeinterlace+1)*skipsams*bytespersam)],subblockbytes); | ||
1979 | |||
1980 | |||
1981 | |||
1982 | // cout << "replace audio block on track " << tracknum+1 << endl; | ||
1983 | |||
1984 | //filehandle[tracknum]; | ||
1985 | |||
1986 | // libsndfile converts all files to 32-bit samples, but we only use 24 bit, | ||
1987 | // so we divide by 256 to shift out the unused 8 bits. | ||
1988 | |||
1989 | __uint32 firstbyte=tracknum*samplesinblock*bytespersam; | ||
1990 | __uint32 whichbyte=firstbyte; | ||
1991 | |||
1992 | int samval; | ||
1993 | for (unsigned int sam=0;sam<samsread;sam+=trackchans) | ||
1994 | { | ||
1995 | int whichsam=sam; | ||
1996 | if (action>2) { | ||
1997 | // multi track | ||
1998 | // use only 24 out of 32 bit | ||
1999 | samval = (audiobuf[tracknum][whichsam+(action-3)])/256; | ||
2000 | } else { | ||
2001 | if (action<2) | ||
2002 | { | ||
2003 | samval=(audiobuf[tracknum][whichsam]); | ||
2004 | } else { | ||
2005 | // action=2 (mono track). | ||
2006 | if (trackchans==1) | ||
2007 | { | ||
2008 | // use the only track | ||
2009 | samval=(audiobuf[tracknum][whichsam])/256; | ||
2010 | } | ||
2011 | else { | ||
2012 | // convert multiple tracks to 1 mono track | ||
2013 | samval=0; | ||
2014 | for (unsigned int whichchan=0;whichchan<trackchans;whichchan++) { | ||
2015 | samval+=(audiobuf[tracknum][whichsam+whichchan])/256; | ||
2016 | } | ||
2017 | // TODO: clip handling | ||
2018 | samval/=trackchans; | ||
2019 | } | ||
2020 | } | ||
2021 | } | ||
2022 | #if (HD24TRANSFERDEBUG==1) | ||
2023 | cout << "whichsam=" << whichsam << " " ;// | ||
2024 | |||
2025 | |||
2026 | cout << "buf[" << tracknum*samplesinblock+(whichsam*bytespersam) << "]="; | ||
2027 | cout << (samval & 0xff) << " " << ((samval>>8) & 0xff) << " " << ((samval>>16) & 0xff) <<"//"; | ||
2028 | if (sam==0) { | ||
2029 | cout << "writing to byte " << whichbyte << " of audiodata " <<endl; | ||
2030 | } | ||
2031 | #endif | ||
2032 | audiodata[whichbyte]=(unsigned char)samval & 0xff; | ||
2033 | audiodata[whichbyte+1]=(unsigned char)(samval>>8) & 0xff; | ||
2034 | audiodata[whichbyte+2]=(unsigned char)(samval>>16) & 0xff; | ||
2035 | whichbyte+=bytespersam; | ||
2036 | } | ||
2037 | // cout << endl; | ||
2038 | |||
2039 | if (transfer_cancel==1) { | ||
2040 | //ui_refresh("tohd24_cancel2"); | ||
2041 | break; | ||
2042 | } | ||
2043 | } | ||
2044 | |||
2045 | // finally we write the audio. the hd24 library will make sure only the relevant | ||
2046 | // tracks will be overwritten and the rest are protected. | ||
2047 | #if (HD24TRANSFERDEBUG==1) | ||
2048 | cout << "1st 30 bytes of track: " << endl; | ||
2049 | for (unsigned int fbyte=0; fbyte<30; fbyte++) { | ||
2050 | cout << audiodata[samplesinblock+fbyte] << " "; | ||
2051 | } | ||
2052 | cout << endl; | ||
2053 | #endif | ||
2054 | //int writesams= (result was not used) | ||
2055 | job->targetsong()->putmtrackaudiodata( | ||
2056 | samplenum+startoffset, | ||
2057 | samplesinblock, | ||
2058 | &audiodata[0], | ||
2059 | hd24song::WRITEMODE_COPY | ||
2060 | ); | ||
2061 | |||
2062 | totbytestransferred+=(samplesinblock*bytespersam); | ||
2063 | |||
2064 | __uint32 pct; // to use for display percentage | ||
2065 | __uint32 oldpct=0; // to use for display percentage | ||
2066 | double dblpct; // to use for ETA calculation | ||
2067 | #if (HD24TRANSFERDEBUG==1) | ||
2068 | cout << "about to calc pct" << endl; | ||
2069 | cout << "totbytestransferred=" << totbytestransferred; | ||
2070 | cout << ", currbytestransferred=" << bytestransferred; | ||
2071 | cout << ", totbytestotransfer=" << totbytestotransfer; | ||
2072 | cout << endl; | ||
2073 | #endif | ||
2074 | |||
2075 | if (translen<100000) { | ||
2076 | pct=(__uint32)(((totbytestransferred+bytestransferred)*100)/(totbytestotransfer)); | ||
2077 | } else { | ||
2078 | pct=(__uint32)((totbytestransferred+bytestransferred)/(totbytestotransfer/100)); | ||
2079 | } | ||
2080 | #if (HD24TRANSFERDEBUG==1) | ||
2081 | cout << "about to calc pct2" << endl; | ||
2082 | #endif | ||
2083 | if (translen<100000) { | ||
2084 | dblpct=(((totbytestransferred+bytestransferred)*100)/(totbytestotransfer)); | ||
2085 | } else { | ||
2086 | dblpct=((totbytestransferred+bytestransferred)/(totbytestotransfer/100)); | ||
2087 | } | ||
2088 | |||
2089 | #if (HD24TRANSFERDEBUG==1) | ||
2090 | cout << "computed pct " << samplenum << endl; | ||
2091 | #endif | ||
2092 | time (&endtime); | ||
2093 | olddifseconds=difseconds; | ||
2094 | difseconds=(long long int)difftime(endtime,starttime); | ||
2095 | |||
2096 | if ((pct!=oldpct) || ((difseconds-olddifseconds)>=1)) | ||
2097 | { | ||
2098 | /* update on percentage change, and also every | ||
2099 | so many samples (to allow frequent enough | ||
2100 | screen updates with large audio files) */ | ||
2101 | oldpct=pct; | ||
2102 | |||
2103 | string* pctmsg=new string("Transferring audio to HD24... %d%%"); | ||
2104 | // TODO: Estimated time remaining goes here | ||
2105 | setstatus(ui,pctmsg,pct); | ||
2106 | delete pctmsg; | ||
2107 | } | ||
2108 | |||
2109 | // fl_check(); covered by setstatus | ||
2110 | } | ||
2111 | |||
2112 | // fl_check(); covered by setstatus | ||
2113 | if (job->smptegen!=NULL) | ||
2114 | { | ||
2115 | // TODO: move to job destructor? | ||
2116 | delete job->smptegen; | ||
2117 | job->smptegen=NULL; | ||
2118 | } | ||
2119 | if (audiodata!=NULL) | ||
2120 | { | ||
2121 | free (audiodata); | ||
2122 | audiodata=NULL; | ||
2123 | } | ||
2124 | for (unsigned int bufnum=0;bufnum<MAXCHANNELS;bufnum++) { | ||
2125 | if (audiobuf[bufnum]!=NULL) { | ||
2126 | memutils::myfree("audiobuf transfer_to_hd24",audiobuf[bufnum]); | ||
2127 | audiobuf[bufnum]=NULL; | ||
2128 | } | ||
2129 | } | ||
2130 | |||
2131 | //end transfer_to_hd24 | ||
2132 | |||
2133 | |||
2134 | |||
2135 | job->targetsong()->stoprecord(); | ||
2136 | |||
2137 | for (unsigned int chnum=1;chnum<=job->targetsong()->logical_channels();chnum++) { | ||
2138 | job->targetsong()->trackarmed(chnum,false); | ||
2139 | } | ||
2140 | this->closeinputfiles((SNDFILE**)&(job->filehandle[0]),job->targetsong()->logical_channels()); | ||
2141 | return totbytestransferred; | ||
2142 | } | ||
2143 | |||
diff --git a/src/lib/hd24transferengine.h b/src/lib/hd24transferengine.h new file mode 100644 index 0000000..03d8392 --- /dev/null +++ b/src/lib/hd24transferengine.h | |||
@@ -0,0 +1,188 @@ | |||
1 | #ifndef __hd24transferengine_h__ | ||
2 | #define __hd24transferengine_h__ | ||
3 | |||
4 | class MixerControl; | ||
5 | |||
6 | #include <config.h> | ||
7 | #include <hd24fs.h> | ||
8 | #include <hd24sndfile.h> | ||
9 | #include <ui_mixer.h> | ||
10 | #include <smpte.h> | ||
11 | class hd24transferjob | ||
12 | { | ||
13 | friend class hd24transferengine; | ||
14 | private: | ||
15 | long long llsizelimit; /* to hold max filesize for autosplit */ | ||
16 | int mixleft; | ||
17 | int mixright; | ||
18 | int m_selectedformat; | ||
19 | hd24fs* jobsourcefs; | ||
20 | hd24song* jobsourcesong; | ||
21 | hd24fs* jobtargetfs; | ||
22 | hd24song* jobtargetsong; | ||
23 | __uint32 m_startoffset; | ||
24 | __uint32 m_endoffset; | ||
25 | SNDFILE* filehandle[24]; /* todo: implement as hd24sndfile* */ | ||
26 | char* filepath[24]; /* one full file path/name per track | ||
27 | mainly to be used for export to hd24 */ | ||
28 | bool have_smpte; | ||
29 | int m_trackaction[24]; | ||
30 | SMPTEgenerator* smptegen; | ||
31 | public: | ||
32 | |||
33 | string* m_projectdir; | ||
34 | int usecustomrate; // 1 to stamp export with custom sample rate | ||
35 | // 0 to keep song sample rate | ||
36 | __uint32 stamprate; //sample rate to use if usecustomrate==1 | ||
37 | int wantsplit; | ||
38 | int* trackselected; | ||
39 | hd24transferjob(); | ||
40 | ~hd24transferjob(); | ||
41 | void init_vars(); | ||
42 | |||
43 | void sizelimit(__sint64 llsizelimit); | ||
44 | __sint64 sizelimit(); | ||
45 | |||
46 | __uint32 startoffset(); | ||
47 | __uint32 endoffset(); | ||
48 | void startoffset(__uint32 newoff); | ||
49 | void endoffset(__uint32 newoff); | ||
50 | |||
51 | void projectdir(const char* projectdir); | ||
52 | const char* projectdir(); | ||
53 | void selectedformat(int format); | ||
54 | int selectedformat(); | ||
55 | hd24fs* sourcefs(); | ||
56 | hd24fs* targetfs(); | ||
57 | hd24song* sourcesong(); | ||
58 | hd24song* targetsong(); | ||
59 | void sourcefs(hd24fs* fs); | ||
60 | void targetfs(hd24fs* fs); | ||
61 | void sourcesong(hd24song* song); | ||
62 | void targetsong(hd24song* song); | ||
63 | char* sourcefilename(int base1tracknum); | ||
64 | void sourcefilename(int base1tracknum,const char* name); | ||
65 | void trackaction(int base1tracknum,int action); | ||
66 | int trackaction(int base1tracknum); | ||
67 | }; | ||
68 | |||
69 | class hd24transferengine | ||
70 | { | ||
71 | private: | ||
72 | void* ui; | ||
73 | |||
74 | MixerControl* transfermixer; | ||
75 | hd24transferjob* job; | ||
76 | |||
77 | __uint32 songnum; | ||
78 | __uint32 totsongs; | ||
79 | __sint64 totbytestotransfer; | ||
80 | __sint64 totbytestransferred; | ||
81 | |||
82 | int prefix; | ||
83 | int transfer_cancel; | ||
84 | int trackspergroup; | ||
85 | int* audiobuf[24]; /* for libsndfile int reading from file */ | ||
86 | bool isfirstchanofgroup[24]; /* for exporting stereo pairs/groups of channels */ | ||
87 | bool islastchanofgroup[24]; /* for exporting stereo pairs/groups of channels */ | ||
88 | |||
89 | void setstatus(void* ui,string* message,double percent); | ||
90 | |||
91 | void openbuffers(unsigned char** audiobuf,unsigned int channels,unsigned int bufsize); | ||
92 | void closebuffers(unsigned char** audiobuf,unsigned int channels); | ||
93 | void writerawbuf(hd24sndfile* filehandle,unsigned char* buf,long subblockbytes); | ||
94 | void flushbuffer(hd24sndfile** filehandle,unsigned char** buffer,__uint32 flushbytes,unsigned int channels); | ||
95 | |||
96 | |||
97 | bool overwritegivesproblems(hd24song* thesong,int partnum); | ||
98 | bool confirmfileoverwrite(); // perform interactive/GUI callback | ||
99 | // to confirm if file overwriting is OK | ||
100 | bool anyfilesexist(hd24song* thesong); | ||
101 | void transfer_in_progress(bool active); | ||
102 | |||
103 | time_t starttime; // these are for benchmarking the transfer | ||
104 | time_t endtime; | ||
105 | |||
106 | /* Regarding populating list of supported file formats | ||
107 | TODO: Move to a separate class? | ||
108 | */ | ||
109 | int formatcount; | ||
110 | void populate_formatlist(); | ||
111 | vector<string>* m_format_outputextension; | ||
112 | vector<string>* m_format_shortdesc; | ||
113 | int m_format_outputformat[100]; | ||
114 | int m_format_outputchannels[100]; | ||
115 | int m_format_bitdepth[100]; | ||
116 | bool m_format_sndfile[100]; | ||
117 | string* m_lasterror; | ||
118 | |||
119 | public: | ||
120 | SoundFileWrapper* soundfile; | ||
121 | bool (*uiconfirmfunction)(void* ui,const char*); | ||
122 | void (*setstatusfunction)(void* ui,const char*,double progress_pct); | ||
123 | |||
124 | void set_ui(void* p_ui); | ||
125 | |||
126 | hd24transferengine(); | ||
127 | ~hd24transferengine(); | ||
128 | |||
129 | void mixer(MixerControl* m_mixer); | ||
130 | MixerControl* mixer(); | ||
131 | |||
132 | void lasterror(const char* errormessage); | ||
133 | string* lasterror(); | ||
134 | |||
135 | int supportedformatcount(); | ||
136 | int format_outputchannels(int i); | ||
137 | const char* getformatdesc(int formatnum); | ||
138 | |||
139 | void trackselected(__uint32 base0tracknum,bool select); | ||
140 | bool trackselected(__uint32 base0tracknum); | ||
141 | |||
142 | void mixleft(bool select); | ||
143 | bool mixleft(); | ||
144 | void mixright(bool select); | ||
145 | bool mixright(); | ||
146 | |||
147 | void init_vars(); | ||
148 | void prepare_transfer_to_pc( | ||
149 | __uint32 songnum, __uint32 totsongs, | ||
150 | __sint64 totbytestotransfer, | ||
151 | __sint64 totbytestransferred, | ||
152 | int wantsplit,__uint32 prefix); | ||
153 | |||
154 | __sint64 transfer_to_pc(); | ||
155 | __sint64 transfer_to_hd24(); | ||
156 | |||
157 | bool openinputfiles(SNDFILE** filehandle,SF_INFO* sfinfoin,unsigned int channels); | ||
158 | void closeinputfiles(SNDFILE** filehandle,unsigned int channels); | ||
159 | bool dontopenoutputfiles(hd24sndfile** filehandle,unsigned int channels,unsigned int partnum,int prefix); //HACK | ||
160 | |||
161 | bool openoutputfiles(hd24sndfile** filehandle,unsigned int channels,unsigned int partnum,int prefix); | ||
162 | void closeoutputfiles(hd24sndfile** filehandle,unsigned int channels); | ||
163 | string* generate_filename(int tracknum,int partnum,int prefix); | ||
164 | void sizelimit(__sint64 llsizelimit); | ||
165 | __sint64 sizelimit(); | ||
166 | void projectdir(const char* projectdir); | ||
167 | const char* projectdir(); | ||
168 | |||
169 | void selectedformat(int format); | ||
170 | int selectedformat(); | ||
171 | |||
172 | void sourcesong(hd24song* newsong); | ||
173 | hd24song* sourcesong(); | ||
174 | void targetsong(hd24song* newsong); | ||
175 | hd24song* targetsong(); | ||
176 | |||
177 | __uint32 startoffset(); | ||
178 | __uint32 endoffset(); | ||
179 | void startoffset(__uint32 newoff); | ||
180 | void endoffset(__uint32 newoff); | ||
181 | char* sourcefilename(int base1tracknum); | ||
182 | void sourcefilename(int base1tracknum,const char* name); | ||
183 | void trackaction(int base1tracknum,int action); | ||
184 | int trackaction(int base1tracknum); | ||
185 | |||
186 | }; | ||
187 | |||
188 | #endif | ||
diff --git a/src/lib/hd24utils.cpp b/src/lib/hd24utils.cpp new file mode 100755 index 0000000..6efb3a7 --- /dev/null +++ b/src/lib/hd24utils.cpp | |||
@@ -0,0 +1,637 @@ | |||
1 | #define UTILDEBUG 0 | ||
2 | #ifdef DARWIN | ||
3 | # define creat64 creat | ||
4 | # define open64 open | ||
5 | # define lseek64 lseek | ||
6 | # define pread64 pread | ||
7 | # define pwrite64 pwrite | ||
8 | #endif | ||
9 | |||
10 | #if defined(LINUX) || defined(DARWIN) | ||
11 | # define PRINTAPP "lp" | ||
12 | #endif | ||
13 | |||
14 | #ifdef WINDOWS | ||
15 | # include <windows.h> | ||
16 | # include <shellapi.h> | ||
17 | # define PRINTAPP "print" | ||
18 | # define popen _popen | ||
19 | # define pclose _pclose | ||
20 | #else | ||
21 | # include <unistd.h> | ||
22 | #endif | ||
23 | |||
24 | #include <string> | ||
25 | #include <sys/types.h> | ||
26 | #include <sys/stat.h> | ||
27 | #include <fcntl.h> | ||
28 | #include <stdio.h> | ||
29 | #include <stdlib.h> | ||
30 | #include <iostream> | ||
31 | #include <fstream> | ||
32 | #include <math.h> | ||
33 | #include <hd24devicenamegenerator.h> | ||
34 | #include <FL/FLTKstuff.H> | ||
35 | #include <FL/Fl_Preferences.H> | ||
36 | #include <FL/filename.H> | ||
37 | #include "convertlib.h" | ||
38 | #include "hd24utils.h" | ||
39 | #include "memutils.h" | ||
40 | #define _LARGE_FILES | ||
41 | #define LARGE_FILES | ||
42 | #define LARGEFILE64_SOURCE | ||
43 | #define _FILE_OFFSET_BITS 64 | ||
44 | #define FILE_OFFSET_BITS 64 | ||
45 | #define SECTORSIZE 512 | ||
46 | #define FSINFO_VERSION_MAJOR 0x8 | ||
47 | #define FSINFO_VERSION_MINOR 0x9 | ||
48 | #define FSINFO_BLOCKSIZE_IN_SECTORS 0x10 | ||
49 | #define FSINFO_AUDIOBLOCKS_PER_CLUSTER 0x14 | ||
50 | #define FSINFO_STARTSECTOR_FAT 0x38 | ||
51 | #define FSINFO_NUMSECTORS_FAT 0x3c | ||
52 | #define FSINFO_CLUSTERS_ON_DISK 0x44 | ||
53 | #define FSINFO_MAXPROJECTS 0x50 | ||
54 | #define FSINFO_MAXSONGSPERPROJECT 0x54 | ||
55 | #define FSINFO_DATAAREA 0x7c | ||
56 | #define DRIVEINFO_VOLUME 0x1b8 | ||
57 | #define DRIVEINFO_PROJECTCOUNT 0x0c | ||
58 | #define DRIVEINFO_LASTPROJ 0x10 | ||
59 | #define DRIVEINFO_PROJECTLIST 0x20 | ||
60 | |||
61 | void hd24utils::gencatalog_showsongs(hd24project* currentproj,string* strcatalog) | ||
62 | { | ||
63 | if (currentproj==NULL) { | ||
64 | return; | ||
65 | } | ||
66 | if (strcatalog==NULL) { | ||
67 | return; | ||
68 | } | ||
69 | int numsongs=currentproj->songcount(); | ||
70 | *strcatalog+=" ======================================================================\n"; | ||
71 | if (numsongs==0) { | ||
72 | *strcatalog+=" There are no songs in this project.\n"; | ||
73 | return; | ||
74 | } | ||
75 | hd24song* currsong=NULL; | ||
76 | for (int i=1; i<=numsongs; i++) { | ||
77 | currsong=currentproj->getsong(i); | ||
78 | if (currsong==NULL) continue; | ||
79 | |||
80 | *strcatalog+=" "; | ||
81 | *strcatalog+=" "; | ||
82 | if (i<10) { | ||
83 | *strcatalog+=" "; | ||
84 | } | ||
85 | string* songnum=Convert::int2str(i); | ||
86 | *strcatalog+=*songnum; | ||
87 | *strcatalog+=": "; | ||
88 | delete songnum; | ||
89 | |||
90 | string* currsname=currsong->songname(); | ||
91 | string* pad=Convert::padright(*currsname,35," "); | ||
92 | delete(currsname); | ||
93 | *strcatalog+=*pad; | ||
94 | delete pad; | ||
95 | string* dur=currsong->display_duration(); | ||
96 | *strcatalog+=*dur; | ||
97 | delete dur; | ||
98 | *strcatalog+= ", " ; | ||
99 | |||
100 | string* chans=Convert::int2str(currsong->logical_channels()); | ||
101 | string* chans2=Convert::padleft(*chans,2," "); | ||
102 | *strcatalog+=*chans; | ||
103 | delete chans; | ||
104 | delete chans2; | ||
105 | *strcatalog+="ch. "; | ||
106 | |||
107 | string* samrate=Convert::int2str(currsong->samplerate()); | ||
108 | *strcatalog+=*samrate; | ||
109 | delete samrate; | ||
110 | *strcatalog+=" Hz"; | ||
111 | |||
112 | |||
113 | if (currsong->iswriteprotected()) | ||
114 | { | ||
115 | *strcatalog+="*"; | ||
116 | } | ||
117 | |||
118 | *strcatalog+="\n"; | ||
119 | |||
120 | delete currsong; | ||
121 | currsong=NULL; | ||
122 | } | ||
123 | return; | ||
124 | } | ||
125 | |||
126 | void hd24utils::gencatalog_showprojects(hd24fs* currenthd24,string* strcatalog) | ||
127 | { | ||
128 | int numprojs=currenthd24->projectcount(); | ||
129 | hd24project* currproj=NULL; | ||
130 | for (int i=1; i<=numprojs; i++) | ||
131 | { | ||
132 | currproj=currenthd24->getproject(i); | ||
133 | |||
134 | *strcatalog+=" ======================================================================\n"; | ||
135 | *strcatalog+=" Project "; | ||
136 | string* projnum=Convert::int2str(i); | ||
137 | *strcatalog+=*projnum; | ||
138 | delete projnum; | ||
139 | *strcatalog+=": "; | ||
140 | |||
141 | string* currpname=currproj->projectname(); | ||
142 | *strcatalog+= *currpname; | ||
143 | delete(currpname); | ||
144 | |||
145 | *strcatalog+="\n"; // << endl; | ||
146 | gencatalog_showsongs (currproj,strcatalog); //to_out); | ||
147 | delete(currproj); | ||
148 | } | ||
149 | |||
150 | } | ||
151 | |||
152 | int hd24utils::gencatalog(hd24fs* currenthd24,string* strcatalog) | ||
153 | { | ||
154 | |||
155 | time_t currenttime; | ||
156 | struct tm timestamp; | ||
157 | char timebuf[80]; | ||
158 | time(¤ttime); | ||
159 | timestamp = *localtime(¤ttime); | ||
160 | strftime(timebuf,sizeof(timebuf),"%a %Y-%m-%d %H:%M:%S %Z", ×tamp); | ||
161 | *strcatalog+= " Catalog timestamp : "; | ||
162 | *strcatalog+= timebuf ; | ||
163 | *strcatalog+="\n"; | ||
164 | |||
165 | *strcatalog+=" Volume name : "; | ||
166 | string* volname=currenthd24->volumename(); | ||
167 | *strcatalog+=*volname; | ||
168 | delete volname; | ||
169 | *strcatalog+="\n"; | ||
170 | |||
171 | *strcatalog+=" Number of projects : "; | ||
172 | string* pcount=Convert::int2str(currenthd24->projectcount()); | ||
173 | *strcatalog+=*pcount; | ||
174 | delete pcount; | ||
175 | |||
176 | *strcatalog+="\n"; | ||
177 | gencatalog_showprojects(currenthd24,strcatalog); | ||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | string* hd24utils::savecatalog(hd24fs* currenthd24,string* filename) | ||
182 | { | ||
183 | string* error=new string(""); | ||
184 | |||
185 | // gencatalog | ||
186 | string* catalog=new string(""); | ||
187 | |||
188 | if (hd24utils::gencatalog(currenthd24,catalog)!=0) | ||
189 | { | ||
190 | *error+="Error generating catalog."; | ||
191 | return error; | ||
192 | } | ||
193 | fstream to_out(filename->c_str(),ios::out); | ||
194 | if (to_out==NULL) | ||
195 | { | ||
196 | *error+="Cannot write catalog."; | ||
197 | return error; | ||
198 | } | ||
199 | to_out << *catalog ; | ||
200 | |||
201 | to_out.flush(); | ||
202 | to_out.close(); | ||
203 | return NULL; | ||
204 | } | ||
205 | |||
206 | string* hd24utils::printcatalog(hd24fs* currenthd24) | ||
207 | { | ||
208 | |||
209 | string* error=new string(""); | ||
210 | string catname="_hd24cat.txt"; | ||
211 | |||
212 | |||
213 | // gencatalog | ||
214 | string* catalog=new string(""); | ||
215 | |||
216 | if (hd24utils::gencatalog(currenthd24,catalog)!=0) | ||
217 | { | ||
218 | *error+="Error generating catalog."; | ||
219 | return error; | ||
220 | } | ||
221 | fstream to_out(catname.c_str(),ios::out); | ||
222 | if (to_out==NULL) | ||
223 | { | ||
224 | *error+="Cannot write catalog."; | ||
225 | return error; | ||
226 | } | ||
227 | *catalog += "\f\n"; // form feed | ||
228 | to_out << *catalog ; | ||
229 | |||
230 | to_out.flush(); | ||
231 | to_out.close(); | ||
232 | |||
233 | #ifdef WINDOWS | ||
234 | SHELLEXECUTEINFO ShExecInfo = {0}; | ||
235 | ShExecInfo.cbSize = sizeof (SHELLEXECUTEINFO); | ||
236 | ShExecInfo.fMask = SEE_MASK_NOCLOSEPROCESS; //SEE_MASK_INVOKEIDLIST; | ||
237 | ShExecInfo.hwnd = NULL; | ||
238 | ShExecInfo.lpVerb="print"; | ||
239 | ShExecInfo.lpFile=catname.c_str(); | ||
240 | ShExecInfo.lpParameters = ""; | ||
241 | ShExecInfo.lpDirectory=NULL; | ||
242 | ShExecInfo.nShow = SW_HIDE; | ||
243 | ShExecInfo.hInstApp = NULL; | ||
244 | ShellExecuteEx(&ShExecInfo); | ||
245 | WaitForSingleObject(ShExecInfo.hProcess,INFINITE); | ||
246 | unlink (catname.c_str()); | ||
247 | #else | ||
248 | char s[1024]; | ||
249 | string* catcmd = new string (PRINTAPP); | ||
250 | *catcmd += " "; | ||
251 | *catcmd += catname; | ||
252 | *catcmd += " 2>&1"; | ||
253 | FILE *fp = popen(catcmd->c_str() , "r"); | ||
254 | while (fgets(s, sizeof(s)-1, fp)) | ||
255 | { | ||
256 | *error += s; | ||
257 | } | ||
258 | pclose(fp); | ||
259 | unlink (catname.c_str()); | ||
260 | #endif | ||
261 | return error; | ||
262 | } | ||
263 | |||
264 | |||
265 | void hd24utils::interlacetobuffer(unsigned char* sourcebuf,unsigned char* targetbuf, | ||
266 | __uint32 totbytes,__uint32 bytespersam,__uint32 trackwithingroup,__uint32 trackspergroup) | ||
267 | { | ||
268 | __uint32 samplenum; | ||
269 | __uint32 totsams=totbytes/bytespersam; | ||
270 | __uint32 trackoff=(trackwithingroup*bytespersam); | ||
271 | __uint32 q=0; | ||
272 | // unroll loop for bytespersam=1,2,3 | ||
273 | switch (bytespersam) | ||
274 | { | ||
275 | case 3: | ||
276 | for (samplenum=0;samplenum<totsams;samplenum++) | ||
277 | { | ||
278 | __uint32 samoff=(samplenum*bytespersam); | ||
279 | q=trackspergroup*samoff+trackoff; | ||
280 | targetbuf[q++]=sourcebuf[samoff]; | ||
281 | targetbuf[q++]=sourcebuf[samoff+1]; | ||
282 | targetbuf[q++]=sourcebuf[samoff+2]; | ||
283 | } | ||
284 | break; | ||
285 | case 1: | ||
286 | for (samplenum=0;samplenum<totsams;samplenum++) | ||
287 | { | ||
288 | __uint32 samoff=(samplenum*bytespersam); | ||
289 | q=trackspergroup*samoff+trackoff; | ||
290 | targetbuf[q]=sourcebuf[samoff]; | ||
291 | } | ||
292 | break; | ||
293 | case 2: | ||
294 | for (samplenum=0;samplenum<totsams;samplenum++) | ||
295 | { | ||
296 | __uint32 samoff=(samplenum*bytespersam); | ||
297 | q=trackspergroup*samoff+trackoff; | ||
298 | targetbuf[q++]=sourcebuf[samoff]; | ||
299 | targetbuf[q++]=sourcebuf[samoff+1]; | ||
300 | } | ||
301 | break; | ||
302 | default: | ||
303 | for (samplenum=0;samplenum<totsams;samplenum++) | ||
304 | { | ||
305 | __uint32 samoff=(samplenum*bytespersam); | ||
306 | q=trackspergroup*samoff; | ||
307 | for (__uint32 j=0; j<bytespersam; j++) { | ||
308 | targetbuf[q+j+trackoff]=sourcebuf[samoff+j]; | ||
309 | } | ||
310 | } | ||
311 | break; | ||
312 | } | ||
313 | } | ||
314 | |||
315 | bool hd24utils::dirExists(const char * pszDirName) | ||
316 | { | ||
317 | #ifdef WIN32 | ||
318 | unsigned int dwAttrs; | ||
319 | if (!(pszDirName)) | ||
320 | { | ||
321 | //setupLog(NULL, "DirExists failed: passed in NULL parameter for directory"); | ||
322 | return (1==0); | ||
323 | } | ||
324 | dwAttrs = GetFileAttributes(pszDirName); | ||
325 | if ((dwAttrs != 0xFFFFFFFF) && (dwAttrs & FILE_ATTRIBUTE_DIRECTORY)) | ||
326 | { | ||
327 | return (1==1); | ||
328 | } | ||
329 | return (1==0); | ||
330 | #else | ||
331 | struct stat fi; | ||
332 | |||
333 | if (stat (pszDirName, &fi) == -1 || !S_ISDIR(fi.st_mode)) | ||
334 | { | ||
335 | return (1==0); | ||
336 | } | ||
337 | else | ||
338 | { | ||
339 | return (1==1); | ||
340 | } | ||
341 | #endif | ||
342 | } | ||
343 | int hd24utils::savedrivesectors(hd24fs* currenthd24,string* outputfilename,unsigned long firstsector,unsigned long endsector,char* message,int* cancel) { | ||
344 | unsigned long i; | ||
345 | #define MULTISECTOR 100 | ||
346 | unsigned char bootblock[(MULTISECTOR+1)*512]; // 1 sector spare | ||
347 | memset(bootblock,0,MULTISECTOR*512); | ||
348 | #if defined(LINUX) || defined(DARWIN) | ||
349 | #if (UTILDEBUG==1) | ||
350 | cout << "creat64" << endl; | ||
351 | #endif | ||
352 | FSHANDLE handle=creat64(outputfilename->c_str(),O_WRONLY); | ||
353 | #endif | ||
354 | #ifdef WINDOWS | ||
355 | FSHANDLE handle=CreateFile(outputfilename->c_str(),GENERIC_WRITE|GENERIC_READ, | ||
356 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
357 | NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL); | ||
358 | if (hd24fs::isinvalidhandle(handle)) { | ||
359 | handle=CreateFile(outputfilename->c_str(),GENERIC_WRITE|GENERIC_READ, | ||
360 | FILE_SHARE_READ|FILE_SHARE_WRITE, | ||
361 | NULL,OPEN_ALWAYS,FILE_ATTRIBUTE_NORMAL,NULL); | ||
362 | } | ||
363 | |||
364 | #endif | ||
365 | if (hd24fs::isinvalidhandle(handle)) { | ||
366 | // cout << "Cannot open file "<<filename <<" for writing. Access denied?" << endl; | ||
367 | return 1; | ||
368 | } | ||
369 | int q=0; | ||
370 | for (i=firstsector;i<=endsector;i++) { | ||
371 | q++; | ||
372 | int numsectors=1; | ||
373 | if ((endsector-i) >=MULTISECTOR) { | ||
374 | numsectors=MULTISECTOR; | ||
375 | } | ||
376 | if (currenthd24!=NULL) { | ||
377 | currenthd24->readsector_noheader(currenthd24,i,bootblock); // raw reading | ||
378 | } | ||
379 | #if defined(LINUX) || defined(DARWIN) | ||
380 | __uint64 targetoff=i; | ||
381 | targetoff-=firstsector; | ||
382 | targetoff*=512; | ||
383 | ssize_t byteswritten=0; | ||
384 | if (currenthd24!=NULL) { | ||
385 | byteswritten=pwrite64(handle,bootblock,512,targetoff); | ||
386 | } else { | ||
387 | byteswritten=pwrite64(handle,bootblock,512*numsectors,targetoff); | ||
388 | i+=(numsectors-1); | ||
389 | } | ||
390 | #endif | ||
391 | #ifdef WINDOWS | ||
392 | //DWORD dummy; | ||
393 | //long bytes=0; | ||
394 | __uint64 targetoff=i; | ||
395 | targetoff-=firstsector; | ||
396 | __uint64 byteswritten=0; | ||
397 | if (currenthd24!=NULL) { | ||
398 | byteswritten=currenthd24->writesectors(handle,targetoff,bootblock,1); | ||
399 | } else { | ||
400 | byteswritten=currenthd24->writesectors(handle,targetoff,bootblock,numsectors); | ||
401 | i+=(numsectors-1); | ||
402 | } | ||
403 | #endif | ||
404 | if (byteswritten==0) { | ||
405 | #if defined(LINUX) || defined(DARWIN) | ||
406 | close (handle); | ||
407 | #endif | ||
408 | #ifdef WINDOWS | ||
409 | CloseHandle(handle); | ||
410 | #endif | ||
411 | return 1; | ||
412 | } | ||
413 | if (message!=NULL) { | ||
414 | if (q%1000==0) { | ||
415 | sprintf(message,"Saving sector %ld of %ld",i,(endsector+1)); | ||
416 | |||
417 | // cout << i << endl; | ||
418 | Fl::wait(0); | ||
419 | } | ||
420 | } | ||
421 | } | ||
422 | #if defined(LINUX) || defined(DARWIN) | ||
423 | close (handle); | ||
424 | chmod(outputfilename->c_str(),0664); | ||
425 | #endif | ||
426 | #ifdef WINDOWS | ||
427 | CloseHandle(handle); | ||
428 | #endif | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | int hd24utils::savedriveimage(hd24fs* currenthd24,string* imagefilename,char* message,int* cancel) { | ||
434 | unsigned long firstsector=0; | ||
435 | unsigned long endsector=currenthd24->getlastsectornum(); | ||
436 | return savedrivesectors(currenthd24,imagefilename,firstsector,endsector,message,cancel); | ||
437 | } | ||
438 | |||
439 | int hd24utils::newdriveimage(string* imagefilename,__uint32 endsector,char* message,int* cancel) { | ||
440 | if (endsector<1353964) | ||
441 | { | ||
442 | // requested drive size is less than possible minimum size | ||
443 | return -1; | ||
444 | } | ||
445 | |||
446 | unsigned long firstsector=0; | ||
447 | #if (UTILDEBUG==1) | ||
448 | cout << "about to save drive sectors" <<endl; | ||
449 | #endif | ||
450 | int result=savedrivesectors(NULL,imagefilename,firstsector,endsector,message,cancel); | ||
451 | if (result!=0) | ||
452 | { | ||
453 | return result; | ||
454 | } | ||
455 | #if (UTILDEBUG==1) | ||
456 | cout << "saved drive sectors, creating new fs object to format" <<endl; | ||
457 | #endif | ||
458 | hd24fs* newfs=new hd24fs((const char*)NULL,hd24fs::MODE_RDWR,imagefilename,true); | ||
459 | #if (UTILDEBUG==1) | ||
460 | cout << "write enabling fs" <<endl; | ||
461 | #endif | ||
462 | newfs->write_enable(); | ||
463 | #if (UTILDEBUG==1) | ||
464 | cout << "quickformatting fs" <<endl; | ||
465 | #endif | ||
466 | newfs->quickformat(message); | ||
467 | #if (UTILDEBUG==1) | ||
468 | cout << "format result=" << *message << endl; | ||
469 | cout << "deleting format fs object" <<endl; | ||
470 | #endif | ||
471 | delete newfs; | ||
472 | #if (UTILDEBUG==1) | ||
473 | cout << "destructed fs object" <<endl; | ||
474 | #endif | ||
475 | return 0; | ||
476 | } | ||
477 | |||
478 | void hd24utils::dumpsector(const char* buffer) | ||
479 | { | ||
480 | for (int i=0;i<512;i+=16) { | ||
481 | string* dummy=Convert::int32tohex(i); | ||
482 | cout << *dummy << " "; | ||
483 | delete dummy; dummy=NULL; | ||
484 | for (int j=0;j<16;j++) { | ||
485 | string* dummy= Convert::byte2hex(buffer[i+j]); | ||
486 | cout << *dummy; | ||
487 | if (j==7) { | ||
488 | cout << "-" ; | ||
489 | } else { | ||
490 | cout << " " ; | ||
491 | } | ||
492 | delete dummy; dummy=NULL; | ||
493 | } | ||
494 | cout << " "; | ||
495 | for (int j=0;j<16;j++) { | ||
496 | cout << Convert::safebyte(buffer[i+j]); | ||
497 | } | ||
498 | cout << "" << endl; | ||
499 | } | ||
500 | } | ||
501 | int hd24utils::saveheader(hd24fs* currenthd24,string* headerfilename) { | ||
502 | return savedrivesectors(currenthd24,headerfilename,0,0x700,NULL,NULL); | ||
503 | // TODO: 0x700 sectors is arbitrary. First song entry is at 0x77, | ||
504 | // total of 99*99 songs of 7 sectors each puts actual required length | ||
505 | // at 0x10c76. However, this has served fine so far. | ||
506 | |||
507 | } | ||
508 | |||
509 | void hd24utils::findfile(const char* rawname,const char* path,char* result) | ||
510 | { | ||
511 | string* strpath=new string(path); | ||
512 | #ifdef WINDOWS | ||
513 | string* pathsep=new string(";"); | ||
514 | #else | ||
515 | string* pathsep=new string(":"); | ||
516 | #endif | ||
517 | int last=0; | ||
518 | string* exename; | ||
519 | string* exepath; | ||
520 | #if (UTILDEBUG==1) | ||
521 | cout << "search path for exe " << endl; | ||
522 | #endif | ||
523 | while (last==0) | ||
524 | { | ||
525 | unsigned int idx=strpath->find(pathsep->c_str()); | ||
526 | if (idx==string::npos) { | ||
527 | last=1; | ||
528 | exepath=new string(strpath->c_str()); | ||
529 | exename=new string(strpath->c_str()); | ||
530 | *strpath=""; | ||
531 | } else { | ||
532 | exepath=new string(strpath->substr(0,idx)); | ||
533 | exename=new string(strpath->substr(0,idx)); | ||
534 | *strpath=strpath->substr(idx+1); | ||
535 | } | ||
536 | #if (UTILDEBUG==1) | ||
537 | cout << "exepath= " << *exepath << endl; | ||
538 | #endif | ||
539 | if (exepath->substr(exepath->length()-1,1)!=PATHSLASH) { | ||
540 | *exepath+=PATHSLASH; | ||
541 | } | ||
542 | if (exename->substr(exename->length()-1,1)!=PATHSLASH) { | ||
543 | *exename+=PATHSLASH; | ||
544 | } | ||
545 | |||
546 | *exename+=rawname; | ||
547 | #if (UTILDEBUG==1) | ||
548 | cout << "test if file " << exename->c_str() << " exists" << endl; | ||
549 | #endif | ||
550 | if (hd24utils::fileExists(exename->c_str())) { | ||
551 | strncpy(result,exepath->c_str(),2048); | ||
552 | if (exename!=NULL) { | ||
553 | delete exename; | ||
554 | exename=NULL; | ||
555 | } | ||
556 | if (exepath!=NULL) { | ||
557 | delete exepath; | ||
558 | exepath=NULL; | ||
559 | } | ||
560 | if (strpath!=NULL) { | ||
561 | delete strpath; | ||
562 | strpath=NULL; | ||
563 | } | ||
564 | if (pathsep!=NULL) { | ||
565 | delete pathsep; | ||
566 | pathsep=NULL; | ||
567 | } | ||
568 | return ; | ||
569 | } | ||
570 | if (exename!=NULL) { | ||
571 | delete exename; | ||
572 | exename=NULL; | ||
573 | } | ||
574 | if (exepath!=NULL) { | ||
575 | delete exepath; | ||
576 | exepath=NULL; | ||
577 | } | ||
578 | } | ||
579 | |||
580 | if (strpath!=NULL) { | ||
581 | delete strpath; | ||
582 | strpath=NULL; | ||
583 | } | ||
584 | if (pathsep!=NULL) { | ||
585 | delete pathsep; | ||
586 | pathsep=NULL; | ||
587 | } | ||
588 | |||
589 | result[0]=(char)0; | ||
590 | return; | ||
591 | } | ||
592 | |||
593 | bool hd24utils::fileExists(const char* strFilename) { | ||
594 | struct stat stFileInfo; | ||
595 | int intStat; | ||
596 | |||
597 | // Attempt to get the file attributes | ||
598 | intStat = stat(strFilename,&stFileInfo); | ||
599 | if(intStat == 0) | ||
600 | { | ||
601 | // We were able to get the file attributes | ||
602 | // so the file obviously exists. | ||
603 | return true; | ||
604 | } | ||
605 | // We were not able to get the file attributes. | ||
606 | // This may mean that we don't have permission to | ||
607 | // access the folder which contains this file. If you | ||
608 | // need to do that level of checking, lookup the | ||
609 | // return values of stat which will give you | ||
610 | // more details on why stat failed. | ||
611 | return false; | ||
612 | } | ||
613 | |||
614 | string* hd24utils::getlastdir(string which) | ||
615 | { | ||
616 | string* whichdir; | ||
617 | char buffer[FL_PATH_MAX]; | ||
618 | |||
619 | Fl_Preferences* userprefs=new Fl_Preferences(Fl_Preferences::USER, "HD24","HD24connect" ); | ||
620 | /* Attempt to find last used project dir */ | ||
621 | if (userprefs->entryExists(which.c_str())) { | ||
622 | userprefs->get(which.c_str(),buffer,".",FL_PATH_MAX); | ||
623 | whichdir=new string(buffer); | ||
624 | } else { | ||
625 | whichdir=new string("."); | ||
626 | } | ||
627 | delete userprefs; | ||
628 | return whichdir; | ||
629 | } | ||
630 | |||
631 | void hd24utils::setlastdir(string which,const char* newdir) | ||
632 | { | ||
633 | Fl_Preferences* userprefs=new Fl_Preferences(Fl_Preferences::USER, "HD24","HD24connect" ); | ||
634 | userprefs->set(which.c_str(),newdir); | ||
635 | // cout << "just set " << which << " to " << newdir << endl; | ||
636 | delete userprefs; | ||
637 | } | ||
diff --git a/src/lib/hd24utils.h b/src/lib/hd24utils.h new file mode 100755 index 0000000..b7a9fa7 --- /dev/null +++ b/src/lib/hd24utils.h | |||
@@ -0,0 +1,64 @@ | |||
1 | #ifndef __hd24utils_h__ | ||
2 | #define __hd24utils_h__ | ||
3 | #ifndef WINDOWS | ||
4 | #define PATHSLASH "/" | ||
5 | # include <sys/dir.h> | ||
6 | # include <dirent.h> | ||
7 | #else | ||
8 | #define PATHSLASH "\\" | ||
9 | # include <dir.h> | ||
10 | # include <windows.h> | ||
11 | # include <winioctl.h> | ||
12 | # define FSHANDLE HANDLE | ||
13 | # define FSHANDLE_INVALID INVALID_HANDLE_VALUE | ||
14 | #endif | ||
15 | |||
16 | #if defined(LINUX) || defined(DARWIN) | ||
17 | # define FSHANDLE int | ||
18 | # define FSHANDLE_INVALID -1 | ||
19 | #endif | ||
20 | |||
21 | #include <config.h> | ||
22 | #include <stdio.h> | ||
23 | #include <string> | ||
24 | #include <FL/FLTKstuff.H> | ||
25 | #include "convertlib.h" | ||
26 | #include "memutils.h" | ||
27 | #include <hd24fs.h> | ||
28 | |||
29 | using namespace std; | ||
30 | class hd24fs; | ||
31 | class hd24project; | ||
32 | class hd24song; | ||
33 | |||
34 | class hd24utils | ||
35 | { | ||
36 | friend class hd24fs; | ||
37 | friend class hd24project; | ||
38 | friend class hd24song; | ||
39 | private: | ||
40 | // static void savecatalog_showprojects(hd24fs* currenthd24,fstream & to_out); | ||
41 | // static void savecatalog_showsongs(hd24project* currentproj,fstream & to_out); | ||
42 | static void gencatalog_showprojects(hd24fs* currenthd24,string* strcatalog); | ||
43 | static void gencatalog_showsongs(hd24project* currentproj,string* strcatalog); | ||
44 | |||
45 | public: | ||
46 | // static int savecatalog(hd24fs* currenthd24,string* headerfilename,bool toprint); | ||
47 | // static int gencatalog(hd24fs* currenthd24,string* headerfilename,bool toprint); | ||
48 | static string* savecatalog(hd24fs* currenthd24,string* filename); | ||
49 | static void findfile(const char* rawfilename, const char* searchpath, char* result); | ||
50 | static int gencatalog(hd24fs* currenthd24,string* strcatalog); | ||
51 | static string* printcatalog(hd24fs* currenthd24); | ||
52 | static int saveheader(hd24fs* currenthd24,string* headerfilename); | ||
53 | static int savedriveimage(hd24fs* currenthd24,string* imagefilename, char* message,int* cancel); | ||
54 | static int newdriveimage(string* imagefilename,__uint32 endsector,char* message,int* cancel); | ||
55 | static int savedrivesectors(hd24fs* currenthd24,string* imagefilename,unsigned long startsector,unsigned long endsector,char* message,int* cancel); | ||
56 | static void interlacetobuffer(unsigned char* sourcebuf,unsigned char* targetbuf, __uint32 totbytes,__uint32 bytespersam,__uint32 trackwithingroup,__uint32 trackspergroup); | ||
57 | static bool dirExists(const char * pszDirName); | ||
58 | static bool fileExists(const char * filename); | ||
59 | static string* getlastdir(string which); | ||
60 | static void dumpsector (const char* buffer); | ||
61 | static void setlastdir(string which,const char* newdir); | ||
62 | }; | ||
63 | |||
64 | #endif | ||
diff --git a/src/lib/memutils.cpp b/src/lib/memutils.cpp new file mode 100644 index 0000000..e12b208 --- /dev/null +++ b/src/lib/memutils.cpp | |||
@@ -0,0 +1,27 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <iostream> | ||
3 | #include "memutils.h" | ||
4 | #define MEMDEBUG 0 | ||
5 | void* memutils::mymalloc(const char* wherefrom,__uint32 elcount,__uint32 elsize) | ||
6 | { | ||
7 | void* q=calloc(elcount,elsize); | ||
8 | #if (MEMDEBUG==1) | ||
9 | cout << "ALLOC: " << wherefrom | ||
10 | <<" allocated " | ||
11 | << elcount<<" bytes at " << q << endl; | ||
12 | #else | ||
13 | wherefrom=NULL; | ||
14 | #endif | ||
15 | return q; | ||
16 | } | ||
17 | |||
18 | void memutils::myfree(const char* wherefrom,void* freewhat) | ||
19 | { | ||
20 | #if (MEMDEBUG==1) | ||
21 | cout << "FREE: "<< wherefrom <<" free bytes at " << freewhat << endl; | ||
22 | #else | ||
23 | wherefrom=NULL; | ||
24 | #endif | ||
25 | free(freewhat); | ||
26 | } | ||
27 | |||
diff --git a/src/lib/memutils.h b/src/lib/memutils.h new file mode 100644 index 0000000..0798296 --- /dev/null +++ b/src/lib/memutils.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifndef __memutils_h__ | ||
2 | #define __memutils_h__ | ||
3 | |||
4 | using namespace std; | ||
5 | #include <config.h> | ||
6 | |||
7 | class memutils | ||
8 | { | ||
9 | public: | ||
10 | static void* mymalloc(const char* wherefrom,__uint32 elcount,__uint32 elsize); | ||
11 | static void myfree(const char* wherefrom,void* freewhat); | ||
12 | }; | ||
13 | |||
14 | #endif | ||
15 | |||
diff --git a/src/lib/nojack.cpp b/src/lib/nojack.cpp new file mode 100755 index 0000000..206557d --- /dev/null +++ b/src/lib/nojack.cpp | |||
@@ -0,0 +1,223 @@ | |||
1 | #include "nojack.h" | ||
2 | #ifndef NULL | ||
3 | #define NULL 0 | ||
4 | #endif | ||
5 | jack_client_t *jack_client_new (const char *client_name) { return NULL; }; | ||
6 | int jack_client_close (jack_client_t *client) { return 0; }; | ||
7 | int jack_client_name_size(void) { return 0; }; | ||
8 | int jack_internal_client_new (const char *client_name, const char *so_name, | ||
9 | const char *so_data) { return 0; }; | ||
10 | void jack_internal_client_close (const char *client_name) { return; } | ||
11 | int jack_is_realtime (jack_client_t *client) { return 0; } | ||
12 | void jack_on_shutdown (jack_client_t *client, void (*function)(void *arg), void *arg) { return; } | ||
13 | int jack_set_process_callback (jack_client_t *client, | ||
14 | JackProcessCallback process_callback, | ||
15 | void *arg) {return 0; } | ||
16 | int jack_set_thread_init_callback (jack_client_t *client, | ||
17 | JackThreadInitCallback thread_init_callback, | ||
18 | void *arg) { return 0;} | ||
19 | int jack_set_freewheel_callback (jack_client_t *client, | ||
20 | JackFreewheelCallback freewheel_callback, | ||
21 | void *arg) { return 0;} | ||
22 | int jack_set_freewheel(jack_client_t* client, int onoff) { return 0;} | ||
23 | |||
24 | int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes) {return 0;} | ||
25 | int jack_set_buffer_size_callback (jack_client_t *client, | ||
26 | JackBufferSizeCallback bufsize_callback, | ||
27 | void *arg) {return 0;}; | ||
28 | int jack_set_sample_rate_callback (jack_client_t *client, | ||
29 | JackSampleRateCallback srate_callback, | ||
30 | void *arg) { return 0;}; | ||
31 | int jack_transport_query(jack_client_t *x,__uint64* y) {return 0;} | ||
32 | int jack_set_port_registration_callback (jack_client_t *, | ||
33 | JackPortRegistrationCallback | ||
34 | registration_callback, void *arg) {return 0;}; | ||
35 | int jack_set_graph_order_callback (jack_client_t *, JackGraphOrderCallback graph_callback, void *) {return 0;}; | ||
36 | |||
37 | int jack_set_xrun_callback (jack_client_t *, JackXRunCallback xrun_callback, void *arg) { return 0;}; | ||
38 | int jack_activate (jack_client_t *client) {return 0;}; | ||
39 | int jack_deactivate (jack_client_t *client) {return 0;}; | ||
40 | jack_port_t *jack_port_register (jack_client_t *client, | ||
41 | const char *port_name, | ||
42 | const char *port_type, | ||
43 | unsigned long flags, | ||
44 | unsigned long buffer_size) { return NULL; } | ||
45 | int jack_port_unregister (jack_client_t *, jack_port_t *) { return 0; } | ||
46 | void *jack_port_get_buffer (jack_port_t *, jack_nframes_t) { return NULL;} | ||
47 | const char *jack_port_name (const jack_port_t *port) { return NULL; } | ||
48 | const char *jack_port_short_name (const jack_port_t *port) { return NULL; } | ||
49 | int jack_port_flags (const jack_port_t *port) { return 0;} | ||
50 | const char *jack_port_type (const jack_port_t *port) { return 0;} | ||
51 | |||
52 | int jack_port_is_mine (const jack_client_t *, const jack_port_t *port) {return 0;}; | ||
53 | |||
54 | int jack_port_connected (const jack_port_t *port); | ||
55 | int jack_port_connected_to (const jack_port_t *port, | ||
56 | const char *port_name); | ||
57 | const char **jack_port_get_connections (const jack_port_t *port); | ||
58 | const char **jack_port_get_all_connections (const jack_client_t *client, | ||
59 | const jack_port_t *port); | ||
60 | int jack_port_tie (jack_port_t *src, jack_port_t *dst); | ||
61 | int jack_port_untie (jack_port_t *port); | ||
62 | int jack_port_lock (jack_client_t *, jack_port_t *); | ||
63 | int jack_port_unlock (jack_client_t *, jack_port_t *); | ||
64 | jack_nframes_t jack_port_get_latency (jack_port_t *port); | ||
65 | jack_nframes_t jack_port_get_total_latency (jack_client_t *, | ||
66 | jack_port_t *port); | ||
67 | void jack_port_set_latency (jack_port_t *, jack_nframes_t); | ||
68 | int jack_port_set_name (jack_port_t *port, const char *port_name); | ||
69 | int jack_port_request_monitor (jack_port_t *port, int onoff); | ||
70 | int jack_port_ensure_monitor (jack_port_t *port, int onoff); | ||
71 | int jack_port_monitoring_input (jack_port_t *port); | ||
72 | int jack_connect (jack_client_t *, | ||
73 | const char *source_port, | ||
74 | const char *destination_port); | ||
75 | int jack_disconnect (jack_client_t *, | ||
76 | const char *source_port, | ||
77 | const char *destination_port); | ||
78 | int jack_port_disconnect (jack_client_t *, jack_port_t *); | ||
79 | int jack_port_name_size(void); | ||
80 | |||
81 | /** | ||
82 | * @return the maximum number of characters in a JACK port type name | ||
83 | * including the final NULL character. This value is a constant. | ||
84 | */ | ||
85 | int jack_port_type_size(void); | ||
86 | |||
87 | /** | ||
88 | * @return the sample rate of the jack system, as set by the user when | ||
89 | * jackd was started. | ||
90 | */ | ||
91 | jack_nframes_t jack_get_sample_rate (jack_client_t *); | ||
92 | |||
93 | /** | ||
94 | * @return the current maximum size that will ever be passed to the @a | ||
95 | * process_callback. It should only be used *before* the client has | ||
96 | * been activated. This size may change, clients that depend on it | ||
97 | * must register a @a bufsize_callback so they will be notified if it | ||
98 | * does. | ||
99 | * | ||
100 | * @see jack_set_buffer_size_callback() | ||
101 | */ | ||
102 | jack_nframes_t jack_get_buffer_size (jack_client_t *); | ||
103 | |||
104 | /** | ||
105 | * @param port_name_pattern A regular expression used to select | ||
106 | * ports by name. If NULL or of zero length, no selection based | ||
107 | * on name will be carried out. | ||
108 | * @param type_name_pattern A regular expression used to select | ||
109 | * ports by type. If NULL or of zero length, no selection based | ||
110 | * on type will be carried out. | ||
111 | * @param flags A value used to select ports by their flags. | ||
112 | * If zero, no selection based on flags will be carried out. | ||
113 | * | ||
114 | * @return a NULL-terminated array of ports that match the specified | ||
115 | * arguments. The caller is responsible for calling free(3) any | ||
116 | * non-NULL returned value. | ||
117 | * | ||
118 | * @see jack_port_name_size(), jack_port_type_size() | ||
119 | */ | ||
120 | const char **jack_get_ports (jack_client_t *, | ||
121 | const char *port_name_pattern, | ||
122 | const char *type_name_pattern, | ||
123 | unsigned long flags); | ||
124 | |||
125 | /** | ||
126 | * @return address of the jack_port_t named @a port_name. | ||
127 | * | ||
128 | * @see jack_port_name_size() | ||
129 | */ | ||
130 | jack_port_t *jack_port_by_name (jack_client_t *, const char *port_name); | ||
131 | |||
132 | /** | ||
133 | * @return address of the jack_port_t of a @a port_id. | ||
134 | */ | ||
135 | jack_port_t *jack_port_by_id (const jack_client_t *client, | ||
136 | jack_port_id_t port_id); | ||
137 | |||
138 | /** | ||
139 | * Old-style interface to become the timebase for the entire JACK | ||
140 | * subsystem. | ||
141 | * | ||
142 | * @deprecated This function still exists for compatibility with the | ||
143 | * earlier transport interface, but it does nothing. Instead, see | ||
144 | * transport.h and use jack_set_timebase_callback(). | ||
145 | * | ||
146 | * @return ENOSYS, function not implemented. | ||
147 | */ | ||
148 | int jack_engine_takeover_timebase (jack_client_t *); | ||
149 | |||
150 | /** | ||
151 | * @return the time in frames that has passed since the JACK server | ||
152 | * began the current process cycle. | ||
153 | */ | ||
154 | jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *); | ||
155 | |||
156 | /** | ||
157 | * @return an estimate of the current time in frames. This is a | ||
158 | * running counter, no significance should be attached to its value, | ||
159 | * but it can be compared to a previously returned value. | ||
160 | */ | ||
161 | jack_nframes_t jack_frame_time (const jack_client_t *); | ||
162 | |||
163 | /** | ||
164 | * @return the frame_time after the last processing of the graph | ||
165 | * this is only to be used from the process callback. | ||
166 | * | ||
167 | * This function can be used to put timestamps generated by | ||
168 | * jack_frame_time() in correlation to the current process cycle. | ||
169 | */ | ||
170 | jack_nframes_t jack_last_frame_time (const jack_client_t *client); | ||
171 | |||
172 | |||
173 | /** | ||
174 | * @return the current CPU load estimated by JACK. This is a running | ||
175 | * average of the time it takes to execute a full process cycle for | ||
176 | * all clients as a percentage of the real time available per cycle | ||
177 | * determined by the buffer size and sample rate. | ||
178 | */ | ||
179 | float jack_cpu_load (jack_client_t *client); | ||
180 | |||
181 | /** | ||
182 | * Set the directory in which the server is expected | ||
183 | * to have put its communication FIFOs. A client | ||
184 | * will need to call this before calling | ||
185 | * jack_client_new() if the server was started | ||
186 | * with arguments telling it to use a non-standard | ||
187 | * directory. | ||
188 | * | ||
189 | * @deprecated This function is deprecated. Don't use in new programs | ||
190 | * and remove it in old programs. | ||
191 | */ | ||
192 | void jack_set_server_dir (const char *path); | ||
193 | |||
194 | /** | ||
195 | * @return the pthread ID of the thread running the JACK client side | ||
196 | * code. | ||
197 | */ | ||
198 | pthread_t jack_client_thread_id (jack_client_t *); | ||
199 | |||
200 | /** | ||
201 | * Display JACK error message. | ||
202 | * | ||
203 | * Set via jack_set_error_function(), otherwise a JACK-provided | ||
204 | * default will print @a msg (plus a newline) to stderr. | ||
205 | * | ||
206 | * @param msg error message text (no newline at end). | ||
207 | */ | ||
208 | extern void (*jack_error_callback)(const char *msg); | ||
209 | |||
210 | /** | ||
211 | * Set the @ref jack_error_callback for error message display. | ||
212 | * | ||
213 | * The JACK library provides two built-in callbacks for this purpose: | ||
214 | * default_jack_error_callback() and silent_jack_error_callback(). | ||
215 | */ | ||
216 | void jack_set_error_function (void (*func)(const char *)); | ||
217 | __uint64 jack_get_current_transport_frame(void* client) { return 0; } | ||
218 | void jack_transport_stop (void * dummy) { return; }; | ||
219 | void jack_transport_start (void * dummy) { return; }; | ||
220 | void jack_transport_locate (void * dummy,int x) { return; }; | ||
221 | //void* jack_port_register (void* dummy,const void* dum2,int q,int y,int z) {return NULL;}; | ||
222 | #define JACK_DEFAULT_AUDIO_TYPE 0 | ||
223 | |||
diff --git a/src/lib/nojack.h b/src/lib/nojack.h new file mode 100755 index 0000000..6a8ab9b --- /dev/null +++ b/src/lib/nojack.h | |||
@@ -0,0 +1,467 @@ | |||
1 | /* | ||
2 | Copyright (C) 2001 Paul Davis | ||
3 | |||
4 | This program is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU Lesser General Public License as published by | ||
6 | the Free Software Foundation; either version 2.1 of the License, or | ||
7 | (at your option) any later version. | ||
8 | |||
9 | This program is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU Lesser General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU Lesser General Public License | ||
15 | along with this program; if not, write to the Free Software | ||
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | ||
17 | |||
18 | $Id: jack.h,v 1.64 2004/07/15 03:07:28 trutkin Exp $ | ||
19 | */ | ||
20 | |||
21 | #ifndef __jack_h__ | ||
22 | #define __jack_h__ | ||
23 | |||
24 | #include "config.h" | ||
25 | #define __int64 long long | ||
26 | #ifdef __cplusplus | ||
27 | extern "C" { | ||
28 | #endif | ||
29 | #define jack_client_t void | ||
30 | #define jack_nframes_t __uint64 | ||
31 | #define jack_position_t __uint64 | ||
32 | #define jack_default_audio_sample_t int | ||
33 | #define jack_port_t void* | ||
34 | #define JackPortIsOutput 0 | ||
35 | #define JackPortIsInput 0 | ||
36 | typedef int(*JackProcessCallback)(__uint64, int,void*); | ||
37 | #define JackThreadInitCallback void* | ||
38 | #define JackPortRegistrationCallback void* | ||
39 | #define JackGraphOrderCallback void* | ||
40 | #define JackXRunCallback void* | ||
41 | #define JackFreewheelCallback void* | ||
42 | #define JackBufferSizeCallback void* | ||
43 | #define JackSampleRateCallback void* | ||
44 | #define jack_port_id_t void* | ||
45 | #define jack_transport_state_t int | ||
46 | #define JackTransportStopped 0 | ||
47 | #define pthread_t void* | ||
48 | jack_client_t *jack_client_new (const char *client_name); | ||
49 | int jack_client_close (jack_client_t *client); | ||
50 | int jack_client_name_size(void); | ||
51 | int jack_internal_client_new (const char *client_name, const char *so_name, | ||
52 | const char *so_data); | ||
53 | void jack_internal_client_close (const char *client_name); | ||
54 | int jack_is_realtime (jack_client_t *client); | ||
55 | void jack_on_shutdown (jack_client_t *client, void (*function)(void *arg), void *arg) ; | ||
56 | int jack_set_process_callback (jack_client_t *client, | ||
57 | JackProcessCallback process_callback, | ||
58 | void *arg) ; | ||
59 | int jack_set_thread_init_callback (jack_client_t *client, | ||
60 | JackThreadInitCallback thread_init_callback, | ||
61 | void *arg) ; | ||
62 | int jack_set_freewheel_callback (jack_client_t *client, | ||
63 | JackFreewheelCallback freewheel_callback, | ||
64 | void *arg) ; | ||
65 | int jack_set_freewheel(jack_client_t* client, int onoff) ; | ||
66 | |||
67 | int jack_set_buffer_size (jack_client_t *client, jack_nframes_t nframes) ; | ||
68 | int jack_set_buffer_size_callback (jack_client_t *client, | ||
69 | JackBufferSizeCallback bufsize_callback, | ||
70 | void *arg); | ||
71 | int jack_set_sample_rate_callback (jack_client_t *client, | ||
72 | JackSampleRateCallback srate_callback, | ||
73 | void *arg); | ||
74 | int jack_transport_query(jack_client_t *x,__uint64* y); | ||
75 | int jack_set_port_registration_callback (jack_client_t *, | ||
76 | JackPortRegistrationCallback | ||
77 | registration_callback, void *arg) ; | ||
78 | int jack_set_graph_order_callback (jack_client_t *, JackGraphOrderCallback graph_callback, void *) ; | ||
79 | |||
80 | int jack_set_xrun_callback (jack_client_t *, JackXRunCallback xrun_callback, void *arg) ; | ||
81 | int jack_activate (jack_client_t *client) ; | ||
82 | int jack_deactivate (jack_client_t *client) ; | ||
83 | jack_port_t *jack_port_register (jack_client_t *client, | ||
84 | const char *port_name, | ||
85 | const char *port_type, | ||
86 | unsigned long flags, | ||
87 | unsigned long buffer_size) ; | ||
88 | int jack_port_unregister (jack_client_t *, jack_port_t *) ; | ||
89 | void *jack_port_get_buffer (jack_port_t *, jack_nframes_t) ; | ||
90 | const char *jack_port_name (const jack_port_t *port) ; | ||
91 | const char *jack_port_short_name (const jack_port_t *port) ; | ||
92 | int jack_port_flags (const jack_port_t *port) ; | ||
93 | const char *jack_port_type (const jack_port_t *port) ; | ||
94 | |||
95 | int jack_port_is_mine (const jack_client_t *, const jack_port_t *port) ; | ||
96 | |||
97 | /** | ||
98 | * @return number of connections to or from @a port. | ||
99 | * | ||
100 | * @pre The calling client must own @a port. | ||
101 | */ | ||
102 | int jack_port_connected (const jack_port_t *port); | ||
103 | |||
104 | /** | ||
105 | * @return TRUE if the locally-owned @a port is @b directly connected | ||
106 | * to the @a port_name. | ||
107 | * | ||
108 | * @see jack_port_name_size() | ||
109 | */ | ||
110 | int jack_port_connected_to (const jack_port_t *port, | ||
111 | const char *port_name); | ||
112 | |||
113 | /** | ||
114 | * @return a null-terminated array of full port names to which the @a | ||
115 | * port is connected. If none, returns NULL. | ||
116 | * | ||
117 | * The caller is responsible for calling free(3) on any non-NULL | ||
118 | * returned value. | ||
119 | * | ||
120 | * @param port locally owned jack_port_t pointer. | ||
121 | * | ||
122 | * @see jack_port_name_size(), jack_port_get_all_connections() | ||
123 | */ | ||
124 | const char **jack_port_get_connections (const jack_port_t *port); | ||
125 | |||
126 | /** | ||
127 | * @return a null-terminated array of full port names to which the @a | ||
128 | * port is connected. If none, returns NULL. | ||
129 | * | ||
130 | * The caller is responsible for calling free(3) on any non-NULL | ||
131 | * returned value. | ||
132 | * | ||
133 | * This differs from jack_port_get_connections() in two important | ||
134 | * respects: | ||
135 | * | ||
136 | * 1) You may not call this function from code that is | ||
137 | * executed in response to a JACK event. For example, | ||
138 | * you cannot use it in a GraphReordered handler. | ||
139 | * | ||
140 | * 2) You need not be the owner of the port to get information | ||
141 | * about its connections. | ||
142 | * | ||
143 | * @see jack_port_name_size() | ||
144 | */ | ||
145 | const char **jack_port_get_all_connections (const jack_client_t *client, | ||
146 | const jack_port_t *port); | ||
147 | |||
148 | /** | ||
149 | * A client may call this on a pair of its own ports to | ||
150 | * semi-permanently wire them together. This means that | ||
151 | * a client that wants to direct-wire an input port to | ||
152 | * an output port can call this and then no longer | ||
153 | * have to worry about moving data between them. Any data | ||
154 | * arriving at the input port will appear automatically | ||
155 | * at the output port. | ||
156 | * | ||
157 | * The 'destination' port must be an output port. The 'source' | ||
158 | * port must be an input port. Both ports must belong to | ||
159 | * the same client. You cannot use this to tie ports between | ||
160 | * clients. That is what a connection is for. | ||
161 | * | ||
162 | * @return 0 on success, otherwise a non-zero error code | ||
163 | */ | ||
164 | int jack_port_tie (jack_port_t *src, jack_port_t *dst); | ||
165 | |||
166 | /** | ||
167 | * This undoes the effect of jack_port_tie(). The port | ||
168 | * should be same as the 'destination' port passed to | ||
169 | * jack_port_tie(). | ||
170 | * | ||
171 | * @return 0 on success, otherwise a non-zero error code | ||
172 | */ | ||
173 | int jack_port_untie (jack_port_t *port); | ||
174 | |||
175 | /** | ||
176 | * A client may call this function to prevent other objects | ||
177 | * from changing the connection status of a port. The port | ||
178 | * must be owned by the calling client. | ||
179 | * | ||
180 | * @return 0 on success, otherwise a non-zero error code | ||
181 | */ | ||
182 | int jack_port_lock (jack_client_t *, jack_port_t *); | ||
183 | |||
184 | /** | ||
185 | * This allows other objects to change the connection status of a port. | ||
186 | * | ||
187 | * @return 0 on success, otherwise a non-zero error code | ||
188 | */ | ||
189 | int jack_port_unlock (jack_client_t *, jack_port_t *); | ||
190 | |||
191 | /** | ||
192 | * @return the time (in frames) between data being available or | ||
193 | * delivered at/to a port, and the time at which it arrived at or is | ||
194 | * delivered to the "other side" of the port. E.g. for a physical | ||
195 | * audio output port, this is the time between writing to the port and | ||
196 | * when the signal will leave the connector. For a physical audio | ||
197 | * input port, this is the time between the sound arriving at the | ||
198 | * connector and the corresponding frames being readable from the | ||
199 | * port. | ||
200 | */ | ||
201 | jack_nframes_t jack_port_get_latency (jack_port_t *port); | ||
202 | |||
203 | /** | ||
204 | * The maximum of the sum of the latencies in every | ||
205 | * connection path that can be drawn between the port and other | ||
206 | * ports with the @ref JackPortIsTerminal flag set. | ||
207 | */ | ||
208 | jack_nframes_t jack_port_get_total_latency (jack_client_t *, | ||
209 | jack_port_t *port); | ||
210 | |||
211 | /** | ||
212 | * The port latency is zero by default. Clients that control | ||
213 | * physical hardware with non-zero latency should call this | ||
214 | * to set the latency to its correct value. Note that the value | ||
215 | * should include any systemic latency present "outside" the | ||
216 | * physical hardware controlled by the client. For example, | ||
217 | * for a client controlling a digital audio interface connected | ||
218 | * to an external digital converter, the latency setting should | ||
219 | * include both buffering by the audio interface *and* the converter. | ||
220 | */ | ||
221 | void jack_port_set_latency (jack_port_t *, jack_nframes_t); | ||
222 | |||
223 | /** | ||
224 | * Modify a port's short name. May be called at any time. If the | ||
225 | * resulting full name (including the @a "client_name:" prefix) is | ||
226 | * longer than jack_port_name_size(), it will be truncated. | ||
227 | * | ||
228 | * @return 0 on success, otherwise a non-zero error code. | ||
229 | */ | ||
230 | int jack_port_set_name (jack_port_t *port, const char *port_name); | ||
231 | |||
232 | /** | ||
233 | * If @ref JackPortCanMonitor is set for this @a port, turn input | ||
234 | * monitoring on or off. Otherwise, do nothing. | ||
235 | */ | ||
236 | int jack_port_request_monitor (jack_port_t *port, int onoff); | ||
237 | |||
238 | /** | ||
239 | * If @ref JackPortCanMonitor is set for this @a port_name, turn input | ||
240 | * monitoring on or off. Otherwise, do nothing. | ||
241 | * | ||
242 | * @return 0 on success, otherwise a non-zero error code. | ||
243 | * | ||
244 | * @see jack_port_name_size() | ||
245 | */ | ||
246 | int jack_port_request_monitor_by_name (jack_client_t *client, | ||
247 | const char *port_name, int onoff); | ||
248 | |||
249 | /** | ||
250 | * If @ref JackPortCanMonitor is set for a port, this function turns | ||
251 | * on input monitoring if it was off, and turns it off if only one | ||
252 | * request has been made to turn it on. Otherwise it does nothing. | ||
253 | * | ||
254 | * @return 0 on success, otherwise a non-zero error code | ||
255 | */ | ||
256 | int jack_port_ensure_monitor (jack_port_t *port, int onoff); | ||
257 | |||
258 | /** | ||
259 | * @return TRUE if input monitoring has been requested for @a port. | ||
260 | */ | ||
261 | int jack_port_monitoring_input (jack_port_t *port); | ||
262 | |||
263 | /** | ||
264 | * Establish a connection between two ports. | ||
265 | * | ||
266 | * When a connection exists, data written to the source port will | ||
267 | * be available to be read at the destination port. | ||
268 | * | ||
269 | * @pre The port types must be identical. | ||
270 | * | ||
271 | * @pre The @ref JackPortFlags of the @a source_port must include @ref | ||
272 | * JackPortIsOutput. | ||
273 | * | ||
274 | * @pre The @ref JackPortFlags of the @a destination_port must include | ||
275 | * @ref JackPortIsInput. | ||
276 | * | ||
277 | * @return 0 on success, EEXIST if the connection is already made, | ||
278 | * otherwise a non-zero error code | ||
279 | */ | ||
280 | int jack_connect (jack_client_t *, | ||
281 | const char *source_port, | ||
282 | const char *destination_port); | ||
283 | |||
284 | /** | ||
285 | * Remove a connection between two ports. | ||
286 | * | ||
287 | * @pre The port types must be identical. | ||
288 | * | ||
289 | * @pre The @ref JackPortFlags of the @a source_port must include @ref | ||
290 | * JackPortIsOutput. | ||
291 | * | ||
292 | * @pre The @ref JackPortFlags of the @a destination_port must include | ||
293 | * @ref JackPortIsInput. | ||
294 | * | ||
295 | * @return 0 on success, otherwise a non-zero error code | ||
296 | */ | ||
297 | int jack_disconnect (jack_client_t *, | ||
298 | const char *source_port, | ||
299 | const char *destination_port); | ||
300 | |||
301 | /** | ||
302 | * Perform the same function as jack_disconnect() using port handles | ||
303 | * rather than names. This avoids the name lookup inherent in the | ||
304 | * name-based version. | ||
305 | * | ||
306 | * Clients connecting their own ports are likely to use this function, | ||
307 | * while generic connection clients (e.g. patchbays) would use | ||
308 | * jack_disconnect(). | ||
309 | */ | ||
310 | int jack_port_disconnect (jack_client_t *, jack_port_t *); | ||
311 | |||
312 | /** | ||
313 | * @return the maximum number of characters in a full JACK port name | ||
314 | * including the final NULL character. This value is a constant. | ||
315 | * | ||
316 | * A port's full name contains the owning client name concatenated | ||
317 | * with a colon (:) followed by its short name and a NULL | ||
318 | * character. | ||
319 | */ | ||
320 | int jack_port_name_size(void); | ||
321 | |||
322 | /** | ||
323 | * @return the maximum number of characters in a JACK port type name | ||
324 | * including the final NULL character. This value is a constant. | ||
325 | */ | ||
326 | int jack_port_type_size(void); | ||
327 | |||
328 | /** | ||
329 | * @return the sample rate of the jack system, as set by the user when | ||
330 | * jackd was started. | ||
331 | */ | ||
332 | jack_nframes_t jack_get_sample_rate (jack_client_t *); | ||
333 | |||
334 | /** | ||
335 | * @return the current maximum size that will ever be passed to the @a | ||
336 | * process_callback. It should only be used *before* the client has | ||
337 | * been activated. This size may change, clients that depend on it | ||
338 | * must register a @a bufsize_callback so they will be notified if it | ||
339 | * does. | ||
340 | * | ||
341 | * @see jack_set_buffer_size_callback() | ||
342 | */ | ||
343 | jack_nframes_t jack_get_buffer_size (jack_client_t *); | ||
344 | |||
345 | /** | ||
346 | * @param port_name_pattern A regular expression used to select | ||
347 | * ports by name. If NULL or of zero length, no selection based | ||
348 | * on name will be carried out. | ||
349 | * @param type_name_pattern A regular expression used to select | ||
350 | * ports by type. If NULL or of zero length, no selection based | ||
351 | * on type will be carried out. | ||
352 | * @param flags A value used to select ports by their flags. | ||
353 | * If zero, no selection based on flags will be carried out. | ||
354 | * | ||
355 | * @return a NULL-terminated array of ports that match the specified | ||
356 | * arguments. The caller is responsible for calling free(3) any | ||
357 | * non-NULL returned value. | ||
358 | * | ||
359 | * @see jack_port_name_size(), jack_port_type_size() | ||
360 | */ | ||
361 | const char **jack_get_ports (jack_client_t *, | ||
362 | const char *port_name_pattern, | ||
363 | const char *type_name_pattern, | ||
364 | unsigned long flags); | ||
365 | |||
366 | /** | ||
367 | * @return address of the jack_port_t named @a port_name. | ||
368 | * | ||
369 | * @see jack_port_name_size() | ||
370 | */ | ||
371 | jack_port_t *jack_port_by_name (jack_client_t *, const char *port_name); | ||
372 | |||
373 | /** | ||
374 | * @return address of the jack_port_t of a @a port_id. | ||
375 | */ | ||
376 | jack_port_t *jack_port_by_id (const jack_client_t *client, | ||
377 | jack_port_id_t port_id); | ||
378 | |||
379 | /** | ||
380 | * Old-style interface to become the timebase for the entire JACK | ||
381 | * subsystem. | ||
382 | * | ||
383 | * @deprecated This function still exists for compatibility with the | ||
384 | * earlier transport interface, but it does nothing. Instead, see | ||
385 | * transport.h and use jack_set_timebase_callback(). | ||
386 | * | ||
387 | * @return ENOSYS, function not implemented. | ||
388 | */ | ||
389 | int jack_engine_takeover_timebase (jack_client_t *); | ||
390 | |||
391 | /** | ||
392 | * @return the time in frames that has passed since the JACK server | ||
393 | * began the current process cycle. | ||
394 | */ | ||
395 | jack_nframes_t jack_frames_since_cycle_start (const jack_client_t *); | ||
396 | |||
397 | /** | ||
398 | * @return an estimate of the current time in frames. This is a | ||
399 | * running counter, no significance should be attached to its value, | ||
400 | * but it can be compared to a previously returned value. | ||
401 | */ | ||
402 | jack_nframes_t jack_frame_time (const jack_client_t *); | ||
403 | |||
404 | /** | ||
405 | * @return the frame_time after the last processing of the graph | ||
406 | * this is only to be used from the process callback. | ||
407 | * | ||
408 | * This function can be used to put timestamps generated by | ||
409 | * jack_frame_time() in correlation to the current process cycle. | ||
410 | */ | ||
411 | jack_nframes_t jack_last_frame_time (const jack_client_t *client); | ||
412 | |||
413 | |||
414 | /** | ||
415 | * @return the current CPU load estimated by JACK. This is a running | ||
416 | * average of the time it takes to execute a full process cycle for | ||
417 | * all clients as a percentage of the real time available per cycle | ||
418 | * determined by the buffer size and sample rate. | ||
419 | */ | ||
420 | float jack_cpu_load (jack_client_t *client); | ||
421 | |||
422 | /** | ||
423 | * Set the directory in which the server is expected | ||
424 | * to have put its communication FIFOs. A client | ||
425 | * will need to call this before calling | ||
426 | * jack_client_new() if the server was started | ||
427 | * with arguments telling it to use a non-standard | ||
428 | * directory. | ||
429 | * | ||
430 | * @deprecated This function is deprecated. Don't use in new programs | ||
431 | * and remove it in old programs. | ||
432 | */ | ||
433 | void jack_set_server_dir (const char *path); | ||
434 | |||
435 | /** | ||
436 | * @return the pthread ID of the thread running the JACK client side | ||
437 | * code. | ||
438 | */ | ||
439 | pthread_t jack_client_thread_id (jack_client_t *); | ||
440 | |||
441 | /** | ||
442 | * Display JACK error message. | ||
443 | * | ||
444 | * Set via jack_set_error_function(), otherwise a JACK-provided | ||
445 | * default will print @a msg (plus a newline) to stderr. | ||
446 | * | ||
447 | * @param msg error message text (no newline at end). | ||
448 | */ | ||
449 | extern void (*jack_error_callback)(const char *msg); | ||
450 | |||
451 | /** | ||
452 | * Set the @ref jack_error_callback for error message display. | ||
453 | * | ||
454 | * The JACK library provides two built-in callbacks for this purpose: | ||
455 | * default_jack_error_callback() and silent_jack_error_callback(). | ||
456 | */ | ||
457 | void jack_set_error_function (void (*func)(const char *)); | ||
458 | __uint64 jack_get_current_transport_frame(void* client) ; | ||
459 | void jack_transport_stop (void * dummy) ; | ||
460 | void jack_transport_start (void * dummy) ; | ||
461 | void jack_transport_locate (void * dummy,int x) ; | ||
462 | #define JACK_DEFAULT_AUDIO_TYPE 0 | ||
463 | #ifdef __cplusplus | ||
464 | } | ||
465 | #endif | ||
466 | |||
467 | #endif /* __jack_h__ */ | ||
diff --git a/src/lib/portwin.h b/src/lib/portwin.h new file mode 100644 index 0000000..14c85b1 --- /dev/null +++ b/src/lib/portwin.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifdef LINUX | ||
2 | #include <FL/x.H> //dave | ||
3 | #include <X11/xpm.h> //dave | ||
4 | |||
5 | #endif | ||
6 | |||
diff --git a/src/lib/sharedlibs.cpp b/src/lib/sharedlibs.cpp new file mode 100644 index 0000000..32e5fd8 --- /dev/null +++ b/src/lib/sharedlibs.cpp | |||
@@ -0,0 +1,332 @@ | |||
1 | #include <sharedlibs.h> | ||
2 | #include <FL/fl_message.H> | ||
3 | void SmartLoader::SmartFind(const char* filename,const char* absprogpath,char* result) | ||
4 | { | ||
5 | /* Find the given file in a clever way: | ||
6 | * Search the given path first | ||
7 | * (on the Mac, perhaps recursively) | ||
8 | * Then the environment PATH variable | ||
9 | * and finally any predefined library paths */ | ||
10 | result[0]=(char)0; | ||
11 | hd24utils::findfile(filename,absprogpath,result); | ||
12 | if (strlen(result)!=0) | ||
13 | { | ||
14 | // found it already | ||
15 | return; | ||
16 | } | ||
17 | |||
18 | hd24utils::findfile(filename,getenv("PATH"),result); | ||
19 | if (strlen(result)!=0) | ||
20 | { | ||
21 | // found it already | ||
22 | return; | ||
23 | } | ||
24 | |||
25 | hd24utils::findfile(filename,DEFAULTLIBPATH,result); | ||
26 | if (strlen(result)!=0) | ||
27 | { | ||
28 | // found it already | ||
29 | return; | ||
30 | } | ||
31 | return; | ||
32 | }; | ||
33 | |||
34 | PortAudioWrapper::PortAudioWrapper(char* absprogpath) | ||
35 | { | ||
36 | libloaded=false; | ||
37 | Pa_Initialize=NULL; | ||
38 | Pa_Terminate=NULL; | ||
39 | char result[2048]; | ||
40 | SmartFind(LIBFILE_PORTAUDIO,absprogpath,&result[0]); | ||
41 | |||
42 | string abslib=""; | ||
43 | abslib+=result; | ||
44 | abslib+=LIBFILE_PORTAUDIO; | ||
45 | #if (RECORDERDEBUG==1) | ||
46 | cout << "Opening from smartpath: " << abslib.c_str() << endl; | ||
47 | #endif | ||
48 | |||
49 | LIBHANDLE_T* handle=dlopen(abslib.c_str(),RTLD_NOW); | ||
50 | if (handle==NULL) { | ||
51 | #if (RECORDERDEBUG==1) | ||
52 | cout << "Fail. Opening from default path instead." << endl; | ||
53 | #endif | ||
54 | |||
55 | handle=dlopen(LIBFILE_PORTAUDIO,RTLD_NOW); | ||
56 | if (handle==NULL) { | ||
57 | #if (RECORDERDEBUG==1) | ||
58 | cout << dlerror() << endl; | ||
59 | #endif | ||
60 | } else { | ||
61 | #if (RECORDERDEBUG==1) | ||
62 | cout << dlerror() << endl; | ||
63 | cout << "Defining functions from default path." << endl; | ||
64 | #endif | ||
65 | define_functions(handle); | ||
66 | |||
67 | } | ||
68 | } else { | ||
69 | #if (RECORDERDEBUG==1) | ||
70 | cout << "Defining functions from smart path." << endl; | ||
71 | #endif | ||
72 | |||
73 | define_functions(handle); | ||
74 | } | ||
75 | } | ||
76 | |||
77 | PortAudioWrapper::~PortAudioWrapper() | ||
78 | { | ||
79 | if (libhandle!=NULL) | ||
80 | { | ||
81 | dlclose(libhandle); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | void PortAudioWrapper::define_functions(LIBHANDLE_T* handle) | ||
86 | { | ||
87 | if (handle==NULL) return; | ||
88 | libhandle=handle; | ||
89 | libloaded=false; | ||
90 | // Given a handle to a dynamic library, define functions that are in it. | ||
91 | |||
92 | #if (RECORDERDEBUG==1) | ||
93 | cout << "Define Pa_Initialize..." << endl; | ||
94 | #endif | ||
95 | Pa_Initialize=(PaError (*)(void))dlsym(handle,"Pa_Initialize"); | ||
96 | |||
97 | if (Pa_Initialize==NULL) { fl_message("Error loading Pa_Initialize"); return; } | ||
98 | #if (RECORDERDEBUG==1) | ||
99 | cout << "Define Pa_Terminate..." << endl; | ||
100 | #endif | ||
101 | |||
102 | |||
103 | Pa_Terminate=(PaError (*)(void))dlsym(handle,"Pa_Terminate"); | ||
104 | if (Pa_Terminate==NULL) { fl_message("Error loading Pa_Terminate"); return; } | ||
105 | |||
106 | #if (RECORDERDEBUG==1) | ||
107 | cout << "Define Pa_StartStream..." << endl; | ||
108 | #endif | ||
109 | |||
110 | Pa_StartStream=(PaError (*)(PaStream*))dlsym(handle,"Pa_StartStream"); | ||
111 | if (Pa_StartStream==NULL) { fl_message("Error loading Pa_StartStream"); return; } | ||
112 | |||
113 | #if (RECORDERDEBUG==1) | ||
114 | cout << "Define Pa_StopStream..." << endl; | ||
115 | #endif | ||
116 | |||
117 | Pa_StopStream=(PaError (*)(PaStream*))dlsym(handle,"Pa_StopStream"); | ||
118 | if (Pa_StopStream==NULL) { fl_message("Error loading Pa_StopStream"); return; } | ||
119 | |||
120 | #if (RECORDERDEBUG==1) | ||
121 | cout << "Define Pa_AbortStream..." << endl; | ||
122 | #endif | ||
123 | |||
124 | Pa_AbortStream=(PaError (*)(PaStream*))dlsym(handle,"Pa_AbortStream"); | ||
125 | if (Pa_AbortStream==NULL) { fl_message("Error loading Pa_AbortStream"); return; } | ||
126 | |||
127 | #if (RECORDERDEBUG==1) | ||
128 | cout << "Define Pa_CloseStream..." << endl; | ||
129 | #endif | ||
130 | |||
131 | Pa_CloseStream=(PaError (*)(PaStream*))dlsym(handle,"Pa_CloseStream"); | ||
132 | if (Pa_CloseStream==NULL) { fl_message("Error loading Pa_CloseStream"); return; } | ||
133 | |||
134 | #if (RECORDERDEBUG==1) | ||
135 | cout << "Define Pa_GetStreamTime..." << endl; | ||
136 | #endif | ||
137 | |||
138 | Pa_GetStreamTime=(PaTime (*)(PaStream*))dlsym(handle,"Pa_GetStreamTime"); | ||
139 | if (Pa_GetStreamTime==NULL) { fl_message("Error loading Pa_GetStreamTime"); return; } | ||
140 | |||
141 | #if (RECORDERDEBUG==1) | ||
142 | cout << "Define Pa_StreamActive..." << endl; | ||
143 | #endif | ||
144 | |||
145 | Pa_StreamActive=(PaError (*)(PaStream*))dlsym(handle,"Pa_IsStreamActive"); | ||
146 | if (Pa_StreamActive==NULL) { | ||
147 | Pa_StreamActive=(PaError (*)(PaStream*))dlsym(handle,"Pa_StreamActive"); | ||
148 | } | ||
149 | if (Pa_StreamActive==NULL) { | ||
150 | fl_message("Error loading Pa_StreamActive"); return; | ||
151 | } | ||
152 | |||
153 | #if (RECORDERDEBUG==1) | ||
154 | cout << "Define Pa_OpenStream..." << endl; | ||
155 | #endif | ||
156 | Pa_OpenStream=(PaError (*)(PaStream**, | ||
157 | const PaStreamParameters*, | ||
158 | const PaStreamParameters*, | ||
159 | double, | ||
160 | unsigned long, | ||
161 | PaStreamFlags, | ||
162 | PaStreamCallback*, | ||
163 | void*))dlsym(handle,"Pa_OpenStream"); | ||
164 | |||
165 | if (Pa_OpenStream==NULL) { fl_message("Error loading Pa_OpenStream"); return; } | ||
166 | |||
167 | #if (RECORDERDEBUG==1) | ||
168 | cout << "Define Pa_GetDeviceCount..." << endl; | ||
169 | #endif | ||
170 | |||
171 | Pa_GetDeviceCount=(int (*)(void))dlsym(handle,"Pa_GetDeviceCount"); | ||
172 | if (Pa_GetDeviceCount==NULL) { fl_message("Error loading Pa_GetDeviceCount"); return; } | ||
173 | |||
174 | #if (RECORDERDEBUG==1) | ||
175 | cout << "Define Pa_GetDeviceInfo..." << endl; | ||
176 | #endif | ||
177 | |||
178 | Pa_GetDeviceInfo=(const PaDeviceInfo* (*)(int))dlsym(handle,"Pa_GetDeviceInfo"); | ||
179 | if (Pa_GetDeviceInfo==NULL) { fl_message("Error loading Pa_GetDeviceInfo"); return; } | ||
180 | |||
181 | #if (RECORDERDEBUG==1) | ||
182 | cout << "Define Pa_GetDefaultInputDevice..." << endl; | ||
183 | #endif | ||
184 | |||
185 | Pa_GetDefaultInputDevice=(PaDeviceIndex (*)(void))dlsym(handle,"Pa_GetDefaultInputDevice"); | ||
186 | if (Pa_GetDefaultInputDevice==NULL) { fl_message("Error loading Pa_GetDefaultInputDevice"); return; } | ||
187 | |||
188 | #if (RECORDERDEBUG==1) | ||
189 | cout << "Define Pa_GetDefaultOutputDevice..." << endl; | ||
190 | #endif | ||
191 | |||
192 | Pa_GetDefaultOutputDevice=(PaDeviceIndex (*)(void))dlsym(handle,"Pa_GetDefaultOutputDevice"); | ||
193 | if (Pa_GetDefaultOutputDevice==NULL) { fl_message("Error loading Pa_GetDefaultOutputDevice"); return; } | ||
194 | |||
195 | #if (RECORDERDEBUG==1) | ||
196 | cout << "Define Pa_GetVersionText..." << endl; | ||
197 | #endif | ||
198 | |||
199 | Pa_GetVersionText=(const char* (*)(void))dlsym(handle,"Pa_GetVersionText"); | ||
200 | |||
201 | #if (RECORDERDEBUG==1) | ||
202 | cout << "Define Pa_GetErrorText..." << endl; | ||
203 | #endif | ||
204 | |||
205 | Pa_GetErrorText=(const char* (*)(PaError))dlsym(handle,"Pa_GetErrorText"); | ||
206 | |||
207 | #if (RECORDERDEBUG==1) | ||
208 | PaError initerror=(*(this->Pa_Initialize))(); | ||
209 | cout << "initerror=" <<initerror << endl; | ||
210 | cout << "Portaudio version=" << (*(this->Pa_GetVersionText))() << endl; | ||
211 | #endif | ||
212 | |||
213 | #if (RECORDERDEBUG==1) | ||
214 | int devcount=(*(this->Pa_GetDeviceCount))(); | ||
215 | cout << "Portaudio Device count=" << devcount << endl; | ||
216 | cout << "Default Portaudio Input Device =" << (*(this->Pa_GetDefaultInputDevice))() << endl; | ||
217 | cout << "Default Portaudio Output Device =" << (*(this->Pa_GetDefaultOutputDevice))() << endl; | ||
218 | #endif | ||
219 | |||
220 | libloaded=true; | ||
221 | } | ||
222 | |||
223 | SoundFileWrapper::SoundFileWrapper(char* absprogpath) | ||
224 | { | ||
225 | sf_open=NULL; | ||
226 | sf_close=NULL; | ||
227 | libloaded=false; | ||
228 | |||
229 | char result[2048]; | ||
230 | // TODO: Was there a reason why this said PORTAUDIO? | ||
231 | // SmartFind(LIBFILE_PORTAUDIO,absprogpath,&result[0]); | ||
232 | SmartFind(LIBFILE_SNDFILE,absprogpath,&result[0]); | ||
233 | |||
234 | string abslib=""; | ||
235 | abslib+=result; | ||
236 | abslib+=LIBFILE_SNDFILE; | ||
237 | LIBHANDLE_T* handle=dlopen(abslib.c_str(),RTLD_NOW); | ||
238 | if (handle==NULL) { | ||
239 | fl_message("%s",dlerror()); | ||
240 | } | ||
241 | if (handle==NULL) { | ||
242 | handle=dlopen(LIBFILE_SNDFILE,RTLD_NOW); | ||
243 | if (handle==NULL) { | ||
244 | fl_message("%s",dlerror()); | ||
245 | } else { | ||
246 | define_functions(handle); | ||
247 | } | ||
248 | } else { | ||
249 | define_functions(handle); | ||
250 | } | ||
251 | } | ||
252 | |||
253 | SoundFileWrapper::~SoundFileWrapper() | ||
254 | { | ||
255 | if (libhandle!=NULL) | ||
256 | { | ||
257 | dlclose(libhandle); | ||
258 | } | ||
259 | |||
260 | } | ||
261 | |||
262 | void SoundFileWrapper::define_functions(LIBHANDLE_T* handle) | ||
263 | { | ||
264 | if (handle==NULL) return; | ||
265 | libhandle=handle; | ||
266 | // Given a handle to a dynamic library, define functions that are in it. | ||
267 | sf_open=(SNDFILE*(*)(const char*,int,SF_INFO*))dlsym(handle,"sf_open"); | ||
268 | if (sf_open==NULL) { | ||
269 | fl_message("Unable to load libsndfile, file transfers won't work."); | ||
270 | } | ||
271 | sf_close=(int(*)(SNDFILE*))dlsym(handle,"sf_close"); | ||
272 | sf_read_int=(sf_count_t(*)(SNDFILE*,int*,sf_count_t))dlsym(handle,"sf_read_int"); | ||
273 | sf_write_raw=(sf_count_t(*)(SNDFILE*,const void*,sf_count_t))dlsym(handle,"sf_write_raw"); | ||
274 | sf_write_float=(sf_count_t(*)(SNDFILE*,const void*,sf_count_t))dlsym(handle,"sf_write_float"); | ||
275 | if (sf_open!=NULL) { | ||
276 | libloaded=true; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | JackWrapper::JackWrapper(char* absprogpath) | ||
281 | { | ||
282 | libloaded=false; | ||
283 | char result[2048]; | ||
284 | // TODO: Was there a reason why this said PORTAUDIO? | ||
285 | // SmartFind(LIBFILE_PORTAUDIO,absprogpath,&result[0]); | ||
286 | SmartFind(LIBFILE_JACK,absprogpath,&result[0]); | ||
287 | |||
288 | string abslib=""; | ||
289 | abslib+=result; | ||
290 | abslib+=LIBFILE_JACK; | ||
291 | LIBHANDLE_T* handle=dlopen(abslib.c_str(),RTLD_NOW); | ||
292 | if (handle==NULL) { | ||
293 | handle=dlopen(LIBFILE_JACK,RTLD_NOW); | ||
294 | if (handle==NULL) { | ||
295 | // cout << dlerror() << endl; | ||
296 | } else { | ||
297 | define_functions(handle); | ||
298 | } | ||
299 | } else { | ||
300 | define_functions(handle); | ||
301 | } | ||
302 | } | ||
303 | |||
304 | JackWrapper::~JackWrapper() | ||
305 | { | ||
306 | if (libhandle!=NULL) | ||
307 | { | ||
308 | dlclose(libhandle); | ||
309 | } | ||
310 | |||
311 | } | ||
312 | |||
313 | void JackWrapper::define_functions(LIBHANDLE_T* handle) | ||
314 | { | ||
315 | if (handle==NULL) return; | ||
316 | libhandle=handle; | ||
317 | // Given a handle to a dynamic library, define functions that are in it. | ||
318 | jack_client_new=(jack_client_t*(*)(const char*))dlsym(handle,"jack_client_new"); | ||
319 | jack_set_process_callback=(int(*)(jack_client_t*,JackProcessCallback,void*))dlsym(handle,"jack_set_process_callback"); | ||
320 | jack_on_shutdown=(void (*)(jack_client_t*,void (*function)(void *), void *))dlsym(handle,"jack_on_shutdown"); | ||
321 | jack_get_sample_rate=(jack_nframes_t (*)(jack_client_t*))dlsym(handle,"jack_get_sample_rate"); | ||
322 | jack_port_get_buffer=(void* (*)(jack_port_t*,jack_nframes_t))dlsym(handle,"jack_port_get_buffer"); | ||
323 | jack_transport_query=(jack_transport_state_t (*)(const jack_client_t*,jack_position_t*))dlsym(handle,"jack_transport_query"); | ||
324 | jack_port_register=(jack_port_t* (*)(jack_client_t*,const char*,const char*,unsigned long,unsigned long))dlsym(handle,"jack_port_register"); | ||
325 | jack_activate=(int (*)(jack_client_t*))dlsym(handle,"jack_activate"); | ||
326 | jack_get_current_transport_frame=(jack_nframes_t (*)(const jack_client_t*))dlsym(handle,"jack_get_current_transport_frame"); | ||
327 | jack_transport_locate=(int (*)(jack_client_t*,jack_nframes_t))dlsym(handle,"jack_transport_locate"); | ||
328 | jack_transport_start=(void (*)(jack_client_t*))dlsym(handle,"jack_transport_start"); | ||
329 | jack_transport_stop=(void (*)(jack_client_t*))dlsym(handle,"jack_transport_stop"); | ||
330 | libloaded=true; | ||
331 | } | ||
332 | |||
diff --git a/src/lib/sharedlibs.h b/src/lib/sharedlibs.h new file mode 100644 index 0000000..325e301 --- /dev/null +++ b/src/lib/sharedlibs.h | |||
@@ -0,0 +1,88 @@ | |||
1 | #ifndef __sharedlibs_h__ | ||
2 | #define __sharedlibs_h__ | ||
3 | |||
4 | #include <xplat_dlfcn.h> | ||
5 | #include <soundlibs.h> | ||
6 | #include <sndfile.h> | ||
7 | #include <hd24utils.h> | ||
8 | |||
9 | class SmartLoader | ||
10 | { | ||
11 | public: | ||
12 | void SmartFind(const char* filename,const char* absprogpath,char* result); | ||
13 | }; | ||
14 | |||
15 | class PortAudioWrapper:SmartLoader | ||
16 | { | ||
17 | /* This class dynamically smart-loads the portaudio library, if available */ | ||
18 | private: | ||
19 | |||
20 | char libloadedstring[1024]; | ||
21 | |||
22 | public: | ||
23 | |||
24 | PaError (*Pa_Initialize)(void); | ||
25 | PaError (*Pa_Terminate)(void); | ||
26 | PaError (*Pa_StartStream)(PaStream*); | ||
27 | PaError (*Pa_StopStream)(PaStream*); | ||
28 | PaError (*Pa_AbortStream)(PaStream*); | ||
29 | PaError (*Pa_CloseStream)(PaStream*); | ||
30 | PaError (*Pa_StreamActive)(PaStream*); | ||
31 | PaTime (*Pa_GetStreamTime)(PaStream*); | ||
32 | PaError (*Pa_OpenStream)(PaStream **stream,const PaStreamParameters *inputParameters,const PaStreamParameters *outputParameters,double sampleRate,unsigned long framesPerBuffer,PaStreamFlags streamFlags,PaStreamCallback *streamCallback,void* userData); | ||
33 | int (*Pa_GetDefaultInputDevice)(void); | ||
34 | int (*Pa_GetDefaultOutputDevice)(void); | ||
35 | int (*Pa_GetDeviceCount)(void); | ||
36 | const char* (*Pa_GetVersionText)(void); | ||
37 | const char* (*Pa_GetErrorText)(PaError ErrorCode); | ||
38 | const PaDeviceInfo* (*Pa_GetDeviceInfo)(int); | ||
39 | |||
40 | void define_functions(LIBHANDLE_T* handle); | ||
41 | PortAudioWrapper(char* absprogpath); | ||
42 | ~PortAudioWrapper(); | ||
43 | int libloaded; | ||
44 | void* libhandle; | ||
45 | |||
46 | }; | ||
47 | |||
48 | class SoundFileWrapper:SmartLoader | ||
49 | { | ||
50 | public: | ||
51 | /* This class dynamically smart-loads libsndfile, if available */ | ||
52 | SNDFILE* (*sf_open)(const char*,int,SF_INFO*); | ||
53 | int (*sf_close)(SNDFILE*); | ||
54 | sf_count_t (*sf_read_int)(SNDFILE*,int*,sf_count_t); | ||
55 | sf_count_t (*sf_write_raw)(SNDFILE*,const void*,sf_count_t); | ||
56 | sf_count_t (*sf_write_float)(SNDFILE*,const void*,sf_count_t); | ||
57 | void define_functions(LIBHANDLE_T* handle); | ||
58 | SoundFileWrapper(char* absprogpath); | ||
59 | ~SoundFileWrapper(); | ||
60 | int libloaded; | ||
61 | void* libhandle; | ||
62 | }; | ||
63 | |||
64 | class JackWrapper:SmartLoader | ||
65 | { | ||
66 | public: | ||
67 | jack_client_t* (*jack_client_new)(const char*); | ||
68 | int (*jack_set_process_callback)(jack_client_t*,JackProcessCallback,void*); | ||
69 | void (*jack_on_shutdown)(jack_client_t*,void (*function)(void *), void *); | ||
70 | jack_nframes_t (*jack_get_sample_rate)(jack_client_t*); | ||
71 | void* (*jack_port_get_buffer)(jack_port_t*,jack_nframes_t); | ||
72 | |||
73 | jack_transport_state_t (*jack_transport_query)(const jack_client_t*,jack_position_t*); | ||
74 | jack_port_t* (*jack_port_register)(jack_client_t*,const char*,const char*,unsigned long,unsigned long); | ||
75 | int (*jack_activate)(jack_client_t*); | ||
76 | jack_nframes_t (*jack_get_current_transport_frame)(const jack_client_t*); | ||
77 | int (*jack_transport_locate)(jack_client_t*,jack_nframes_t); | ||
78 | void (*jack_transport_start)(jack_client_t*); | ||
79 | void (*jack_transport_stop)(jack_client_t*); | ||
80 | void define_functions(LIBHANDLE_T* handle); | ||
81 | JackWrapper(char* absprogpath); | ||
82 | ~JackWrapper(); | ||
83 | int libloaded; | ||
84 | void* libhandle; | ||
85 | |||
86 | }; | ||
87 | |||
88 | #endif | ||
diff --git a/src/lib/smpte.cpp b/src/lib/smpte.cpp new file mode 100644 index 0000000..537834c --- /dev/null +++ b/src/lib/smpte.cpp | |||
@@ -0,0 +1,221 @@ | |||
1 | #include "smpte.h" | ||
2 | #include "memutils.h" | ||
3 | #define SMPTE_DEBUG 0 | ||
4 | SMPTEgenerator::SMPTEgenerator(__uint32 p_samplerate) | ||
5 | { | ||
6 | #if (SMPTE_DEBUG==1) | ||
7 | cout << "Construct SMPTE generator with samrate=" << p_samplerate << endl; | ||
8 | #endif | ||
9 | // this->lastframe=-1; | ||
10 | this->prevbitnum=-1; | ||
11 | this->prevhalfbit=-1; | ||
12 | this->haveframe=0; | ||
13 | this->prevoutval=0; | ||
14 | this->framerate=30; // 30 is default for HD24. | ||
15 | this->bitsperframe=80; | ||
16 | this->nondrop=1; | ||
17 | this->setsamplerate(p_samplerate); | ||
18 | this->smpteword=(short*)memutils::mymalloc("smptegenerator::smptegenerator",80,sizeof(short)); | ||
19 | // pre-fill sync word | ||
20 | for (int i=0;i<64;i++) | ||
21 | { | ||
22 | this->smpteword[i]=0; | ||
23 | } | ||
24 | this->smpteword[64]=0; | ||
25 | this->smpteword[65]=0; | ||
26 | this->smpteword[66]=1; | ||
27 | this->smpteword[67]=1; | ||
28 | this->smpteword[68]=1; | ||
29 | this->smpteword[69]=1; | ||
30 | this->smpteword[70]=1; | ||
31 | this->smpteword[71]=1; | ||
32 | this->smpteword[72]=1; | ||
33 | this->smpteword[73]=1; | ||
34 | this->smpteword[74]=1; | ||
35 | this->smpteword[75]=1; | ||
36 | this->smpteword[76]=1; | ||
37 | this->smpteword[77]=1; | ||
38 | this->smpteword[78]=0; | ||
39 | this->smpteword[79]=1; | ||
40 | } | ||
41 | |||
42 | SMPTEgenerator::~SMPTEgenerator() | ||
43 | { | ||
44 | if (this==NULL) | ||
45 | { | ||
46 | return; | ||
47 | } | ||
48 | if (smpteword==NULL) | ||
49 | { | ||
50 | return; | ||
51 | } | ||
52 | memutils::myfree("SMPTE",smpteword); | ||
53 | smpteword=NULL; | ||
54 | } | ||
55 | void SMPTEgenerator::recalcrates() | ||
56 | { | ||
57 | |||
58 | this->bitspersecond=bitsperframe*framerate; | ||
59 | |||
60 | } | ||
61 | |||
62 | void SMPTEgenerator::setsamplerate(__uint32 p_samplerate) | ||
63 | { | ||
64 | this->samplerate=p_samplerate; | ||
65 | this->recalcrates(); | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | void SMPTEgenerator::setframerate(__uint32 p_framerate) | ||
70 | { | ||
71 | this->framerate=p_framerate; | ||
72 | this->recalcrates(); | ||
73 | } | ||
74 | |||
75 | void SMPTEgenerator::fillword(int hour,int minute,int second,int frame) | ||
76 | { | ||
77 | #if (SMPTE_DEBUG==1) | ||
78 | cout << "fill word for " | ||
79 | << hour << ":" << minute << ":" << second <<"."<<frame << endl; | ||
80 | #endif | ||
81 | int frameunits=(frame%10); | ||
82 | int frametens=(int)((frame-frameunits)/10); | ||
83 | |||
84 | int secondsunits=(second%10); | ||
85 | int secondstens=(int)((second-secondsunits)/10); | ||
86 | |||
87 | int minuteunits=(minute%10); | ||
88 | int minutetens=(int)((minute-minuteunits)/10); | ||
89 | |||
90 | int hourunits=(hour%10); | ||
91 | int hourtens=(int)((hour-hourunits)/10); | ||
92 | |||
93 | |||
94 | this->smpteword[0]=((frameunits ) & 1); | ||
95 | this->smpteword[1]=((frameunits>>1) & 1); | ||
96 | this->smpteword[2]=((frameunits>>2) & 1); | ||
97 | this->smpteword[3]=((frameunits>>3) & 1); | ||
98 | // this->smpteword[4]=0; | ||
99 | // this->smpteword[5]=0; | ||
100 | // this->smpteword[6]=0; | ||
101 | // this->smpteword[7]=0; | ||
102 | this->smpteword[8]=((frametens) & 1); | ||
103 | this->smpteword[9]=((frametens>>1) & 1); | ||
104 | // this->smpteword[10]=0; | ||
105 | // this->smpteword[11]=0; | ||
106 | // this->smpteword[12]=0; | ||
107 | // this->smpteword[13]=0; | ||
108 | // this->smpteword[14]=0; | ||
109 | // this->smpteword[15]=0; | ||
110 | this->smpteword[16]=((secondsunits ) & 1); | ||
111 | this->smpteword[17]=((secondsunits>>1) & 1); | ||
112 | this->smpteword[18]=((secondsunits>>2) & 1); | ||
113 | this->smpteword[19]=((secondsunits>>3) & 1); | ||
114 | // this->smpteword[20]=0; | ||
115 | // this->smpteword[21]=0; | ||
116 | // this->smpteword[22]=0; | ||
117 | // this->smpteword[23]=0; | ||
118 | this->smpteword[24]=((secondstens )&1); | ||
119 | this->smpteword[25]=((secondstens>>1)&1); | ||
120 | this->smpteword[26]=((secondstens>>2)&1); | ||
121 | this->smpteword[27]=0; // is biphasemark, filled in later | ||
122 | // but reset here to prevent its influence | ||
123 | |||
124 | // this->smpteword[28]=0; | ||
125 | // this->smpteword[29]=0; | ||
126 | // this->smpteword[30]=0; | ||
127 | // this->smpteword[31]=0; | ||
128 | this->smpteword[32]=((minuteunits ) & 1); | ||
129 | this->smpteword[33]=((minuteunits>>1) & 1); | ||
130 | this->smpteword[34]=((minuteunits>>2) & 1); | ||
131 | this->smpteword[35]=((minuteunits>>3) & 1); | ||
132 | // this->smpteword[36]=0; | ||
133 | // this->smpteword[37]=0; | ||
134 | // this->smpteword[38]=0; | ||
135 | // this->smpteword[39]=0; | ||
136 | this->smpteword[40]=((minutetens ) & 1); | ||
137 | this->smpteword[41]=((minutetens>>1) & 1); | ||
138 | this->smpteword[42]=((minutetens>>2) & 1); | ||
139 | // this->smpteword[43]=0; # binary group flag bit | ||
140 | // this->smpteword[44]=0; | ||
141 | // this->smpteword[45]=0; | ||
142 | // this->smpteword[46]=0; | ||
143 | // this->smpteword[47]=0; | ||
144 | this->smpteword[48]=((hourunits )&1); | ||
145 | this->smpteword[49]=((hourunits>>1)&1); | ||
146 | this->smpteword[50]=((hourunits>>2)&1); | ||
147 | this->smpteword[51]=((hourunits>>3)&1); | ||
148 | // this->smpteword[52]=0; | ||
149 | // this->smpteword[53]=0; | ||
150 | // this->smpteword[54]=0; | ||
151 | // this->smpteword[55]=0; | ||
152 | this->smpteword[56]=((hourtens )&1); | ||
153 | this->smpteword[57]=((hourtens>>1)&1); | ||
154 | // this->smpteword[58]=0; // reserved, must be 0 | ||
155 | // this->smpteword[59]=0; // binary group flag bit | ||
156 | // this->smpteword[60]=0; | ||
157 | // this->smpteword[61]=0; | ||
158 | // this->smpteword[62]=0; | ||
159 | // this->smpteword[63]=0; | ||
160 | |||
161 | // sync word already set in constructor | ||
162 | unsigned parity = 0; | ||
163 | for (int i=0; i<80; ++i) { | ||
164 | parity += this->smpteword[i]; | ||
165 | } | ||
166 | this->smpteword[27] = (parity & 1); | ||
167 | #if (SMPTE_DEBUG==1) | ||
168 | for (int i=0;i<80;i++) | ||
169 | { | ||
170 | cout << this->smpteword[i]; | ||
171 | } | ||
172 | cout << endl; | ||
173 | #endif | ||
174 | return; | ||
175 | |||
176 | } | ||
177 | int SMPTEgenerator::modulate(int currbitval,int bitnum,int halfbit) | ||
178 | { | ||
179 | if ((bitnum!=this->prevbitnum) || ((halfbit!=this->prevhalfbit) && (currbitval==1))) | ||
180 | { | ||
181 | this->prevoutval=1-(this->prevoutval); | ||
182 | } | ||
183 | this->prevbitnum=bitnum; | ||
184 | this->prevhalfbit=halfbit; | ||
185 | return this->prevoutval; | ||
186 | } | ||
187 | |||
188 | int SMPTEgenerator::getbit(__uint32 insamnum) | ||
189 | { | ||
190 | |||
191 | this->samplesperbit=(int)((this->samplerate)/this->bitspersecond); | ||
192 | this->samplesperframe=(int)((this->samplerate)/framerate); | ||
193 | |||
194 | __uint32 sampleinsecond=insamnum % this->samplerate; | ||
195 | __uint32 currentsecond=(insamnum-sampleinsecond)/(this->samplerate); | ||
196 | __uint32 currenthour=int(currentsecond/3600); | ||
197 | currentsecond-=3600*currenthour; | ||
198 | __uint32 currentminute=int(currentsecond/60); | ||
199 | currentsecond-=60*currentminute; | ||
200 | |||
201 | __uint32 currentframe=(int)(sampleinsecond/this->samplesperframe); | ||
202 | __uint32 sampleinframe=sampleinsecond-(currentframe*this->samplesperframe); | ||
203 | __uint32 bitinframe=(int)(sampleinframe/this->samplesperbit); | ||
204 | __uint32 subbit=(int)(sampleinframe-(bitinframe*this->samplesperbit)); | ||
205 | __uint32 halfbit=(this->samplesperbit/2); | ||
206 | if ((bitinframe==0)&&(subbit==0)) | ||
207 | { | ||
208 | this->haveframe=0; | ||
209 | } | ||
210 | if (this->haveframe==0) | ||
211 | { | ||
212 | this->fillword(currenthour,currentminute,currentsecond,currentframe); | ||
213 | this->haveframe=1; | ||
214 | } | ||
215 | |||
216 | if (subbit<halfbit) { | ||
217 | return this->modulate(smpteword[bitinframe],bitinframe,0); | ||
218 | } | ||
219 | return this->modulate(smpteword[bitinframe],bitinframe,1); | ||
220 | } | ||
221 | |||
diff --git a/src/lib/smpte.h b/src/lib/smpte.h new file mode 100644 index 0000000..fdaef3a --- /dev/null +++ b/src/lib/smpte.h | |||
@@ -0,0 +1,41 @@ | |||
1 | #ifndef __smpte_h__ | ||
2 | #define __smpte_h__ | ||
3 | |||
4 | using namespace std; | ||
5 | #include "config.h" | ||
6 | #include <string> | ||
7 | #include <iostream> | ||
8 | |||
9 | class SMPTEgenerator | ||
10 | { | ||
11 | private: | ||
12 | |||
13 | short* smpteword; | ||
14 | int prevbitnum; | ||
15 | int prevhalfbit; | ||
16 | int prevoutval; | ||
17 | int framerate; | ||
18 | int nondrop; | ||
19 | int haveframe; // indicates if a new frame word must be generated | ||
20 | int samplerate; | ||
21 | |||
22 | /* These are pre-calculated: */ | ||
23 | int bitsperframe; | ||
24 | int bitspersecond; | ||
25 | int samplesperbit; | ||
26 | int samplesperframe; | ||
27 | void recalcrates(); | ||
28 | void fillword(int hour,int min,int sec,int frame); | ||
29 | |||
30 | void setsamplerate(__uint32 p_samplerate); | ||
31 | void setframerate(__uint32 p_samplerate); | ||
32 | |||
33 | int modulate(int currbitval,int bitnum,int halfbit); | ||
34 | public: | ||
35 | SMPTEgenerator(__uint32 p_samplerate); | ||
36 | ~SMPTEgenerator(); | ||
37 | int getbit(__uint32 insamnum); | ||
38 | |||
39 | }; | ||
40 | |||
41 | #endif | ||
diff --git a/src/lib/soundlibs.h b/src/lib/soundlibs.h new file mode 100644 index 0000000..faa7231 --- /dev/null +++ b/src/lib/soundlibs.h | |||
@@ -0,0 +1,15 @@ | |||
1 | #ifdef LIBJACK | ||
2 | # include <jack/jack.h> | ||
3 | # include <jack/transport.h> | ||
4 | #else | ||
5 | # include "../lib/nojack.h" | ||
6 | #endif | ||
7 | |||
8 | #ifdef LIBPORTAUDIO | ||
9 | # include "portaudio.h" | ||
10 | # define portaudiostreamtype PaStream | ||
11 | #else | ||
12 | # define portaudiostreamtype void | ||
13 | # define PaTime unsigned long | ||
14 | #endif | ||
15 | |||
diff --git a/src/lib/xplat_dlfcn.h b/src/lib/xplat_dlfcn.h new file mode 100644 index 0000000..3b1c98c --- /dev/null +++ b/src/lib/xplat_dlfcn.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifdef WINDOWS | ||
2 | #include <windows.h> | ||
3 | #define dlopen(a,b) LoadLibrary(a) | ||
4 | #define dlsym(a,b) GetProcAddress(a,b) | ||
5 | #define dlclose(a) /* CloseLibrary(a) */ | ||
6 | #define dlerror() "Error loading library" | ||
7 | #define LIBHANDLE_T HINSTANCE__ | ||
8 | #else | ||
9 | #include <dlfcn.h> | ||
10 | #define LIBHANDLE_T void | ||
11 | #endif | ||
12 | |||
diff --git a/src/test/co b/src/test/co new file mode 100755 index 0000000..d6216bf --- /dev/null +++ b/src/test/co | |||
@@ -0,0 +1,2 @@ | |||
1 | #!/bin/bash | ||
2 | g++ -O3 portaudiotest.cpp -l portaudio -o portaudiotest | ||
diff --git a/src/test/portaudiotest.cpp b/src/test/portaudiotest.cpp new file mode 100644 index 0000000..58f6cac --- /dev/null +++ b/src/test/portaudiotest.cpp | |||
@@ -0,0 +1,158 @@ | |||
1 | using namespace std; | ||
2 | #include <iostream> | ||
3 | #include <portaudio.h> | ||
4 | #include "portaudiotest.h" | ||
5 | #define PA_FRAMESPERBUF 512 | ||
6 | #define __uint32 unsigned long | ||
7 | |||
8 | int HD24UserInterface::portaudio_process( | ||
9 | const void *inputBuffer, | ||
10 | void *outputBuffer, | ||
11 | __uint32 nframes, | ||
12 | const PaStreamCallbackTimeInfo* timeinfo, | ||
13 | PaStreamCallbackFlags, | ||
14 | void *userData) | ||
15 | { | ||
16 | HD24UserInterface* mythis=(HD24UserInterface*)userData; | ||
17 | if (!mythis->havestreamtime) | ||
18 | { | ||
19 | mythis->streamtime=0; | ||
20 | mythis->timeoffset=timeinfo->currentTime; | ||
21 | mythis->havestreamtime=true; | ||
22 | } | ||
23 | mythis->streamtime+=nframes; | ||
24 | cout << ((mythis->streamtime)/48000) << " nframes=" << nframes <<" streamtime=" << timeinfo->currentTime-(mythis->timeoffset) << endl; | ||
25 | float sval=1; | ||
26 | for (int i=0;i<nframes;i++) | ||
27 | { | ||
28 | if ((i%16)==0) sval=-sval; | ||
29 | ((float*)(outputBuffer))[i]=sval; | ||
30 | } | ||
31 | return paContinue; | ||
32 | } | ||
33 | |||
34 | |||
35 | void HD24UserInterface::portaudioinit() | ||
36 | { | ||
37 | cout << "portaudioinit" << endl; | ||
38 | PaError err; | ||
39 | inputParameters=new PaStreamParameters; | ||
40 | outputParameters=new PaStreamParameters; | ||
41 | err=Pa_Initialize(); | ||
42 | if (err!=paNoError) | ||
43 | { | ||
44 | Pa_Terminate(); | ||
45 | return; | ||
46 | } | ||
47 | m_isportaudioinitialized=true; | ||
48 | } | ||
49 | |||
50 | HD24UserInterface::HD24UserInterface() | ||
51 | { | ||
52 | m_isportaudioinitialized=false; | ||
53 | portaudiostream=NULL; | ||
54 | return; | ||
55 | } | ||
56 | |||
57 | bool HD24UserInterface::isportaudioinitialized() | ||
58 | { | ||
59 | return m_isportaudioinitialized; | ||
60 | } | ||
61 | |||
62 | void HD24UserInterface::portaudio_transport_start() | ||
63 | { | ||
64 | |||
65 | cout << "portaudio transport start" << endl; | ||
66 | |||
67 | if (!isportaudioinitialized()) | ||
68 | { | ||
69 | PaError err=Pa_Initialize(); | ||
70 | if (err != paNoError) | ||
71 | { | ||
72 | cout << "Cannot initialize portaudio- exiting." << endl; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | if (isportaudioinitialized() && (portaudiostream!=NULL)) | ||
77 | { | ||
78 | cout << "already have stream- done starting" << endl; | ||
79 | return; | ||
80 | } | ||
81 | |||
82 | PaDeviceIndex indevice=Pa_GetDefaultInputDevice(); | ||
83 | bzero(inputParameters,sizeof(*inputParameters)); | ||
84 | inputParameters->device=indevice; | ||
85 | inputParameters->channelCount=1; | ||
86 | inputParameters->sampleFormat=paFloat32; | ||
87 | inputParameters->suggestedLatency = Pa_GetDeviceInfo( inputParameters->device )->defaultLowInputLatency; | ||
88 | inputParameters->hostApiSpecificStreamInfo = NULL; | ||
89 | |||
90 | cout << "Input params set" << endl; | ||
91 | cout << "Device=" << inputParameters->device << endl; | ||
92 | cout << "Channelcount=" << inputParameters->channelCount << endl; | ||
93 | cout << "sampleFormat=" << inputParameters->sampleFormat << endl; | ||
94 | cout << "suggestedlatency=" << inputParameters->suggestedLatency << endl; | ||
95 | cout << "================================="<<endl; | ||
96 | bzero(outputParameters,sizeof(*outputParameters)); | ||
97 | PaDeviceIndex outdevice=Pa_GetDefaultOutputDevice(); | ||
98 | outputParameters->device=outdevice; | ||
99 | outputParameters->channelCount=1; | ||
100 | outputParameters->sampleFormat=paFloat32; | ||
101 | outputParameters->suggestedLatency = Pa_GetDeviceInfo( outputParameters->device )->defaultLowOutputLatency; | ||
102 | outputParameters->hostApiSpecificStreamInfo = NULL; | ||
103 | |||
104 | cout << "Output params set" << endl; | ||
105 | cout << "Device=" << outputParameters->device << endl; | ||
106 | cout << "Channelcount=" << outputParameters->channelCount << endl; | ||
107 | cout << "sampleFormat=" << outputParameters->sampleFormat << endl; | ||
108 | cout << "suggestedlatency=" << outputParameters->suggestedLatency << endl; | ||
109 | cout << "================================="<<endl; | ||
110 | |||
111 | double samrate=48000; | ||
112 | cout << "trying samerate="<<samrate<<endl; | ||
113 | cout << "framesperbuf=" << PA_FRAMESPERBUF << endl; | ||
114 | |||
115 | PaError err=Pa_OpenStream( | ||
116 | &portaudiostream, | ||
117 | this->inputParameters, | ||
118 | this->outputParameters, | ||
119 | samrate, | ||
120 | PA_FRAMESPERBUF, /* frames per buffer */ | ||
121 | paClipOff | paDitherOff, | ||
122 | portaudio_process, | ||
123 | (void*)this); | ||
124 | this->havestreamtime=false; | ||
125 | |||
126 | if (err!=paNoError) | ||
127 | { | ||
128 | cout << "Error opening stream" << endl; | ||
129 | Pa_Terminate(); | ||
130 | return; | ||
131 | } | ||
132 | |||
133 | cout << "Stream opened, going to start it now..." << endl; | ||
134 | |||
135 | err=Pa_StartStream(portaudiostream); | ||
136 | |||
137 | if (err!=paNoError) | ||
138 | { | ||
139 | cout << "Error starting stream" << endl; | ||
140 | Pa_Terminate(); | ||
141 | return; | ||
142 | } | ||
143 | |||
144 | cout << "Stream started" << endl; | ||
145 | |||
146 | return; | ||
147 | } | ||
148 | |||
149 | int main() | ||
150 | { | ||
151 | HD24UserInterface* ui=new HD24UserInterface(); | ||
152 | ui->portaudioinit(); | ||
153 | ui->portaudio_transport_start(); | ||
154 | int blah; | ||
155 | cin >> blah; | ||
156 | |||
157 | } | ||
158 | |||
diff --git a/src/test/portaudiotest.h b/src/test/portaudiotest.h new file mode 100644 index 0000000..f3dbe32 --- /dev/null +++ b/src/test/portaudiotest.h | |||
@@ -0,0 +1,33 @@ | |||
1 | #ifndef __portaudiotest_h__ | ||
2 | #define __portaudiotest_h__ | ||
3 | #ifndef __uint32 | ||
4 | #define __uint32 unsigned long | ||
5 | #endif | ||
6 | class HD24UserInterface | ||
7 | { | ||
8 | private: | ||
9 | PaStream* portaudiostream; | ||
10 | bool m_isportaudioinitialized; | ||
11 | bool havestreamtime; | ||
12 | PaTime streamtime; | ||
13 | PaTime timeoffset; | ||
14 | static int portaudio_process | ||
15 | ( | ||
16 | const void *inputBuffer, | ||
17 | void *outputBuffer, | ||
18 | __uint32 nframes, | ||
19 | const PaStreamCallbackTimeInfo* timeinfo, | ||
20 | PaStreamCallbackFlags, | ||
21 | void *userData | ||
22 | ); | ||
23 | |||
24 | PaStreamParameters* inputParameters; | ||
25 | PaStreamParameters* outputParameters; | ||
26 | public: | ||
27 | HD24UserInterface(); | ||
28 | bool isportaudioinitialized(); | ||
29 | void portaudioinit(); | ||
30 | void portaudio_transport_start(); | ||
31 | }; | ||
32 | |||
33 | #endif | ||
diff --git a/src/test/portaudiotestold.cpp b/src/test/portaudiotestold.cpp new file mode 100644 index 0000000..954c64e --- /dev/null +++ b/src/test/portaudiotestold.cpp | |||
@@ -0,0 +1,157 @@ | |||
1 | using namespace std; | ||
2 | #include <iostream> | ||
3 | #include <portaudio.h> | ||
4 | #include "portaudiotest.h" | ||
5 | #define PA_FRAMESPERBUF 512 | ||
6 | #define __uint32 unsigned long | ||
7 | |||
8 | int HD24UserInterface::portaudio_process( | ||
9 | const void *inputBuffer, | ||
10 | void *outputBuffer, | ||
11 | __uint32 nframes, | ||
12 | const PaStreamCallbackTimeInfo* timeinfo, | ||
13 | PaStreamCallbackFlags, | ||
14 | void *userData) | ||
15 | { | ||
16 | HD24UserInterface* mythis=(HD24UserInterface*)userData; | ||
17 | const PaStreamInfo* streaminfo=Pa_GetStreamInfo(mythis->portaudiostream); | ||
18 | double samplerate=streaminfo->sampleRate; | ||
19 | if (!mythis->havestreamtime) | ||
20 | { | ||
21 | mythis->streamtime=0; | ||
22 | mythis->havestreamtime=true; | ||
23 | } | ||
24 | mythis->streamtime+=nframes; | ||
25 | for (int i=0;i<nframes*2;i++) | ||
26 | { | ||
27 | float sval=(((i%20)/20)-.5); | ||
28 | ((float*)(outputBuffer))[i]=sval; | ||
29 | } | ||
30 | return paContinue; | ||
31 | } | ||
32 | |||
33 | |||
34 | void HD24UserInterface::portaudioinit() | ||
35 | { | ||
36 | cout << "portaudioinit" << endl; | ||
37 | PaError err; | ||
38 | inputParameters=new PaStreamParameters; | ||
39 | outputParameters=new PaStreamParameters; | ||
40 | err=Pa_Initialize(); | ||
41 | if (err!=paNoError) | ||
42 | { | ||
43 | Pa_Terminate(); | ||
44 | return; | ||
45 | } | ||
46 | m_isportaudioinitialized=true; | ||
47 | } | ||
48 | |||
49 | HD24UserInterface::HD24UserInterface() | ||
50 | { | ||
51 | m_isportaudioinitialized=false; | ||
52 | portaudiostream=NULL; | ||
53 | return; | ||
54 | } | ||
55 | |||
56 | bool HD24UserInterface::isportaudioinitialized() | ||
57 | { | ||
58 | return m_isportaudioinitialized; | ||
59 | } | ||
60 | |||
61 | void HD24UserInterface::portaudio_transport_start() | ||
62 | { | ||
63 | |||
64 | cout << "portaudio transport start" << endl; | ||
65 | |||
66 | if (!isportaudioinitialized()) | ||
67 | { | ||
68 | PaError err=Pa_Initialize(); | ||
69 | if (err != paNoError) | ||
70 | { | ||
71 | cout << "Cannot initialize portaudio- exiting." << endl; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | if (isportaudioinitialized() && (portaudiostream!=NULL)) | ||
76 | { | ||
77 | cout << "already have stream- done starting" << endl; | ||
78 | return; | ||
79 | } | ||
80 | |||
81 | PaDeviceIndex indevice=Pa_GetDefaultInputDevice(); | ||
82 | bzero(inputParameters,sizeof(*inputParameters)); | ||
83 | inputParameters->device=indevice; | ||
84 | inputParameters->channelCount=1; | ||
85 | inputParameters->sampleFormat=paFloat32; | ||
86 | inputParameters->suggestedLatency = Pa_GetDeviceInfo( inputParameters->device )->defaultLowInputLatency; | ||
87 | inputParameters->hostApiSpecificStreamInfo = NULL; | ||
88 | |||
89 | cout << "Input params set" << endl; | ||
90 | cout << "Device=" << inputParameters->device << endl; | ||
91 | cout << "Channelcount=" << inputParameters->channelCount << endl; | ||
92 | cout << "sampleFormat=" << inputParameters->sampleFormat << endl; | ||
93 | cout << "suggestedlatency=" << inputParameters->suggestedLatency << endl; | ||
94 | cout << "================================="<<endl; | ||
95 | bzero(outputParameters,sizeof(*outputParameters)); | ||
96 | PaDeviceIndex outdevice=Pa_GetDefaultOutputDevice(); | ||
97 | outputParameters->device=outdevice; | ||
98 | outputParameters->channelCount=1; | ||
99 | outputParameters->sampleFormat=paFloat32; | ||
100 | outputParameters->suggestedLatency = Pa_GetDeviceInfo( outputParameters->device )->defaultLowOutputLatency; | ||
101 | outputParameters->hostApiSpecificStreamInfo = NULL; | ||
102 | |||
103 | cout << "Output params set" << endl; | ||
104 | cout << "Device=" << outputParameters->device << endl; | ||
105 | cout << "Channelcount=" << outputParameters->channelCount << endl; | ||
106 | cout << "sampleFormat=" << outputParameters->sampleFormat << endl; | ||
107 | cout << "suggestedlatency=" << outputParameters->suggestedLatency << endl; | ||
108 | cout << "================================="<<endl; | ||
109 | |||
110 | double samrate=44100; | ||
111 | cout << "trying samerate="<<samrate<<endl; | ||
112 | cout << "framesperbuf=" << PA_FRAMESPERBUF << endl; | ||
113 | |||
114 | PaError err=Pa_OpenStream( | ||
115 | &portaudiostream, | ||
116 | this->inputParameters, | ||
117 | this->outputParameters, | ||
118 | samrate, | ||
119 | PA_FRAMESPERBUF, /* frames per buffer */ | ||
120 | paClipOff | paDitherOff, | ||
121 | portaudio_process, | ||
122 | (void*)this); | ||
123 | this->havestreamtime=false; | ||
124 | |||
125 | if (err!=paNoError) | ||
126 | { | ||
127 | cout << "Error opening stream" << endl; | ||
128 | Pa_Terminate(); | ||
129 | return; | ||
130 | } | ||
131 | |||
132 | cout << "Stream opened, going to start it now..." << endl; | ||
133 | |||
134 | err=Pa_StartStream(portaudiostream); | ||
135 | |||
136 | if (err!=paNoError) | ||
137 | { | ||
138 | cout << "Error starting stream" << endl; | ||
139 | Pa_Terminate(); | ||
140 | return; | ||
141 | } | ||
142 | |||
143 | cout << "Stream started" << endl; | ||
144 | |||
145 | return; | ||
146 | } | ||
147 | |||
148 | int main() | ||
149 | { | ||
150 | HD24UserInterface* ui=new HD24UserInterface(); | ||
151 | ui->portaudioinit(); | ||
152 | ui->portaudio_transport_start(); | ||
153 | int blah; | ||
154 | cin >> blah; | ||
155 | |||
156 | } | ||
157 | |||