Author: Lou Adler
How do I get the length of a Wav file without using a TMediaPlayer to open the file?
Answer:
Getting the length is possible using the MCI_SENDSTRING API call, but that does get
involved. However, a better method has been suggested that accesses the file
directly and interprets its own internal data to obtain the information.
Here is the function:
1 function GetWaveLength(WaveFile: string): Double;
2 var
3 groupID: array[0..3] of char;
4 riffType: array[0..3] of char;
5 BytesPerSec: Integer;
6 Stream: TFileStream;
7 dataSize: Integer;
8 // chunk seeking function,
9 // -1 means: chunk not found
10
11 function GotoChunk(ID: string): Integer;
12 var
13 chunkID: array[0..3] of char;
14 chunkSize: Integer;
15 begin
16 Result := -1;
17
18 with Stream do
19 begin
20 // index of first chunk
21 Position := 12;
22 repeat
23 // read next chunk
24 read(chunkID, 4);
25 read(chunkSize, 4);
26 if chunkID <> ID then
27 // skip chunk
28 Position := Position + chunkSize;
29 until(chunkID = ID) or (Position >= Size);
30 if chunkID = ID then
31 // chunk found,
32 // return chunk size
33 Result := chunkSize;
34 end;
35 end;
36
37 begin
38 Result := -1;
39 Stream := TFileStream.Create(WaveFile, fmOpenRead or fmShareDenyNone);
40 with Stream do
41 try
42 read(groupID, 4);
43 Position := Position + 4; // skip four bytes (file size)
44 read(riffType, 4);
45
46 if(groupID = 'RIFF') and (riffType = 'WAVE') then
47 begin
48 // search for format chunk
49 if GotoChunk('fmt') <> -1 then
50 begin
51 // found it
52 Position := Position + 8;
53 read(BytesPerSec, 4);
54 //search for data chunk
55 dataSize := GotoChunk('data');
56
57 if dataSize <> -1 then
58 // found it
59 Result := dataSize / BytesPerSec
60 end
61 end
62 finally
63 Free;
64 end;
65 end;
66
67 //This returns the number of seconds as a floating point number, which is not
68 necessarily the most helpful format. Far better to return it as a string
69 representing the time in hours, minutes and seconds. The following function
70 achieves this based on the number of seconds as an integer:
71
72 function SecondsToTimeStr(RemainingSeconds: Integer): string;
73 var
74 Hours, Minutes, Seconds: Integer;
75 HourString, MinuteString, SecondString: string;
76 begin
77 // Calculate Minutes
78 Seconds := RemainingSeconds mod 60;
79 Minutes := RemainingSeconds div 60;
80 Hours := Minutes div 60;
81 Minutes := Minutes - (Hours * 60);
82
83 if Hours < 10 then
84 HourString := '0' + IntToStr(Hours) + ':'
85 else
86 HourString := IntToStr(Hours) + ':';
87
88 if Minutes < 10 then
89 MinuteString := '0' + IntToStr(Minutes) + ':'
90 else
91 MinuteString := IntToStr(Minutes) + ':';
92
93 if Seconds < 10 then
94 SecondString := '0' + IntToStr(Seconds)
95 else
96 SecondString := IntToStr(Seconds);
97 Result := HourString + MinuteString + SecondString;
98 end;
99
100 //Having created these functions you can call them from any relevant event - for
101 example a button click:
102
103 procedure TForm1.Button1Click(Sender: TObject);
104 var
105 Seconds: Integer;
106 begin
107 Seconds := Trunc(GetWaveLength(Edit1.Text));
108 //gets only the Integer part of the length
109 Label1.Caption := SecondsToTimeStr(Seconds);
110 end;
111
112 You can even reduce this to a single line of code if you prefer:
113
114 procedure TForm1.Button1Click(Sender: TObject);
115 begin
116 Label1.Caption := SecondsToTimeStr(Trunc(GetWaveLength(Edit1.Text)));
117 end;
|