MODULE CDRecordUtils;
IMPORT
SYSTEM, Codecs, Strings, Streams, Files, SoundDevices, KernelLog, Disks, DiskVolumes, FATVolumes, ISO9660Volumes, ATADisks,
WMWindowManager, WMComponents, WMStandardComponents, WMFileManager, WMSystemComponents, WMGrids, WMStringGrids, WMDialogs,
WMEvents, WMTabComponents, WMProperties, WMGraphics, WMRectangles;
CONST
MaxLen = 256;
ResOk=0; ResErr=1;
MPEGVer1 = 3;
MPEGVer2 = 2;
MPEGVer25 = 0;
CUnknown* = 0H;
CPCM* = 1H;
CMsADPCM* = 2H;
ErrFileNotFound* = 100;
ErrNoISOImage* = 101;
White = SHORT(0FFFFFFFFH);
Black = 0000000FFH;
LightGray = SHORT(0C8C8C8FFH);
DarkGray = SHORT(0A0A0A0FFH);
TYPE
String = Strings.String;
Status* = OBJECT END Status;
ConvertingStatus* = OBJECT(Status)
VAR
bytesEncoded*: LONGINT;
END ConvertingStatus;
StatusProc* = PROCEDURE {DELEGATE} (status: Status);
WAVInfo* = OBJECT
VAR
compression*, size*, nofchannels*, samplerate*, encoding* : LONGINT;
PROCEDURE Open*(filename : Strings.String): LONGINT;
VAR
bytesRead: LONGINT;
file: Files.File;
r: Files.Reader;
buf: ARRAY 8 OF CHAR;
BEGIN
file := Files.Old(filename^);
IF file = NIL THEN
RETURN 1;
END;
Files.OpenReader(r, file, 0);
buf[4] := 0X;
r.Bytes(buf, 0, 4, bytesRead);
IF buf # "RIFF" THEN
RETURN ResErr;
END;
r.Bytes(buf, 0, 4, bytesRead);
size := ConvertLE32Int(buf);
IF size < 1024 THEN size := file.Length() - 8; END;
r.Bytes(buf, 0, 4, bytesRead);
IF buf # "WAVE" THEN
RETURN ResErr;
END;
r.Bytes(buf, 0, 4, bytesRead);
IF buf # "fmt " THEN
RETURN ResErr;
END;
r.Bytes(buf, 0, 4, bytesRead);
r.Bytes(buf, 0, 2, bytesRead);
compression := ConvertLE16Int(buf);
r.Bytes(buf, 0, 2, bytesRead);
nofchannels := ConvertLE16Int(buf);
r.Bytes(buf, 0, 4, bytesRead);
samplerate := ConvertLE32Int(buf);
r.Bytes(buf, 0, 6, bytesRead);
r.Bytes(buf, 0, 2, bytesRead);
encoding := ConvertLE16Int(buf);
RETURN ResOk;
END Open;
END WAVInfo;
Frame = RECORD
mpegver, bitrate, samplerate, padding, layer, size : LONGINT
END;
ID3v1* = OBJECT
VAR
Title*, Artist*, Album: ARRAY 31 OF CHAR;
END ID3v1;
MP3Info* = OBJECT
VAR
nofframes*, playtime* : LONGINT;
id3v1*: ID3v1;
bitrateTable: ARRAY 6, 16 OF LONGINT;
PROCEDURE &New*;
BEGIN
InitTable(bitrateTable);
id3v1 := NIL;
END New;
PROCEDURE GetNextFrame(r: Files.Reader; VAR frame: Frame): LONGINT;
VAR
n, start, bytesRead, tmp: LONGINT;
chr: CHAR;
buf : ARRAY 4 OF CHAR;
BEGIN
start := -1; n := 0;
REPEAT
r.Bytes(buf, 0, 1, bytesRead);
IF (bytesRead = 1) & (buf[0] = 0FFX) THEN
chr := r.Peek();
IF ASH(ORD(chr), -5) = 7 THEN
start := n;
r.Bytes(buf, 1, 3, bytesRead);
END;
END;
INC(n, 1);
UNTIL (n > 10000) OR (bytesRead < 1) OR (start # -1);
IF start = -1 THEN
RETURN ResErr;
END;
tmp := ASH(ORD(buf[1]), -3) MOD 4;
CASE tmp OF
0: frame.mpegver := MPEGVer25;
| 2: frame.mpegver := MPEGVer2;
| 3: frame.mpegver := MPEGVer1;
ELSE RETURN ResErr;
END;
tmp := ASH(ORD(buf[1]), -1) MOD 4;
CASE tmp OF
1: frame.layer := 3;
| 2: frame.layer := 2;
| 3: frame.layer := 1;
ELSE RETURN ResErr;
END;
tmp := ASH(ORD(buf[2]), -4);
IF frame.mpegver = MPEGVer1 THEN
CASE frame.layer OF
1: frame.bitrate := bitrateTable[0][tmp];
| 2: frame.bitrate := bitrateTable[1][tmp];
| 3: frame.bitrate := bitrateTable[2][tmp];
ELSE RETURN ResErr;
END;
ELSE
CASE frame.layer OF
1: frame.bitrate := bitrateTable[3][tmp];
| 2: frame.bitrate := bitrateTable[4][tmp];
| 3: frame.bitrate := bitrateTable[5][tmp];
ELSE RETURN ResErr;
END;
END;
tmp := ASH(ORD(buf[2]), -2) MOD 4;
IF frame.mpegver = MPEGVer1 THEN
CASE tmp OF
0: frame.samplerate := 44100;
| 1: frame.samplerate := 48000;
| 2: frame.samplerate := 32000;
ELSE RETURN ResErr;
END;
ELSIF frame.mpegver = MPEGVer2 THEN
CASE tmp OF
0: frame.samplerate := 22050;
| 1: frame.samplerate := 24000;
| 2: frame.samplerate := 16000;
ELSE RETURN ResErr;
END;
ELSIF frame.mpegver = MPEGVer25 THEN
CASE tmp OF
0: frame.samplerate := 11025;
| 1: frame.samplerate := 12000;
| 2: frame.samplerate := 8000;
ELSE RETURN ResErr;
END;
END;
frame.padding := ASH(ORD(buf[2]), -1) MOD 2;
IF frame.mpegver = MPEGVer1 THEN
IF frame.layer = 1 THEN
tmp := 48000;
ELSE
tmp := 144000;
END;
ELSE
IF frame.layer = 1 THEN
tmp := 24000
ELSE
tmp := 72000;
END;
END;
frame.size := tmp*frame.bitrate DIV frame.samplerate + frame.padding;
RETURN ResOk;
END GetNextFrame;
PROCEDURE Open*(filename: String): LONGINT;
VAR
file : Files.File;
r: Files.Reader;
frame: Frame;
BEGIN
nofframes := 0; playtime := 0;
file := Files.Old(filename^);
IF file = NIL THEN
RETURN ResErr;
END;
Files.OpenReader(r, file, 0);
WHILE GetNextFrame(r, frame) = ResOk DO
INC(nofframes);
r.SkipBytes(frame.size-4);
INC(playtime, (8*frame.size) DIV frame.bitrate);
END;
IF nofframes < 1 THEN RETURN ResErr END;
playtime := (playtime+1000-1) DIV 1000;
NEW(id3v1);
IF ReadID3v1(filename, id3v1) # ResOk THEN
id3v1 := NIL;
END;
RETURN ResOk;
END Open;
PROCEDURE InitTable(VAR table: ARRAY OF ARRAY OF LONGINT);
BEGIN
table[0][0] := 0; table[1][0] := 0; table[2][0] := 0; table[3][0] := 0; table[4][0] := 0; table[5][0] := 0;
table[0][1] :=32; table[1][1] := 32; table[2][1] := 32; table[3][1] := 32; table[4][1] := 8; table[5][1] := 8;
table[0][2] :=64; table[1][2] := 48; table[2][2] := 40; table[3][2] := 48; table[4][2] := 16; table[5][2] := 16;
table[0][3] :=96; table[1][3] := 56; table[2][3] := 48; table[3][3] := 56; table[4][3] := 24; table[5][3] := 24;
table[0][4] :=128; table[1][4] := 64; table[2][4] := 56; table[3][4] := 64; table[4][4] := 32; table[5][4] := 32;
table[0][5] :=160; table[1][5] := 80; table[2][5] := 64; table[3][5] := 80; table[4][5] := 40; table[5][5] := 64;
table[0][6] :=192; table[1][6] := 96; table[2][6] := 80; table[3][6] := 96; table[4][6] := 48 ; table[5][6] := 80;
table[0][7] :=224; table[1][7] := 112; table[2][7] := 96; table[3][7] := 112; table[4][7] := 56; table[5][7] := 56;
table[0][8] :=256; table[1][8] := 128; table[2][8] := 112; table[3][8] := 128; table[4][8] := 64; table[5][8] := 64;
table[0][9] :=288; table[1][9] := 160; table[2][9] := 128; table[3][9] := 144; table[4][9] := 80; table[5][9] := 128;
table[0][10] := 320; table[1][10] := 192; table[2][10] := 160; table[3][10] := 160; table[4][10] := 96; table[5][10] := 160;
table[0][11] := 352; table[1][11] := 224; table[2][11] := 192; table[3][11] := 176; table[4][11] := 112; table[5][11] := 112;
table[0][12] := 384; table[1][12] := 256; table[2][12] := 224; table[3][12] := 192; table[4][12] := 128; table[5][12] := 128;
table[0][13] := 416; table[1][13] := 320; table[2][13] := 256; table[3][13] := 224; table[4][13] := 144; table[5][13] := 256;
table[0][14] := 448; table[1][14] := 384; table[2][14] := 320; table[3][14] := 256; table[4][14] := 160; table[5][14] := 320;
table[0][15] := -1; table[1][15] := -1; table[2][15] := -1; table[3][15] := -1; table[4][15] := -1; table[5][15] := -1;
END InitTable;
END MP3Info;
StandardDialog* = OBJECT(WMDialogs.Dialog);
VAR
width*, height*: LONGINT;
ok*, abort*: WMStandardComponents.Button;
content*: WMComponents.VisualComponent;
buttonPanel*: WMStandardComponents.Panel;
PROCEDURE &New*(title: String; bounds: WMRectangles.Rectangle; width, height: LONGINT);
BEGIN
x := bounds.l + ((bounds.r - bounds.l - width) DIV 2); IF x < 0 THEN x := 0 END;
y := bounds.t + ((bounds.b - bounds.t - height) DIV 2); IF y < 20 THEN y := 20 END;
SELF.width := width; SELF.height := height;
SetTitle(title);
errors := FALSE;
CreateDialog;
WireDialog;
Init(content.bounds.GetWidth(), content.bounds.GetHeight(), FALSE);
SetContent(content);
END New;
PROCEDURE Show*;
BEGIN
result := -1;
manager := WMWindowManager.GetDefaultManager();
manager.Add(x, y, SELF, {WMWindowManager.FlagFrame, WMWindowManager.FlagStayOnTop});
manager.SetFocus(SELF);
content.Reset(NIL, NIL);
BEGIN {EXCLUSIVE}
AWAIT(result >= 0)
END;
manager.Remove(SELF)
END Show;
PROCEDURE ShowNonModal*;
BEGIN
result := -1;
manager := WMWindowManager.GetDefaultManager();
manager.Add(x, y, SELF, {WMWindowManager.FlagFrame, WMWindowManager.FlagStayOnTop});
manager.SetFocus(SELF);
END ShowNonModal;
PROCEDURE CreateDialog*;
VAR
panel: WMStandardComponents.Panel;
manager: WMWindowManager.WindowManager;
windowStyle: WMWindowManager.WindowStyle;
BEGIN
manager := WMWindowManager.GetDefaultManager();
windowStyle := manager.GetStyle();
NEW(panel); panel.bounds.SetExtents(width, height);
panel.fillColor.Set(windowStyle.bgColor);
panel.takesFocus.Set(FALSE);
NEW(buttonPanel); buttonPanel.bounds.SetHeight(30); buttonPanel.alignment.Set(WMComponents.AlignBottom);
panel.AddContent(buttonPanel);
NEW(abort);
abort.bounds.SetExtents(60,30);
abort.alignment.Set(WMComponents.AlignRight);
abort.caption.SetAOC("Abort");
buttonPanel.AddContent(abort);
NEW(ok);
ok.bounds.SetExtents(60,30);
ok.alignment.Set(WMComponents.AlignRight);
ok.caption.SetAOC("Ok");
buttonPanel.AddContent(ok);
content := panel
END CreateDialog;
PROCEDURE WireDialog;
BEGIN
ok.onClick.Add(Ok);
abort.onClick.Add(Abort);
END WireDialog;
END StandardDialog;
FileDialog* = OBJECT(StandardDialog);
VAR
path*: WMProperties.StringProperty;
explorer: ExplorerPanel;
PROCEDURE CreateDialog*;
VAR
bearing: WMRectangles.Rectangle;
BEGIN
CreateDialog^;
NEW(path, NIL, NIL, NIL);
path.Set(Strings.NewString(""));
bearing := WMRectangles.MakeRect(3, 3, 3, 3);
NEW(explorer);
explorer.alignment.Set(WMComponents.AlignClient);
content.AddContent(explorer);
END CreateDialog;
PROCEDURE Ok(sender, data: ANY);
VAR
dirEntries: WMSystemComponents.DirEntries;
str: ARRAY MaxLen OF CHAR;
BEGIN
dirEntries := explorer.list.list.GetSelection();
IF (LEN(dirEntries) > 0) & (dirEntries[0] # NIL) &(dirEntries[0].name # NIL) & (dirEntries[0].path # NIL) THEN
COPY(dirEntries[0].path^, str);
Strings.Append(str, "/");
Strings.Append(str, dirEntries[0].name^);
path.Set(Strings.NewString(str));
END;
Ok^(sender, data);
END Ok;
END FileDialog;
PropertyPage* = OBJECT(WMComponents.VisualComponent);
VAR
tab: WMTabComponents.Tab;
owner*: PropertySheet;
PROCEDURE UpdateData*(save: BOOLEAN);
END UpdateData;
END PropertyPage;
PropertySheet* = OBJECT(StandardDialog);
VAR
tabs: WMTabComponents.Tabs;
curPage: PropertyPage;
PROCEDURE CreateDialog*;
VAR
topPanel: WMStandardComponents.Panel;
BEGIN
CreateDialog^;
NEW(topPanel);
topPanel.bounds.SetHeight(20); topPanel.alignment.Set(WMComponents.AlignTop); topPanel.fillColor.Set(LightGray);
content.AddContent(topPanel);
NEW(tabs);
tabs.alignment.Set(WMComponents.AlignTop); tabs.bounds.SetExtents(width,20);
tabs.onSelectTab.Add(TabSelected);
topPanel.AddContent(tabs);
END CreateDialog;
PROCEDURE TabSelected(sender, data: ANY);
VAR
tab: WMTabComponents.Tab;
BEGIN
IF (data # NIL) THEN
tab := data(WMTabComponents.Tab);
IF tab.data # NIL THEN
IF curPage # NIL THEN
content.RemoveContent(curPage);
END;
curPage := tab.data(PropertyPage);
content.AddContent(curPage);
curPage.Reset(NIL, NIL);
curPage.Invalidate();
curPage.Resized;
END;
END;
END TabSelected;
PROCEDURE AddPage*(page: PropertyPage; name: String);
VAR
tab: WMTabComponents.Tab;
BEGIN
page.owner := SELF;
tab := tabs.NewTab();
tabs.SetTabCaption(tab, name);
tabs.SetTabData(tab, page);
page.tab := tab;
tabs.AddTab(tab);
END AddPage;
PROCEDURE SelectPage*(page: PropertyPage);
BEGIN
tabs.Select(page.tab);
curPage := page;
IF curPage # NIL THEN
content.RemoveContent(page);
END;
content.AddContent(page);
END SelectPage;
END PropertySheet;
ProgressBar* = OBJECT(WMComponents.VisualComponent)
VAR
start*, end*, cur*: WMProperties.Int32Property;
color*: WMProperties.ColorProperty;
borderColor*: WMProperties.ColorProperty;
PROCEDURE &Init*;
VAR
BEGIN
Init^();
NEW(color, NIL, NIL, NIL);
NEW(borderColor, NIL, NIL, NIL);
NEW(start, NIL, NIL, NIL);
NEW(end, NIL, NIL, NIL);
NEW(cur, NIL, NIL, NIL);
END Init;
PROCEDURE SetPos*(pos: LONGINT);
BEGIN
IF pos < start.Get() THEN
pos := start.Get();
ELSIF pos > end.Get() THEN
pos := end.Get();
END;
cur.Set(pos);
Invalidate();
END SetPos;
PROCEDURE GetPos*(): LONGINT;
BEGIN
RETURN cur.Get();
END GetPos;
PROCEDURE SetRange*(start, end: LONGINT);
BEGIN
SELF.start.Set(start);
SELF.end.Set(end);
cur.Set(start);
END SetRange;
PROCEDURE StepIt*;
BEGIN
IF cur.Get() < end.Get() THEN
cur.Set(cur.Get() + 1);
Invalidate;
END;
END StepIt;
PROCEDURE DrawBackground*(canvas: WMGraphics.Canvas);
VAR
rect: WMRectangles.Rectangle;
width: LONGINT;
pt: ARRAY 4 OF WMGraphics.Point2d;
BEGIN
IF end.Get() > start.Get() THEN
width := (cur.Get()-start.Get()) * bounds.GetWidth() DIV (end.Get()-start.Get());
END;
rect := WMRectangles.MakeRect(0, 0, width, bounds.GetHeight());
canvas.Fill(rect, color.Get(), WMGraphics.ModeCopy);
rect := GetClientRect();
rect.l := width;
canvas.Fill(rect, fillColor.Get(), WMGraphics.ModeCopy);
pt[0].x := 0; pt[0].y := 0;
pt[1].x := bounds.GetWidth()-1; pt[1].y := 0;
pt[2].x := bounds.GetWidth()-1; pt[2].y := bounds.GetHeight()-1;
pt[3].x := 0; pt[3].y := bounds.GetHeight()-1;
canvas.PolyLine(pt, 4, TRUE, borderColor.Get(), WMGraphics.ModeCopy);
END DrawBackground;
END ProgressBar;
ListBox* = OBJECT(WMComponents.VisualComponent);
VAR
grid: WMStringGrids.StringGrid;
nofRows: LONGINT;
caption*: WMProperties.StringProperty;
label: WMStandardComponents.Label;
selected*: WMProperties.Int32Property;
onSelectionChanged* : WMEvents.EventSource;
PROCEDURE &Init*;
VAR
leftPanel, rightPanel: WMStandardComponents.Panel;
BEGIN
Init^();
NEW(caption, NIL, NIL, NIL); properties.Add(caption);
NEW(selected, NIL, NIL, NIL); properties.Add(selected);
NEW(onSelectionChanged, SELF, NIL, NIL, NIL);
NEW(leftPanel); leftPanel.bounds.SetWidth(80); leftPanel.alignment.Set(WMComponents.AlignLeft);
AddContent(leftPanel);
NEW(label); label.bounds.SetHeight(14); label.alignment.Set(WMComponents.AlignTop); label.textColor.Set(Black);
leftPanel.AddContent(label);
NEW(rightPanel); rightPanel.alignment.Set(WMComponents.AlignClient);
AddContent(rightPanel);
NEW(grid);
grid.alignment.Set(WMComponents.AlignClient);
rightPanel.AddContent(grid);
grid.onSelect.Add(SelectionHandler);
grid.model.Acquire;
grid.model.SetNofCols(1);
grid.SetSelectionMode(WMGrids.GridSelectSingleRow);
grid.model.Release;
END Init;
PROCEDURE Update*;
BEGIN
Reset(NIL, NIL);
Invalidate();
Resized;
END Update;
PROCEDURE Clear*;
BEGIN
nofRows := 0;
grid.model.Acquire;
grid.model.SetNofRows(nofRows);
grid.model.Release;
END Clear;
PROCEDURE SelectionHandler*(sender, data: ANY);
VAR
scol, srow, ecol, erow: LONGINT;
BEGIN
grid. GetSelection(scol, srow, ecol, erow );
selected.Set(srow);
END SelectionHandler;
PROCEDURE RecacheProperties;
BEGIN
label.caption.Set(caption.Get());
grid.SetSelection(0, selected.Get(), 0, selected.Get());
onSelectionChanged.Call(selected);
RecacheProperties^;
END RecacheProperties;
PROCEDURE PropertyChanged(sender, property: ANY);
BEGIN
IF property = caption THEN
label.caption.Set(caption.Get());
ELSIF property = selected THEN
grid.SetSelection(0, selected.Get(), 0, selected.Get());
onSelectionChanged.Call(selected);
ELSE
PropertyChanged^(sender, property);
END;
END PropertyChanged;
PROCEDURE Add*(name: String; data: ANY);
BEGIN
grid.model.Acquire;
INC(nofRows);
grid.model.SetNofRows(nofRows);
grid.model.SetCellText(0, nofRows-1, name);
grid.model.SetCellData(0, nofRows-1, data);
grid.model.Release;
END Add;
END ListBox;
ExplorerPanel* = OBJECT(WMComponents.VisualComponent);
VAR
tree*: WMSystemComponents.DirectoryTree;
list: WMFileManager.FileListPanel;
PROCEDURE &Init*;
VAR
panel, sidePanel: WMStandardComponents.Panel;
resizer: WMStandardComponents.Resizer;
BEGIN
Init^();
NEW(panel);
panel.alignment.Set(WMComponents.AlignClient);
panel.fillColor.Set(White);
AddContent(panel);
NEW(sidePanel);
sidePanel.alignment.Set(WMComponents.AlignLeft);
sidePanel.bounds.SetWidth(200);
NEW(resizer);
resizer.alignment.Set(WMComponents.AlignRight);
resizer.bounds.SetWidth(4);
sidePanel.AddContent(resizer);
NEW(tree);
tree.alignment.Set(WMComponents.AlignClient);
sidePanel.AddContent(tree);
panel.AddContent(sidePanel);
tree.onPathChanged.Add(PathChanged);
NEW(list);
list.alignment.Set(WMComponents.AlignClient);
panel.AddContent(list);
END Init;
PROCEDURE PathChanged(sender, data: ANY);
BEGIN
list.pathProp.Set(tree.currentPath.Get());
END PathChanged;
END ExplorerPanel;
PROCEDURE ReadID3v1(VAR filename: String; VAR id3v1: ID3v1): LONGINT;
VAR
file: Files.File;
r: Files.Reader;
id, buf: ARRAY 128 OF CHAR;
len, bytesRead: LONGINT;
BEGIN
file := Files.Old(filename^);
IF file = NIL THEN
RETURN ResErr;
END;
Files.OpenReader(r, file, 0);
len := file.Length();
r.SkipBytes(len-128);
r.Bytes(buf, 0, 128, bytesRead);
Strings.Copy(buf, 0, 3, id);
IF id # "TAG" THEN RETURN ResErr; END;
Strings.Copy(buf, 3, 30, id3v1.Title);
Strings.Copy(buf, 33, 30, id3v1.Artist);
Strings.Copy(buf, 63, 30, id3v1.Album);
RETURN ResOk;
END ReadID3v1;
PROCEDURE ConvertLE16Int*(CONST buf : ARRAY OF CHAR): LONGINT;
BEGIN
RETURN ASH(ORD(buf[1]), 8) + ORD(buf[0]);
END ConvertLE16Int;
PROCEDURE ConvertLE32Int*(CONST buf : ARRAY OF CHAR): LONGINT;
BEGIN
RETURN ASH(ORD(buf[3]), 24) + ASH(ORD(buf[2]), 16) + ASH(ORD(buf[1]), 8) + ORD(buf[0]);
END ConvertLE32Int;
PROCEDURE ConvertBE16Int*(CONST buf : ARRAY OF CHAR): LONGINT;
BEGIN
RETURN ASH(ORD(buf[0]), 8) + ORD(buf[1]);
END ConvertBE16Int;
PROCEDURE ConvertBE32Int*(CONST buf : ARRAY OF CHAR): LONGINT;
BEGIN
RETURN ASH(ORD(buf[0]), 24) + ASH(ORD(buf[1]), 16) + ASH(ORD(buf[2]), 8) + ORD(buf[3]);
END ConvertBE32Int;
PROCEDURE SetLE16*(x: INTEGER; VAR dst : ARRAY OF CHAR);
BEGIN
dst[0] := CHR(x MOD 100H);
dst[1] := CHR(x DIV 100H MOD 100H);
END SetLE16;
PROCEDURE SetLE32*(x: LONGINT; VAR dst: ARRAY OF CHAR);
BEGIN
dst[0] := CHR(x MOD 100H);
dst[1] := CHR(x DIV 100H MOD 100H);
dst[2] := CHR(x DIV 10000H MOD 100H);
dst[3] := CHR(x DIV 1000000H MOD 100H);
END SetLE32;
PROCEDURE SetBE16*(x: INTEGER; VAR dst : ARRAY OF CHAR);
BEGIN
dst[1] := CHR(x MOD 100H);
dst[0] := CHR(x DIV 100H MOD 100H);
END SetBE16;
PROCEDURE SetBE32*(x: LONGINT; VAR dst: ARRAY OF CHAR);
BEGIN
dst[3] := CHR(x MOD 100H);
dst[2] := CHR(x DIV 100H MOD 100H);
dst[1] := CHR(x DIV 10000H MOD 100H);
dst[0] := CHR(x DIV 1000000H MOD 100H);
END SetBE32;
PROCEDURE Mp3ToWave*(srcFileName, destFileName : Strings.String; onConvertStatusChanged: StatusProc) : LONGINT;
VAR
res: LONGINT;
srcFile, destFile : Files.File;
decoder: Codecs.AudioDecoder;
encoder: Codecs.AudioEncoder;
in : Streams.Reader;
out : Files.Writer;
buffer : SoundDevices.Buffer;
convertStatus: ConvertingStatus;
bytesEncoded: LONGINT;
BEGIN
NEW(convertStatus);
decoder := Codecs.GetAudioDecoder("MP3");
IF decoder = NIL THEN
KernelLog.String("Could not open MP3DEcoder");
RETURN ResErr;
END;
encoder := Codecs.GetAudioEncoder("WAV");
IF encoder = NIL THEN
KernelLog.String("Could not open WAV Encoder");
RETURN ResErr;
END;
srcFile := Files.Old(srcFileName^);
destFile := Files.New(destFileName^);
IF destFile = NIL THEN
RETURN ResErr;
END;
Files.Register(destFile);
Files.OpenWriter(out, destFile, 0);
in := Codecs.OpenInputStream(srcFileName^);
IF (in = NIL) OR (out = NIL) THEN
RETURN ResErr;
END;
decoder.Open(in, res);
decoder.SetStreamLength(srcFile.Length());
NEW(buffer);
buffer.len := 4096;
NEW(buffer.data, 4096);
encoder.Open(out, 44100, 16, 2, res);
WHILE decoder.HasMoreData() & (res = ResOk) DO
decoder.FillBuffer(buffer);
encoder.Write(buffer, res);
INC(bytesEncoded, buffer.len);
IF onConvertStatusChanged # NIL THEN
convertStatus.bytesEncoded := bytesEncoded;
onConvertStatusChanged(convertStatus);
END;
END;
encoder.Close(res);
RETURN res;
END Mp3ToWave;
PROCEDURE GetFreeSpace*(CONST destination: ARRAY OF CHAR; VAR freeSpace: LONGINT): LONGINT;
VAR
fs: Files.FileSystem;
prefix, name: ARRAY MaxLen OF CHAR;
res: LONGINT;
BEGIN
res := ResErr;
Files.SplitName(destination, prefix, name);
fs := Files.This(prefix);
IF fs # NIL THEN
freeSpace := (fs.vol.Available() DIV 1024) * fs.vol.blockSize;
res := ResOk;
END;
RETURN res;
END GetFreeSpace;
PROCEDURE IsReadOnly*(CONST destination: ARRAY OF CHAR; VAR readOnly: BOOLEAN): LONGINT;
VAR
fs: Files.FileSystem;
prefix, name: ARRAY MaxLen OF CHAR;
res: LONGINT;
BEGIN
res := ResErr;
Files.SplitName(destination, prefix, name);
fs := Files.This(prefix);
IF (fs # NIL) & (fs.vol # NIL) THEN
readOnly := Files.ReadOnly IN fs.vol.flags;
res := ResOk;
END;
RETURN res;
END IsReadOnly;
PROCEDURE GetDevice*(file: Files.File; VAR device: Disks.Device): LONGINT;
VAR
fs: Files.FileSystem;
res: LONGINT;
BEGIN
res := ResErr;
fs := file.fs;
IF (fs # NIL) & (fs.vol # NIL) THEN
IF fs.vol IS DiskVolumes.Volume THEN
device := fs.vol(DiskVolumes.Volume).dev;
res := ResOk;
ELSIF fs.vol IS FATVolumes.Volume THEN
device := fs.vol(FATVolumes.Volume).dev;
res := ResOk;
ELSIF fs.vol IS ISO9660Volumes.Volume THEN
device := fs.vol(FATVolumes.Volume).dev;
res := ResOk;
END;
END;
RETURN res;
END GetDevice;
PROCEDURE IsOnSameController*(device1, device2: Disks.Device): BOOLEAN;
BEGIN
IF (device1 IS ATADisks.Device) & (device2 IS ATADisks.Device) THEN
RETURN device1(ATADisks.Device).controller = device2(ATADisks.Device).controller;
END;
RETURN FALSE;
END IsOnSameController;
PROCEDURE ClearBuffer*(VAR buf: ARRAY OF CHAR; ofs, len: LONGINT);
VAR
adr: SYSTEM.ADDRESS;
rem: SYSTEM.SIZE;
BEGIN
ASSERT((ofs+len) <= LEN(buf));
adr := SYSTEM.ADR(buf);
INC(adr, ofs);
rem := adr MOD 4;
WHILE rem > 0 DO
SYSTEM.PUT8(adr, 0X);
DEC(rem); INC(adr); DEC(len);
END;
WHILE len >= 4 DO
SYSTEM.PUT32(adr, 0H);
INC(adr, 4); DEC(len, 4);
END;
WHILE len > 0 DO
SYSTEM.PUT8(adr, 0X);
INC(adr); DEC(len);
END;
END ClearBuffer;
END CDRecordUtils.