CDRecordUtils.Mod 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897
  1. MODULE CDRecordUtils;
  2. IMPORT
  3. SYSTEM, Codecs, Strings, Streams, Files, SoundDevices, KernelLog, Disks, DiskVolumes, FATVolumes, ISO9660Volumes, ATADisks,
  4. WMWindowManager, WMComponents, WMStandardComponents, WMFileManager, WMSystemComponents, WMGrids, WMStringGrids, WMDialogs,
  5. WMEvents, WMTabComponents, WMProperties, WMGraphics, WMRectangles;
  6. CONST
  7. MaxLen = 256;
  8. ResOk=0; ResErr=1;
  9. (* mpeg *)
  10. MPEGVer1 = 3;
  11. MPEGVer2 = 2;
  12. MPEGVer25 = 0;
  13. (* wave compression *)
  14. CUnknown* = 0H;
  15. CPCM* = 1H;
  16. CMsADPCM* = 2H;
  17. (* Errors *)
  18. ErrFileNotFound* = 100;
  19. ErrNoISOImage* = 101;
  20. White = 0FFFFFFFFH;
  21. Black = 0000000FFH;
  22. LightGray = (0C8C8C8FFH);
  23. DarkGray = (0A0A0A0FFH);
  24. TYPE
  25. String = Strings.String;
  26. Status* = OBJECT END Status;
  27. ConvertingStatus* = OBJECT(Status)
  28. VAR
  29. bytesEncoded*: LONGINT;
  30. END ConvertingStatus;
  31. StatusProc* = PROCEDURE {DELEGATE} (status: Status);
  32. WAVInfo* = OBJECT
  33. VAR
  34. compression*, size*, nofchannels*, samplerate*, encoding* : LONGINT;
  35. PROCEDURE Open*(filename : Strings.String): LONGINT;
  36. VAR
  37. bytesRead: LONGINT;
  38. file: Files.File;
  39. r: Files.Reader;
  40. buf: ARRAY 8 OF CHAR;
  41. BEGIN
  42. file := Files.Old(filename^);
  43. IF file = NIL THEN
  44. RETURN 1;
  45. END;
  46. Files.OpenReader(r, file, 0);
  47. (* read first chunk and check if file is a wav file *)
  48. buf[4] := 0X;
  49. r.Bytes(buf, 0, 4, bytesRead);
  50. IF buf # "RIFF" THEN
  51. RETURN ResErr;
  52. END;
  53. r.Bytes(buf, 0, 4, bytesRead);
  54. size := ConvertLE32Int(buf);
  55. (* Bluebottle's Wave Encoder only sets the header size
  56. IF size # file.Length() - 8 THEN
  57. RETURN ResErr;
  58. END;
  59. *)
  60. IF size < 1024 THEN size := file.Length() - 8; END;
  61. r.Bytes(buf, 0, 4, bytesRead);
  62. IF buf # "WAVE" THEN
  63. RETURN ResErr;
  64. END;
  65. (* format chunk *)
  66. r.Bytes(buf, 0, 4, bytesRead);
  67. IF buf # "fmt " THEN
  68. RETURN ResErr;
  69. END;
  70. r.Bytes(buf, 0, 4, bytesRead);
  71. r.Bytes(buf, 0, 2, bytesRead);
  72. compression := ConvertLE16Int(buf);
  73. r.Bytes(buf, 0, 2, bytesRead);
  74. nofchannels := ConvertLE16Int(buf);
  75. r.Bytes(buf, 0, 4, bytesRead);
  76. samplerate := ConvertLE32Int(buf);
  77. r.Bytes(buf, 0, 6, bytesRead);
  78. r.Bytes(buf, 0, 2, bytesRead);
  79. encoding := ConvertLE16Int(buf);
  80. RETURN ResOk;
  81. END Open;
  82. END WAVInfo;
  83. Frame = RECORD
  84. mpegver, bitrate, samplerate, padding, layer, size : LONGINT
  85. END;
  86. ID3v1* = OBJECT
  87. VAR
  88. Title*, Artist*, Album: ARRAY 31 OF CHAR;
  89. END ID3v1;
  90. MP3Info* = OBJECT
  91. VAR
  92. nofframes*, playtime* : LONGINT;
  93. id3v1*: ID3v1;
  94. bitrateTable: ARRAY 6, 16 OF LONGINT;
  95. PROCEDURE &New*;
  96. BEGIN
  97. InitTable(bitrateTable);
  98. id3v1 := NIL;
  99. END New;
  100. PROCEDURE GetNextFrame(r: Files.Reader; VAR frame: Frame): LONGINT;
  101. VAR
  102. n, start, bytesRead, tmp: LONGINT;
  103. chr: CHAR;
  104. buf : ARRAY 4 OF CHAR;
  105. BEGIN
  106. start := -1; n := 0;
  107. (* find first frame in first 10k by comparing sync pattern *)
  108. REPEAT
  109. r.Bytes(buf, 0, 1, bytesRead);
  110. IF (bytesRead = 1) & (buf[0] = 0FFX) THEN
  111. chr := r.Peek();
  112. IF ASH(ORD(chr), -5) = 7 THEN
  113. start := n;
  114. r.Bytes(buf, 1, 3, bytesRead);
  115. END;
  116. END;
  117. INC(n, 1);
  118. UNTIL (n > 10000) OR (bytesRead < 1) OR (start # -1);
  119. IF start = -1 THEN
  120. RETURN ResErr;
  121. END;
  122. (* MPEG version *)
  123. tmp := ASH(ORD(buf[1]), -3) MOD 4;
  124. CASE tmp OF
  125. 0: frame.mpegver := MPEGVer25; (* 2.5 *)
  126. | 2: frame.mpegver := MPEGVer2;
  127. | 3: frame.mpegver := MPEGVer1;
  128. ELSE RETURN ResErr;
  129. END;
  130. (* MPEG Layer *)
  131. tmp := ASH(ORD(buf[1]), -1) MOD 4;
  132. CASE tmp OF
  133. 1: frame.layer := 3;
  134. | 2: frame.layer := 2;
  135. | 3: frame.layer := 1;
  136. ELSE RETURN ResErr;
  137. END;
  138. (* Bitrate *)
  139. tmp := ASH(ORD(buf[2]), -4);
  140. IF frame.mpegver = MPEGVer1 THEN
  141. CASE frame.layer OF
  142. 1: frame.bitrate := bitrateTable[0][tmp];
  143. | 2: frame.bitrate := bitrateTable[1][tmp];
  144. | 3: frame.bitrate := bitrateTable[2][tmp];
  145. ELSE RETURN ResErr;
  146. END;
  147. ELSE
  148. CASE frame.layer OF
  149. 1: frame.bitrate := bitrateTable[3][tmp];
  150. | 2: frame.bitrate := bitrateTable[4][tmp];
  151. | 3: frame.bitrate := bitrateTable[5][tmp];
  152. ELSE RETURN ResErr;
  153. END;
  154. END;
  155. (* samplerate *)
  156. tmp := ASH(ORD(buf[2]), -2) MOD 4;
  157. IF frame.mpegver = MPEGVer1 THEN
  158. CASE tmp OF
  159. 0: frame.samplerate := 44100;
  160. | 1: frame.samplerate := 48000;
  161. | 2: frame.samplerate := 32000;
  162. ELSE RETURN ResErr;
  163. END;
  164. ELSIF frame.mpegver = MPEGVer2 THEN
  165. CASE tmp OF
  166. 0: frame.samplerate := 22050;
  167. | 1: frame.samplerate := 24000;
  168. | 2: frame.samplerate := 16000;
  169. ELSE RETURN ResErr;
  170. END;
  171. ELSIF frame.mpegver = MPEGVer25 THEN
  172. CASE tmp OF
  173. 0: frame.samplerate := 11025;
  174. | 1: frame.samplerate := 12000;
  175. | 2: frame.samplerate := 8000;
  176. ELSE RETURN ResErr;
  177. END;
  178. END;
  179. frame.padding := ASH(ORD(buf[2]), -1) MOD 2;
  180. IF frame.mpegver = MPEGVer1 THEN
  181. IF frame.layer = 1 THEN
  182. tmp := 48000;
  183. ELSE
  184. tmp := 144000;
  185. END;
  186. ELSE
  187. IF frame.layer = 1 THEN
  188. tmp := 24000
  189. ELSE
  190. tmp := 72000;
  191. END;
  192. END;
  193. frame.size := tmp*frame.bitrate DIV frame.samplerate + frame.padding;
  194. RETURN ResOk;
  195. END GetNextFrame;
  196. PROCEDURE Open*(filename: String): LONGINT;
  197. VAR
  198. file : Files.File;
  199. r: Files.Reader;
  200. frame: Frame;
  201. BEGIN
  202. nofframes := 0; playtime := 0;
  203. file := Files.Old(filename^);
  204. IF file = NIL THEN
  205. RETURN ResErr;
  206. END;
  207. Files.OpenReader(r, file, 0);
  208. WHILE GetNextFrame(r, frame) = ResOk DO
  209. INC(nofframes);
  210. r.SkipBytes(frame.size-4);
  211. INC(playtime, (8*frame.size) DIV frame.bitrate); (* in ms *)
  212. END;
  213. IF nofframes < 1 THEN RETURN ResErr END;
  214. playtime := (playtime+1000-1) DIV 1000;
  215. NEW(id3v1);
  216. IF ReadID3v1(filename, id3v1) # ResOk THEN
  217. id3v1 := NIL;
  218. END;
  219. RETURN ResOk;
  220. END Open;
  221. PROCEDURE InitTable(VAR table: ARRAY OF ARRAY OF LONGINT);
  222. BEGIN
  223. table[0][0] := 0; table[1][0] := 0; table[2][0] := 0; table[3][0] := 0; table[4][0] := 0; table[5][0] := 0;
  224. table[0][1] :=32; table[1][1] := 32; table[2][1] := 32; table[3][1] := 32; table[4][1] := 8; table[5][1] := 8;
  225. table[0][2] :=64; table[1][2] := 48; table[2][2] := 40; table[3][2] := 48; table[4][2] := 16; table[5][2] := 16;
  226. table[0][3] :=96; table[1][3] := 56; table[2][3] := 48; table[3][3] := 56; table[4][3] := 24; table[5][3] := 24;
  227. table[0][4] :=128; table[1][4] := 64; table[2][4] := 56; table[3][4] := 64; table[4][4] := 32; table[5][4] := 32;
  228. table[0][5] :=160; table[1][5] := 80; table[2][5] := 64; table[3][5] := 80; table[4][5] := 40; table[5][5] := 64;
  229. table[0][6] :=192; table[1][6] := 96; table[2][6] := 80; table[3][6] := 96; table[4][6] := 48 ; table[5][6] := 80;
  230. table[0][7] :=224; table[1][7] := 112; table[2][7] := 96; table[3][7] := 112; table[4][7] := 56; table[5][7] := 56;
  231. table[0][8] :=256; table[1][8] := 128; table[2][8] := 112; table[3][8] := 128; table[4][8] := 64; table[5][8] := 64;
  232. table[0][9] :=288; table[1][9] := 160; table[2][9] := 128; table[3][9] := 144; table[4][9] := 80; table[5][9] := 128;
  233. table[0][10] := 320; table[1][10] := 192; table[2][10] := 160; table[3][10] := 160; table[4][10] := 96; table[5][10] := 160;
  234. table[0][11] := 352; table[1][11] := 224; table[2][11] := 192; table[3][11] := 176; table[4][11] := 112; table[5][11] := 112;
  235. table[0][12] := 384; table[1][12] := 256; table[2][12] := 224; table[3][12] := 192; table[4][12] := 128; table[5][12] := 128;
  236. table[0][13] := 416; table[1][13] := 320; table[2][13] := 256; table[3][13] := 224; table[4][13] := 144; table[5][13] := 256;
  237. table[0][14] := 448; table[1][14] := 384; table[2][14] := 320; table[3][14] := 256; table[4][14] := 160; table[5][14] := 320;
  238. table[0][15] := -1; table[1][15] := -1; table[2][15] := -1; table[3][15] := -1; table[4][15] := -1; table[5][15] := -1;
  239. END InitTable;
  240. END MP3Info;
  241. (* Window Components *)
  242. StandardDialog* = OBJECT(WMDialogs.Dialog);
  243. VAR
  244. width*, height*: LONGINT;
  245. ok*, abort*: WMStandardComponents.Button;
  246. content*: WMComponents.VisualComponent;
  247. buttonPanel*: WMStandardComponents.Panel;
  248. PROCEDURE &New*(title: String; bounds: WMRectangles.Rectangle; width, height: LONGINT);
  249. BEGIN
  250. x := bounds.l + ((bounds.r - bounds.l - width) DIV 2); IF x < 0 THEN x := 0 END;
  251. y := bounds.t + ((bounds.b - bounds.t - height) DIV 2); IF y < 20 THEN y := 20 END;
  252. SELF.width := width; SELF.height := height;
  253. SetTitle(title);
  254. errors := FALSE;
  255. CreateDialog;
  256. WireDialog;
  257. Init(content.bounds.GetWidth(), content.bounds.GetHeight(), FALSE);
  258. SetContent(content);
  259. END New;
  260. PROCEDURE Show*;
  261. BEGIN
  262. result := -1;
  263. manager := WMWindowManager.GetDefaultManager();
  264. manager.Add(x, y, SELF, {WMWindowManager.FlagFrame, WMWindowManager.FlagStayOnTop});
  265. manager.SetFocus(SELF);
  266. content.Reset(NIL, NIL);
  267. BEGIN {EXCLUSIVE}
  268. AWAIT(result >= 0)
  269. END;
  270. manager.Remove(SELF)
  271. END Show;
  272. PROCEDURE ShowNonModal*;
  273. BEGIN
  274. result := -1;
  275. manager := WMWindowManager.GetDefaultManager();
  276. manager.Add(x, y, SELF, {WMWindowManager.FlagFrame, WMWindowManager.FlagStayOnTop});
  277. manager.SetFocus(SELF);
  278. END ShowNonModal;
  279. PROCEDURE CreateDialog*;
  280. VAR
  281. panel: WMStandardComponents.Panel;
  282. manager: WMWindowManager.WindowManager;
  283. windowStyle: WMWindowManager.WindowStyle;
  284. BEGIN
  285. manager := WMWindowManager.GetDefaultManager();
  286. windowStyle := manager.GetStyle();
  287. NEW(panel); panel.bounds.SetExtents(width, height);
  288. panel.fillColor.Set(windowStyle.bgColor);
  289. panel.takesFocus.Set(FALSE);
  290. NEW(buttonPanel); buttonPanel.bounds.SetHeight(30); buttonPanel.alignment.Set(WMComponents.AlignBottom);
  291. panel.AddContent(buttonPanel);
  292. NEW(abort);
  293. abort.bounds.SetExtents(60,30);
  294. abort.alignment.Set(WMComponents.AlignRight);
  295. abort.caption.SetAOC("Abort");
  296. buttonPanel.AddContent(abort);
  297. NEW(ok);
  298. ok.bounds.SetExtents(60,30);
  299. ok.alignment.Set(WMComponents.AlignRight);
  300. ok.caption.SetAOC("Ok");
  301. buttonPanel.AddContent(ok);
  302. content := panel
  303. END CreateDialog;
  304. PROCEDURE WireDialog;
  305. BEGIN
  306. ok.onClick.Add(Ok);
  307. abort.onClick.Add(Abort);
  308. END WireDialog;
  309. END StandardDialog;
  310. FileDialog* = OBJECT(StandardDialog);
  311. VAR
  312. path*: WMProperties.StringProperty;
  313. explorer: ExplorerPanel;
  314. PROCEDURE CreateDialog*;
  315. VAR
  316. bearing: WMRectangles.Rectangle;
  317. BEGIN
  318. CreateDialog^;
  319. NEW(path, NIL, NIL, NIL);
  320. path.Set(Strings.NewString(""));
  321. bearing := WMRectangles.MakeRect(3, 3, 3, 3);
  322. NEW(explorer);
  323. explorer.alignment.Set(WMComponents.AlignClient);
  324. content.AddContent(explorer);
  325. END CreateDialog;
  326. PROCEDURE Ok(sender, data: ANY);
  327. VAR
  328. dirEntries: WMSystemComponents.DirEntries;
  329. str: ARRAY MaxLen OF CHAR;
  330. BEGIN
  331. dirEntries := explorer.list.list.GetSelection();
  332. IF (LEN(dirEntries) > 0) & (dirEntries[0] # NIL) &(dirEntries[0].name # NIL) & (dirEntries[0].path # NIL) THEN
  333. COPY(dirEntries[0].path^, str);
  334. Strings.Append(str, "/");
  335. Strings.Append(str, dirEntries[0].name^);
  336. path.Set(Strings.NewString(str));
  337. END;
  338. Ok^(sender, data);
  339. END Ok;
  340. END FileDialog;
  341. PropertyPage* = OBJECT(WMComponents.VisualComponent);
  342. VAR
  343. tab: WMTabComponents.Tab;
  344. owner*: PropertySheet;
  345. PROCEDURE UpdateData*(save: BOOLEAN);
  346. END UpdateData;
  347. END PropertyPage;
  348. PropertySheet* = OBJECT(StandardDialog);
  349. VAR
  350. tabs: WMTabComponents.Tabs;
  351. curPage: PropertyPage;
  352. PROCEDURE CreateDialog*;
  353. VAR
  354. topPanel: WMStandardComponents.Panel;
  355. BEGIN
  356. CreateDialog^;
  357. NEW(topPanel);
  358. topPanel.bounds.SetHeight(20); topPanel.alignment.Set(WMComponents.AlignTop); topPanel.fillColor.Set(LightGray);
  359. content.AddContent(topPanel);
  360. NEW(tabs);
  361. tabs.alignment.Set(WMComponents.AlignTop); tabs.bounds.SetExtents(width,20);
  362. tabs.onSelectTab.Add(TabSelected);
  363. topPanel.AddContent(tabs);
  364. END CreateDialog;
  365. PROCEDURE TabSelected(sender, data: ANY);
  366. VAR
  367. tab: WMTabComponents.Tab;
  368. BEGIN
  369. IF (data # NIL) THEN
  370. tab := data(WMTabComponents.Tab);
  371. IF tab.data # NIL THEN
  372. IF curPage # NIL THEN
  373. content.RemoveContent(curPage);
  374. END;
  375. curPage := tab.data(PropertyPage);
  376. content.AddContent(curPage);
  377. curPage.Reset(NIL, NIL);
  378. curPage.Invalidate();
  379. curPage.Resized;
  380. END;
  381. END;
  382. END TabSelected;
  383. PROCEDURE AddPage*(page: PropertyPage; name: String);
  384. VAR
  385. tab: WMTabComponents.Tab;
  386. BEGIN
  387. page.owner := SELF;
  388. tab := tabs.NewTab();
  389. tabs.SetTabCaption(tab, name);
  390. tabs.SetTabData(tab, page);
  391. page.tab := tab;
  392. tabs.AddTab(tab);
  393. END AddPage;
  394. PROCEDURE SelectPage*(page: PropertyPage);
  395. BEGIN
  396. tabs.Select(page.tab);
  397. curPage := page;
  398. IF curPage # NIL THEN
  399. content.RemoveContent(page);
  400. END;
  401. content.AddContent(page);
  402. END SelectPage;
  403. END PropertySheet;
  404. ProgressBar* = OBJECT(WMComponents.VisualComponent)
  405. VAR
  406. start*, end*, cur*: WMProperties.Int32Property;
  407. color*: WMProperties.ColorProperty;
  408. borderColor*: WMProperties.ColorProperty;
  409. PROCEDURE &Init*;
  410. VAR
  411. BEGIN
  412. Init^();
  413. NEW(color, NIL, NIL, NIL);
  414. NEW(borderColor, NIL, NIL, NIL);
  415. NEW(start, NIL, NIL, NIL);
  416. NEW(end, NIL, NIL, NIL);
  417. NEW(cur, NIL, NIL, NIL);
  418. END Init;
  419. PROCEDURE SetPos*(pos: Streams.Position);
  420. BEGIN
  421. IF pos < start.Get() THEN
  422. pos := start.Get();
  423. ELSIF pos > end.Get() THEN
  424. pos := end.Get();
  425. END;
  426. cur.Set(pos);
  427. Invalidate();
  428. END SetPos;
  429. PROCEDURE GetPos*(): Streams.Position;
  430. BEGIN
  431. RETURN cur.Get();
  432. END GetPos;
  433. PROCEDURE SetRange*(start, end: LONGINT);
  434. BEGIN
  435. SELF.start.Set(start);
  436. SELF.end.Set(end);
  437. cur.Set(start);
  438. END SetRange;
  439. PROCEDURE StepIt*;
  440. BEGIN
  441. IF cur.Get() < end.Get() THEN
  442. cur.Set(cur.Get() + 1);
  443. Invalidate;
  444. END;
  445. END StepIt;
  446. PROCEDURE DrawBackground*(canvas: WMGraphics.Canvas);
  447. VAR
  448. rect: WMRectangles.Rectangle;
  449. width: LONGINT;
  450. pt: ARRAY 4 OF WMGraphics.Point2d;
  451. BEGIN
  452. IF end.Get() > start.Get() THEN
  453. width := (cur.Get()-start.Get()) * bounds.GetWidth() DIV (end.Get()-start.Get());
  454. END;
  455. rect := WMRectangles.MakeRect(0, 0, width, bounds.GetHeight());
  456. canvas.Fill(rect, color.Get(), WMGraphics.ModeCopy);
  457. rect := GetClientRect();
  458. rect.l := width;
  459. canvas.Fill(rect, fillColor.Get(), WMGraphics.ModeCopy);
  460. pt[0].x := 0; pt[0].y := 0;
  461. pt[1].x := bounds.GetWidth()-1; pt[1].y := 0;
  462. pt[2].x := bounds.GetWidth()-1; pt[2].y := bounds.GetHeight()-1;
  463. pt[3].x := 0; pt[3].y := bounds.GetHeight()-1;
  464. canvas.PolyLine(pt, 4, TRUE, borderColor.Get(), WMGraphics.ModeCopy);
  465. END DrawBackground;
  466. END ProgressBar;
  467. ListBox* = OBJECT(WMComponents.VisualComponent);
  468. VAR
  469. grid: WMStringGrids.StringGrid;
  470. nofRows: LONGINT;
  471. caption*: WMProperties.StringProperty;
  472. label: WMStandardComponents.Label;
  473. selected*: WMProperties.Int32Property;
  474. onSelectionChanged* : WMEvents.EventSource;
  475. PROCEDURE &Init*;
  476. VAR
  477. leftPanel, rightPanel: WMStandardComponents.Panel;
  478. BEGIN
  479. Init^();
  480. NEW(caption, NIL, NIL, NIL); properties.Add(caption);
  481. NEW(selected, NIL, NIL, NIL); properties.Add(selected);
  482. NEW(onSelectionChanged, SELF, NIL, NIL, NIL);
  483. NEW(leftPanel); leftPanel.bounds.SetWidth(80); leftPanel.alignment.Set(WMComponents.AlignLeft);
  484. AddContent(leftPanel);
  485. NEW(label); label.bounds.SetHeight(14); label.alignment.Set(WMComponents.AlignTop); label.textColor.Set(Black);
  486. leftPanel.AddContent(label);
  487. NEW(rightPanel); rightPanel.alignment.Set(WMComponents.AlignClient);
  488. AddContent(rightPanel);
  489. NEW(grid);
  490. grid.alignment.Set(WMComponents.AlignClient);
  491. rightPanel.AddContent(grid);
  492. grid.onSelect.Add(SelectionHandler);
  493. grid.model.Acquire;
  494. grid.model.SetNofCols(1);
  495. grid.SetSelectionMode(WMGrids.GridSelectSingleRow);
  496. grid.model.Release;
  497. END Init;
  498. PROCEDURE Update*;
  499. BEGIN
  500. Reset(NIL, NIL);
  501. Invalidate();
  502. Resized;
  503. END Update;
  504. PROCEDURE Clear*;
  505. BEGIN
  506. nofRows := 0;
  507. grid.model.Acquire;
  508. grid.model.SetNofRows(nofRows);
  509. grid.model.Release;
  510. END Clear;
  511. PROCEDURE SelectionHandler*(sender, data: ANY);
  512. VAR
  513. scol, srow, ecol, erow: LONGINT;
  514. BEGIN
  515. grid. GetSelection(scol, srow, ecol, erow );
  516. selected.Set(srow);
  517. END SelectionHandler;
  518. PROCEDURE RecacheProperties;
  519. BEGIN
  520. label.caption.Set(caption.Get());
  521. grid.SetSelection(0, selected.Get(), 0, selected.Get());
  522. onSelectionChanged.Call(selected);
  523. RecacheProperties^;
  524. END RecacheProperties;
  525. PROCEDURE PropertyChanged(sender, property: ANY);
  526. BEGIN
  527. IF property = caption THEN
  528. label.caption.Set(caption.Get());
  529. ELSIF property = selected THEN
  530. grid.SetSelection(0, selected.Get(), 0, selected.Get());
  531. onSelectionChanged.Call(selected);
  532. ELSE
  533. PropertyChanged^(sender, property);
  534. END;
  535. END PropertyChanged;
  536. PROCEDURE Add*(name: String; data: ANY);
  537. BEGIN
  538. grid.model.Acquire;
  539. INC(nofRows);
  540. grid.model.SetNofRows(nofRows);
  541. grid.model.SetCellText(0, nofRows-1, name);
  542. grid.model.SetCellData(0, nofRows-1, data);
  543. grid.model.Release;
  544. END Add;
  545. END ListBox;
  546. ExplorerPanel* = OBJECT(WMComponents.VisualComponent);
  547. VAR
  548. tree*: WMSystemComponents.DirectoryTree;
  549. list: WMFileManager.FileListPanel;
  550. PROCEDURE &Init*;
  551. VAR
  552. panel, sidePanel: WMStandardComponents.Panel;
  553. resizer: WMStandardComponents.Resizer;
  554. BEGIN
  555. Init^();
  556. NEW(panel);
  557. panel.alignment.Set(WMComponents.AlignClient);
  558. panel.fillColor.Set(White);
  559. AddContent(panel);
  560. NEW(sidePanel);
  561. sidePanel.alignment.Set(WMComponents.AlignLeft);
  562. sidePanel.bounds.SetWidth(200);
  563. NEW(resizer);
  564. resizer.alignment.Set(WMComponents.AlignRight);
  565. resizer.bounds.SetWidth(4);
  566. sidePanel.AddContent(resizer);
  567. NEW(tree);
  568. tree.alignment.Set(WMComponents.AlignClient);
  569. sidePanel.AddContent(tree);
  570. panel.AddContent(sidePanel);
  571. tree.onPathChanged.Add(PathChanged);
  572. NEW(list);
  573. list.alignment.Set(WMComponents.AlignClient);
  574. panel.AddContent(list);
  575. END Init;
  576. PROCEDURE PathChanged(sender, data: ANY);
  577. BEGIN
  578. list.pathProp.Set(tree.currentPath.Get());
  579. END PathChanged;
  580. END ExplorerPanel;
  581. PROCEDURE ReadID3v1(VAR filename: String; VAR id3v1: ID3v1): LONGINT;
  582. VAR
  583. file: Files.File;
  584. r: Files.Reader;
  585. id, buf: ARRAY 128 OF CHAR;
  586. len, bytesRead: LONGINT;
  587. BEGIN
  588. file := Files.Old(filename^);
  589. IF file = NIL THEN
  590. RETURN ResErr;
  591. END;
  592. Files.OpenReader(r, file, 0);
  593. len := file.Length();
  594. r.SkipBytes(len-128);
  595. r.Bytes(buf, 0, 128, bytesRead);
  596. Strings.Copy(buf, 0, 3, id);
  597. IF id # "TAG" THEN RETURN ResErr; END;
  598. Strings.Copy(buf, 3, 30, id3v1.Title);
  599. Strings.Copy(buf, 33, 30, id3v1.Artist);
  600. Strings.Copy(buf, 63, 30, id3v1.Album);
  601. RETURN ResOk;
  602. END ReadID3v1;
  603. PROCEDURE ConvertLE16Int*(CONST buf : ARRAY OF CHAR): LONGINT;
  604. BEGIN
  605. RETURN ASH(ORD(buf[1]), 8) + ORD(buf[0]);
  606. END ConvertLE16Int;
  607. PROCEDURE ConvertLE32Int*(CONST buf : ARRAY OF CHAR): LONGINT;
  608. BEGIN
  609. RETURN ASH(ORD(buf[3]), 24) + ASH(ORD(buf[2]), 16) + ASH(ORD(buf[1]), 8) + ORD(buf[0]);
  610. END ConvertLE32Int;
  611. PROCEDURE ConvertBE16Int*(CONST buf : ARRAY OF CHAR): LONGINT;
  612. BEGIN
  613. RETURN ASH(ORD(buf[0]), 8) + ORD(buf[1]);
  614. END ConvertBE16Int;
  615. PROCEDURE ConvertBE32Int*(CONST buf : ARRAY OF CHAR): LONGINT;
  616. BEGIN
  617. RETURN ASH(ORD(buf[0]), 24) + ASH(ORD(buf[1]), 16) + ASH(ORD(buf[2]), 8) + ORD(buf[3]);
  618. END ConvertBE32Int;
  619. PROCEDURE SetLE16*(x: INTEGER; VAR dst : ARRAY OF CHAR);
  620. BEGIN
  621. dst[0] := CHR(x MOD 100H);
  622. dst[1] := CHR(x DIV 100H MOD 100H);
  623. END SetLE16;
  624. PROCEDURE SetLE32*(x: LONGINT; VAR dst: ARRAY OF CHAR);
  625. BEGIN
  626. dst[0] := CHR(x MOD 100H);
  627. dst[1] := CHR(x DIV 100H MOD 100H);
  628. dst[2] := CHR(x DIV 10000H MOD 100H);
  629. dst[3] := CHR(x DIV 1000000H MOD 100H);
  630. END SetLE32;
  631. PROCEDURE SetBE16*(x: INTEGER; VAR dst : ARRAY OF CHAR);
  632. BEGIN
  633. dst[1] := CHR(x MOD 100H);
  634. dst[0] := CHR(x DIV 100H MOD 100H);
  635. END SetBE16;
  636. PROCEDURE SetBE32*(x: LONGINT; VAR dst: ARRAY OF CHAR);
  637. BEGIN
  638. dst[3] := CHR(x MOD 100H);
  639. dst[2] := CHR(x DIV 100H MOD 100H);
  640. dst[1] := CHR(x DIV 10000H MOD 100H);
  641. dst[0] := CHR(x DIV 1000000H MOD 100H);
  642. END SetBE32;
  643. PROCEDURE Mp3ToWave*(srcFileName, destFileName : Strings.String; onConvertStatusChanged: StatusProc) : LONGINT;
  644. VAR
  645. res: WORD;
  646. srcFile, destFile : Files.File;
  647. decoder: Codecs.AudioDecoder;
  648. encoder: Codecs.AudioEncoder;
  649. in : Streams.Reader;
  650. out : Files.Writer;
  651. buffer : SoundDevices.Buffer;
  652. convertStatus: ConvertingStatus;
  653. bytesEncoded: LONGINT;
  654. BEGIN
  655. NEW(convertStatus);
  656. decoder := Codecs.GetAudioDecoder("MP3");
  657. IF decoder = NIL THEN
  658. KernelLog.String("Could not open MP3DEcoder");
  659. RETURN ResErr;
  660. END;
  661. encoder := Codecs.GetAudioEncoder("WAV");
  662. IF encoder = NIL THEN
  663. KernelLog.String("Could not open WAV Encoder");
  664. RETURN ResErr;
  665. END;
  666. srcFile := Files.Old(srcFileName^);
  667. destFile := Files.New(destFileName^);
  668. IF destFile = NIL THEN
  669. RETURN ResErr;
  670. END;
  671. Files.Register(destFile);
  672. Files.OpenWriter(out, destFile, 0);
  673. in := Codecs.OpenInputStream(srcFileName^);
  674. IF (in = NIL) OR (out = NIL) THEN
  675. RETURN ResErr;
  676. END;
  677. decoder.Open(in, res);
  678. decoder.SetStreamLength(srcFile.Length());
  679. NEW(buffer);
  680. buffer.len := 4096;
  681. NEW(buffer.data, 4096);
  682. encoder.Open(out, 44100, 16, 2, res);
  683. WHILE decoder.HasMoreData() & (res = ResOk) DO
  684. decoder.FillBuffer(buffer);
  685. encoder.Write(buffer, res);
  686. INC(bytesEncoded, buffer.len);
  687. IF onConvertStatusChanged # NIL THEN
  688. convertStatus.bytesEncoded := bytesEncoded;
  689. onConvertStatusChanged(convertStatus);
  690. END;
  691. END;
  692. encoder.Close(res);
  693. RETURN res;
  694. END Mp3ToWave;
  695. PROCEDURE GetFreeSpace*(CONST destination: ARRAY OF CHAR; VAR freeSpace: LONGINT): LONGINT;
  696. VAR
  697. fs: Files.FileSystem;
  698. prefix, name: ARRAY MaxLen OF CHAR;
  699. res: WORD;
  700. BEGIN
  701. res := ResErr;
  702. Files.SplitName(destination, prefix, name);
  703. fs := Files.This(prefix);
  704. IF fs # NIL THEN
  705. freeSpace := (fs.vol.Available() DIV 1024) * fs.vol.blockSize;
  706. res := ResOk;
  707. END;
  708. RETURN res;
  709. END GetFreeSpace;
  710. PROCEDURE IsReadOnly*(CONST destination: ARRAY OF CHAR; VAR readOnly: BOOLEAN): LONGINT;
  711. VAR
  712. fs: Files.FileSystem;
  713. prefix, name: ARRAY MaxLen OF CHAR;
  714. res: WORD;
  715. BEGIN
  716. res := ResErr;
  717. Files.SplitName(destination, prefix, name);
  718. fs := Files.This(prefix);
  719. IF (fs # NIL) & (fs.vol # NIL) THEN
  720. readOnly := Files.ReadOnly IN fs.vol.flags;
  721. res := ResOk;
  722. END;
  723. RETURN res;
  724. END IsReadOnly;
  725. PROCEDURE GetDevice*(file: Files.File; VAR device: Disks.Device): LONGINT;
  726. VAR
  727. fs: Files.FileSystem;
  728. res: WORD;
  729. BEGIN
  730. res := ResErr;
  731. fs := file.fs;
  732. IF (fs # NIL) & (fs.vol # NIL) THEN
  733. IF fs.vol IS DiskVolumes.Volume THEN
  734. device := fs.vol(DiskVolumes.Volume).dev;
  735. res := ResOk;
  736. ELSIF fs.vol IS FATVolumes.Volume THEN
  737. device := fs.vol(FATVolumes.Volume).dev;
  738. res := ResOk;
  739. ELSIF fs.vol IS ISO9660Volumes.Volume THEN
  740. device := fs.vol(FATVolumes.Volume).dev;
  741. res := ResOk;
  742. END;
  743. END;
  744. RETURN res;
  745. END GetDevice;
  746. PROCEDURE IsOnSameController*(device1, device2: Disks.Device): BOOLEAN;
  747. BEGIN
  748. IF (device1 IS ATADisks.Device) & (device2 IS ATADisks.Device) THEN
  749. RETURN device1(ATADisks.Device).controller = device2(ATADisks.Device).controller;
  750. END;
  751. RETURN FALSE;
  752. END IsOnSameController;
  753. PROCEDURE ClearBuffer*(VAR buf: ARRAY OF CHAR; ofs, len: LONGINT);
  754. VAR
  755. adr: ADDRESS;
  756. rem: SIZE;
  757. BEGIN
  758. ASSERT((ofs+len) <= LEN(buf));
  759. adr := ADDRESSOF(buf);
  760. INC(adr, ofs);
  761. rem := adr MOD 4;
  762. WHILE rem > 0 DO
  763. SYSTEM.PUT8(adr, 0X);
  764. DEC(rem); INC(adr); DEC(len);
  765. END;
  766. WHILE len >= 4 DO
  767. SYSTEM.PUT32(adr, 0H);
  768. INC(adr, 4); DEC(len, 4);
  769. END;
  770. WHILE len > 0 DO
  771. SYSTEM.PUT8(adr, 0X);
  772. INC(adr); DEC(len);
  773. END;
  774. END ClearBuffer;
  775. END CDRecordUtils.