1+ using System ;
2+ using System . Runtime . InteropServices ;
3+ using System . IO ;
4+ using BasicAudio . Extensions ;
5+ using System . Text ;
6+
7+ namespace BasicAudio
8+ {
9+
10+ /// <summary>
11+ /// This class is a wrapper for the Windows API calls to play wave, midi or mp3 files. Although this is .Net Standard 2 compliant
12+ /// it requires PInvokes to the Windows API and will fail in environments like Linux, Windows Universal Apps, Server environments, etc.
13+ /// </summary>
14+ /// <remarks>
15+ /// This class was originally designed for use in traditional Windows apps long before the invent of .Net Standard. It is highly
16+ /// recommended to use a library like NAudio for advanced audio capability.
17+ /// </remarks>
18+ public class AudioPlayer
19+ {
20+ //*********************************************************************************************************************
21+ //
22+ // Class: AudioPlayer
23+ // Organization: http://www.blakepell.com
24+ // Initial Date: 03/31/2007
25+ // Last Updated: 04/05/2019
26+ // Programmer(s): Blake Pell, blakepell@hotmail.com
27+ //
28+ //*********************************************************************************************************************
29+
30+ [ DllImport ( "winmm.dll" ) ]
31+ static extern int mciSendString ( string command , StringBuilder buffer , int bufferSize , IntPtr hwndCallback ) ;
32+
33+ /// <summary>
34+ /// Constructor
35+ /// </summary>
36+ public AudioPlayer ( )
37+ {
38+
39+ }
40+
41+ /// <summary>
42+ /// Constructor: Location is the filename of the media to play. Wave files, mp3 files and midi files are the supported formats.
43+ /// </summary>
44+ /// <param name="filePath">File path of the media to play.</param>
45+ public AudioPlayer ( string filePath )
46+ {
47+ this . Filename = filePath ;
48+ }
49+
50+ /// <summary>
51+ /// Plays the file that is specified as the filename.
52+ /// </summary>
53+ public void Play ( )
54+ {
55+ // Some basic checks to make sure a file exists and is available, if not throw an exception the caller
56+ // can then handle.
57+ if ( string . IsNullOrEmpty ( Filename ) )
58+ {
59+ throw new FileNotFoundException ( "No file was provided to Play." ) ;
60+ }
61+
62+ if ( ! File . Exists ( this . Filename ) )
63+ {
64+ throw new FileNotFoundException ( "File does not exist or is inaccessible." ) ;
65+ }
66+
67+ // There is probably a better way to do this than to go off of the extension but this is what
68+ // we're going to do for now unless someone has a need to better identify the file type.
69+ switch ( Filename . SafeRight ( 3 ) . ToLower ( ) )
70+ {
71+ case "mp3" :
72+ mciSendString ( $ "open \" { Filename } \" type mpegvideo alias audiofile", null , 0 , IntPtr . Zero ) ;
73+
74+ string playCommand = "play audiofile from 0" ;
75+
76+ if ( Wait == true )
77+ {
78+ playCommand += " wait" ;
79+ }
80+
81+ mciSendString ( playCommand , null , 0 , IntPtr . Zero ) ;
82+ break ;
83+ case "wav" :
84+ mciSendString ( $ "open \" { Filename } \" type waveaudio alias audiofile", null , 0 , IntPtr . Zero ) ;
85+ mciSendString ( "play audiofile from 0" , null , 0 , IntPtr . Zero ) ;
86+ break ;
87+ case "mid" :
88+ case "idi" :
89+ var sb = new StringBuilder ( 128 ) ;
90+
91+ mciSendString ( "stop midi" , sb , 0 , IntPtr . Zero ) ;
92+ mciSendString ( "close midi" , sb , 0 , IntPtr . Zero ) ;
93+ mciSendString ( $ "open sequencer!{ Filename } alias midi", sb , 0 , IntPtr . Zero ) ;
94+ mciSendString ( "play midi" , sb , 0 , IntPtr . Zero ) ;
95+ break ;
96+ default :
97+ Close ( ) ;
98+ throw new Exception ( "File type not supported." ) ;
99+ }
100+
101+ IsPaused = false ;
102+
103+ }
104+
105+ /// <summary>
106+ /// Pause the current play back.
107+ /// </summary>
108+ public void Pause ( )
109+ {
110+ mciSendString ( "pause audiofile" , null , 0 , IntPtr . Zero ) ;
111+ IsPaused = true ;
112+ }
113+
114+ /// <summary>
115+ /// Resume the current play back if it is currently paused.
116+ /// </summary>
117+ public void Resume ( )
118+ {
119+ mciSendString ( "resume audiofile" , null , 0 , IntPtr . Zero ) ;
120+ IsPaused = false ;
121+ }
122+
123+ /// <summary>
124+ /// Stop the current file if it's playing.
125+ /// </summary>
126+ public void Stop ( )
127+ {
128+ mciSendString ( "stop audiofile" , null , 0 , IntPtr . Zero ) ;
129+ }
130+
131+ /// <summary>
132+ /// Close the file.
133+ /// </summary>
134+ public void Close ( )
135+ {
136+ mciSendString ( "close audiofile" , null , 0 , IntPtr . Zero ) ;
137+ }
138+
139+ /// <summary>
140+ /// Halt the program until the .wav file is done playing. Be careful, this will lock the entire program up until the
141+ /// file is done playing. It behaves as if the Windows Sleep API is called while the file is playing (and maybe it is, I don't
142+ /// actually know, I'm just theorizing). :P
143+ /// </summary>
144+ public bool Wait { get ; set ; } = false ;
145+
146+ /// <summary>
147+ /// Sets the audio file's time format via the mciSendString API.
148+ /// </summary>
149+ /// <value></value>
150+ public int Milleseconds
151+ {
152+ get
153+ {
154+ var sb = new StringBuilder ( 255 ) ;
155+ mciSendString ( "set audiofile time format milliseconds" , null , 0 , IntPtr . Zero ) ;
156+ mciSendString ( "status audiofile length" , sb , 255 , IntPtr . Zero ) ;
157+
158+ // Get rid of the nulls
159+ sb . Replace ( "\0 " , "" ) ;
160+
161+ // Get rid of the nulls, they muck things up
162+ if ( string . IsNullOrEmpty ( sb . ToString ( ) ) )
163+ {
164+ return 0 ;
165+ }
166+ else
167+ {
168+ return Convert . ToInt32 ( sb . ToString ( ) ) ;
169+ }
170+ }
171+ }
172+
173+ /// <summary>
174+ /// Gets the status of the current playback file via the mciSendString API.
175+ /// </summary>
176+ public string Status
177+ {
178+ get
179+ {
180+ var sb = new StringBuilder ( ) ;
181+ mciSendString ( "status audiofile mode" , sb , 255 , IntPtr . Zero ) ;
182+
183+ // Get rid of the nulls
184+ sb . Replace ( "\0 " , "" ) ;
185+
186+ return sb . ToString ( ) ;
187+ }
188+ }
189+
190+ /// <summary>
191+ /// Gets the file size of the current audio file.
192+ /// </summary>
193+ public long FileSize
194+ {
195+ get
196+ {
197+ try
198+ {
199+ return new FileInfo ( Filename ) . Length ;
200+ }
201+ catch
202+ {
203+ return - 1 ;
204+ }
205+ }
206+ }
207+
208+ /// <summary>
209+ /// Gets the channels of the file via the mciSendString API.
210+ /// </summary>
211+ public int Channels
212+ {
213+ get
214+ {
215+ var sb = new StringBuilder ( 255 ) ;
216+ mciSendString ( "status audiofile channels" , sb , 255 , IntPtr . Zero ) ;
217+
218+ if ( sb . ToString ( ) . IsNumeric ( ) )
219+ {
220+ return Convert . ToInt32 ( sb . ToString ( ) ) ;
221+ }
222+ else
223+ {
224+ return - 1 ;
225+ }
226+ }
227+ }
228+
229+ /// <summary>
230+ /// Used for debugging purposes.
231+ /// </summary>
232+ public string Debug
233+ {
234+ get
235+ {
236+ var sb = new StringBuilder ( 255 ) ;
237+ mciSendString ( "status audiofile channels" , sb , 255 , IntPtr . Zero ) ;
238+
239+ return sb . ToString ( ) ;
240+ }
241+ }
242+
243+ /// <summary>
244+ /// Whether or not the current playback is paused.
245+ /// </summary>
246+ public bool IsPaused { get ; set ; } = false ;
247+
248+ /// <summary>
249+ /// The current filename of the file that is to be played back.
250+ /// </summary>
251+ /// <value></value>
252+ public string Filename { get ; set ; }
253+
254+ }
255+
256+ }
0 commit comments