source: tags/1.3.8/Music.pas

Last change on this file was 680, checked in by chronos, 13 days ago
  • Fixed: Memory leaks from music player on application termination.
File size: 6.7 KB
Line 
1unit Music;
2
3interface
4
5uses
6 Classes, SysUtils, Dialogs, uos_flat, ctypes;
7
8type
9
10 { TMusicPlayer }
11
12 TMusicPlayer = class
13 private
14 FVolume: Single;
15 PlayerIndex1: Integer;
16 InputIndex1: Integer;
17 Initialized: Boolean;
18 PlayListItemIndex: Integer;
19 InputLength: Integer;
20 AutoPlayNext: Boolean;
21 LibrariesLoaded: Boolean;
22 NewPlayerIndex: Integer;
23 function GetPlaying: Boolean;
24 procedure Initialize;
25 procedure EndPlay(PlayerIndex: cint32);
26 function GetNextPlaylistItem: string;
27 procedure PlayNext(Data: PtrInt);
28 procedure SetVolume(AValue: Single);
29 public
30 Playlist: TStringList;
31 constructor Create;
32 destructor Destroy; override;
33 procedure RandomizePlaylist;
34 procedure LoadPlaylistFromDir(Directory: string);
35 procedure Play;
36 procedure Stop;
37 property Playing: Boolean read GetPlaying;
38 property Volume: Single read FVolume write SetVolume;
39 end;
40
41var
42 MusicPlayer: TMusicPlayer;
43
44
45implementation
46
47uses
48 Directories, Forms;
49
50{ TMusicPlayer }
51
52procedure TMusicPlayer.Initialize;
53var
54 SndFileFileName: string;
55 PortAudioFileName: string;
56 XmpFileName: string;
57begin
58 if Initialized then Exit;
59
60 {$IFDEF UNIX}
61 SndFileFileName := 'libsndfile.so';
62 PortAudioFileName := 'libportaudio.so';
63 XmpFileName := 'libxmp.so.4';
64 {$ELSE}
65 {$if defined(cpu64)}
66 SndFileFileName := 'LibSndFile-64.dll';
67 PortAudioFileName := 'LibPortaudio-64.dll';
68 XmpFileName := 'libxmp-64.dll';
69 {$ELSE}
70 SndFileFileName := 'LibSndFile-32.dll';
71 PortAudioFileName := 'LibPortaudio-32.dll';
72 XmpFileName := 'libxmp-32.dll';
73 {$ENDIF}
74 {$ENDIF}
75
76 if (PortAudioFileName <> 'system') and (PortAudioFileName <> '') then
77 if not uos_TestLoadLibrary(PChar(PortAudioFileName)) then begin
78 if uos_TestLoadLibrary(PChar(PortAudioFileName + '.1')) then
79 PortAudioFileName := PortAudioFileName + '.1'
80 else
81 if uos_TestLoadLibrary(PChar(PortAudioFileName + '.2')) then
82 PortAudioFileName := PortAudioFileName + '.2';
83 end;
84
85 // Optionally load SndFile
86 if (SndFileFileName <> 'system') and (SndFileFileName <> '') then
87 if not uos_TestLoadLibrary(PChar(SndFileFileName)) then begin
88 if uos_TestLoadLibrary(PChar(SndFileFileName + '.1')) then
89 SndFileFileName := SndFileFileName + '.1'
90 else
91 if uos_TestLoadLibrary(PChar(SndFileFileName + '.2')) then
92 SndFileFileName := SndFileFileName + '.2'
93 else SndFileFileName := '';
94 end;
95
96 if uos_LoadLib(PChar(PortAudioFileName), PChar(SndFileFileName), nil, nil,
97 nil, nil, PChar(XmpFileName)) = 0 then begin
98 LibrariesLoaded := True;
99 end else begin
100 LibrariesLoaded := False;
101 if uosLoadResult.PAloaderror = 1 then
102 WriteLn(StdErr, 'Error: ' + PortAudioFileName + ' not found.');
103 if uosLoadResult.PAloaderror = 2 then
104 WriteLn(StdErr, 'Error: ' + PortAudioFileName + ' can''t be loaded.');
105 if uosLoadResult.SFloaderror = 1 then
106 WriteLn(StdErr, 'Error: ' + SndFileFileName + ' not found.');
107 if uosLoadResult.SFloaderror = 2 then
108 WriteLn(StdErr, 'Error: ' + SndFileFileName + ' can''t be loaded.');
109 if uosLoadResult.XMloadError = 1 then
110 WriteLn(StdErr, 'Error: ' + XmpFileName + ' not found.');
111 if uosLoadResult.XMloadError = 2 then
112 WriteLn(StdErr, 'Error: ' + XmpFileName + ' can''t be loaded.');
113 end;
114
115 Initialized := True;
116end;
117
118function TMusicPlayer.GetPlaying: Boolean;
119begin
120 Result := PlayerIndex1 >= 0;
121end;
122
123procedure TMusicPlayer.EndPlay(PlayerIndex: cint32);
124begin
125 if AutoPlayNext then begin
126 if PlayerIndex = PlayerIndex1 then Application.QueueAsyncCall(PlayNext, 0);
127 end else PlayerIndex1 := -1;
128end;
129
130function TMusicPlayer.GetNextPlaylistItem: string;
131begin
132 Inc(PlayListItemIndex);
133 if PlayListItemIndex >= Playlist.Count then PlayListItemIndex := 0;
134 Result := Playlist[PlayListItemIndex];
135end;
136
137procedure TMusicPlayer.PlayNext(Data: PtrInt);
138begin
139 Play;
140end;
141
142procedure TMusicPlayer.SetVolume(AValue: Single);
143begin
144 if FVolume = AValue then Exit;
145 FVolume := AValue;
146 if FVolume > 1 then FVolume := 1;
147 if FVolume < 0 then FVolume := 0;
148 if Playing then
149 uos_InputSetDSPVolume(PlayerIndex1, InputIndex1, Volume, Volume, True);
150end;
151
152constructor TMusicPlayer.Create;
153begin
154 Playlist := TStringList.Create;
155 PlayerIndex1 := -1;
156 NewPlayerIndex := 0;
157 FVolume := 1;
158end;
159
160destructor TMusicPlayer.Destroy;
161begin
162 uos_free();
163 FreeAndNil(Playlist);
164 inherited;
165end;
166
167procedure TMusicPlayer.RandomizePlaylist;
168var
169 I: Integer;
170 Index: Integer;
171 TempPlaylist: TStringList;
172begin
173 if Playlist.Count < 2 then Exit;
174
175 TempPlaylist := TStringList.Create;
176 try
177 TempPlaylist.Assign(Playlist);
178 PlayList.Clear;
179 for I := 0 to TempPlaylist.Count - 1 do begin
180 Index := Random(TempPlaylist.Count);
181 PlayList.Add(TempPlaylist[Index]);
182 TempPlaylist.Delete(Index);
183 end;
184 finally
185 TempPlaylist.Free;
186 end;
187end;
188
189procedure TMusicPlayer.LoadPlaylistFromDir(Directory: string);
190var
191 SearchRec: TSearchRec;
192begin
193 Playlist.Clear;
194 Directory := IncludeTrailingPathDelimiter(Directory);
195 if FindFirst(Directory + '*', faAnyFile, SearchRec) = 0 then
196 try
197 repeat
198 if (SearchRec.Name = '.') or (SearchRec.Name = '..') or ((SearchRec.Attr and faDirectory) > 0) then Continue;
199 Playlist.Add(Directory + SearchRec.Name);
200 until FindNext(SearchRec) <> 0;
201 finally
202 FindClose(SearchRec);
203 end;
204end;
205
206procedure TMusicPlayer.Play;
207var
208 OutputIndex1: Integer;
209 FileName: string;
210begin
211 Initialize;
212 if not LibrariesLoaded then Exit;
213
214 AutoPlayNext := False;
215 if PlayerIndex1 >= 0 then uos_Stop(PlayerIndex1);
216
217 PlayerIndex1 := NewPlayerIndex;
218 Inc(NewPlayerIndex);
219
220 uos_CreatePlayer(PlayerIndex1);
221 uos_EndProc(PlayerIndex1, EndPlay);
222
223 FileName := GetNextPlaylistItem;
224 InputIndex1 := uos_AddFromFile(PlayerIndex1, PChar(FileName));
225 if InputIndex1 < 0 then begin
226 MessageDlg('Music file ' + FileName + ' doesn''t exist.', mtError, [mbYes], 0);
227 Exit;
228 end;
229
230 uos_InputSetPositionEnable(PlayerIndex1, InputIndex1, 1);
231 InputLength := uos_InputLength(PlayerIndex1, InputIndex1);
232 uos_InputAddDSPVolume(PlayerIndex1, InputIndex1, Volume, Volume);
233
234 OutputIndex1 := uos_AddIntoDevOut(PlayerIndex1, -1, -1, -1, -1, -1, -1, -1);
235 if OutputIndex1 < 0 then begin
236 MessageDlg('Music output doesn''t work.', mtError, [mbYes], 0);
237 Exit;
238 end;
239
240 uos_Play(PlayerIndex1);
241 AutoPlayNext := True;
242end;
243
244procedure TMusicPlayer.Stop;
245begin
246 Initialize;
247 if not LibrariesLoaded then Exit;
248
249 AutoPlayNext := False;
250 if PlayerIndex1 >= 0 then begin
251 Initialize;
252 uos_EndProc(PlayerIndex1, nil);
253 uos_Stop(PlayerIndex1);
254 end;
255 PlayerIndex1 := -1;
256end;
257
258initialization
259
260MusicPlayer := TMusicPlayer.Create;
261
262finalization
263
264FreeAndNil(MusicPlayer);
265
266end.
267
Note: See TracBrowser for help on using the repository browser.