1+ use std:: fmt;
2+ use std:: path:: Path ;
3+ use std:: time:: Duration ;
4+
5+ use thiserror:: Error ;
6+
17#[ derive( Copy , Clone , Debug , Eq , PartialEq , Hash ) ]
28pub struct SoundId ( u32 ) ;
39
@@ -7,9 +13,76 @@ impl SoundId {
713 }
814}
915
16+ impl fmt:: Display for SoundId {
17+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
18+ write ! ( f, "{}" , self . 0 )
19+ }
20+ }
21+
22+ #[ derive( Debug , Error ) ]
23+ pub enum AudioError {
24+ #[ error( "audio output device unavailable: {0}" ) ]
25+ OutputUnavailable ( #[ from] rodio:: StreamError ) ,
26+ #[ error( "failed to resolve current directory: {0}" ) ]
27+ CurrentDirectory ( #[ source] std:: io:: Error ) ,
28+ #[ error( "failed to normalize audio file path {path:?}: {source}" ) ]
29+ PathNormalization {
30+ path : std:: path:: PathBuf ,
31+ #[ source]
32+ source : std:: io:: Error ,
33+ } ,
34+ #[ error( "failed to open audio file {path:?}: {source}" ) ]
35+ FileOpen {
36+ path : std:: path:: PathBuf ,
37+ #[ source]
38+ source : std:: io:: Error ,
39+ } ,
40+ #[ error( "failed to decode audio file {path:?}: {source}" ) ]
41+ Decode {
42+ path : std:: path:: PathBuf ,
43+ #[ source]
44+ source : rodio:: decoder:: DecoderError ,
45+ } ,
46+ #[ error( "failed to clone audio file handle {path:?}: {source}" ) ]
47+ FileClone {
48+ path : std:: path:: PathBuf ,
49+ #[ source]
50+ source : std:: io:: Error ,
51+ } ,
52+ #[ error( "sound {0} has not been loaded" ) ]
53+ SoundNotLoaded ( SoundId ) ,
54+ #[ error( "failed to create audio sink: {0}" ) ]
55+ SinkCreation ( #[ source] rodio:: PlayError ) ,
56+ #[ error( "failed to read audio metadata {path:?}: {source}" ) ]
57+ Metadata {
58+ path : std:: path:: PathBuf ,
59+ #[ source]
60+ source : std:: io:: Error ,
61+ } ,
62+ }
63+
64+ pub type AudioResult < T > = Result < T , AudioError > ;
65+
66+ #[ derive( Copy , Clone , Debug , Eq , PartialEq ) ]
67+ pub enum LoadStrategy {
68+ Auto ,
69+ Buffered ,
70+ Streaming ,
71+ }
72+
1073pub trait AudioBackend {
11- fn load ( & mut self , path : & str ) -> SoundId ;
12- fn play ( & mut self , sound : SoundId ) ;
74+ fn load ( & mut self , path : & Path , strategy : LoadStrategy ) -> AudioResult < SoundId > ;
75+ fn play ( & mut self , sound : SoundId ) -> AudioResult < ( ) > ;
76+ fn stop ( & mut self , sound : SoundId ) -> AudioResult < ( ) > ;
77+ fn pause ( & mut self , sound : SoundId ) -> AudioResult < ( ) > ;
78+ fn resume ( & mut self , sound : SoundId ) -> AudioResult < ( ) > ;
79+ fn set_volume ( & mut self , sound : SoundId , volume : f32 ) -> AudioResult < ( ) > ;
80+ fn stop_all ( & mut self ) ;
81+ fn set_master_volume ( & mut self , volume : f32 ) ;
82+ fn is_playing ( & self , sound : SoundId ) -> bool ;
83+ fn duration ( & self , sound : SoundId ) -> Option < Duration > ;
84+ fn unload ( & mut self , sound : SoundId ) -> AudioResult < ( ) > ;
85+ fn unload_all ( & mut self ) ;
1386}
1487
1588pub struct AudioSystem {
@@ -21,11 +94,75 @@ impl AudioSystem {
2194 Self { backend }
2295 }
2396
24- pub fn load ( & mut self , path : & str ) -> SoundId {
25- self . backend . load ( path)
97+ pub fn load < P > ( & mut self , path : P ) -> AudioResult < SoundId >
98+ where
99+ P : AsRef < Path > ,
100+ {
101+ self . load_with_strategy ( path, LoadStrategy :: Auto )
102+ }
103+
104+ pub fn load_with_strategy < P > ( & mut self , path : P , strategy : LoadStrategy ) -> AudioResult < SoundId >
105+ where
106+ P : AsRef < Path > ,
107+ {
108+ self . backend . load ( path. as_ref ( ) , strategy)
109+ }
110+
111+ pub fn load_buffered < P > ( & mut self , path : P ) -> AudioResult < SoundId >
112+ where
113+ P : AsRef < Path > ,
114+ {
115+ self . load_with_strategy ( path, LoadStrategy :: Buffered )
26116 }
27117
28- pub fn play ( & mut self , sound : SoundId ) {
118+ pub fn load_streaming < P > ( & mut self , path : P ) -> AudioResult < SoundId >
119+ where
120+ P : AsRef < Path > ,
121+ {
122+ self . load_with_strategy ( path, LoadStrategy :: Streaming )
123+ }
124+
125+ pub fn play ( & mut self , sound : SoundId ) -> AudioResult < ( ) > {
29126 self . backend . play ( sound)
30127 }
128+
129+ pub fn stop ( & mut self , sound : SoundId ) -> AudioResult < ( ) > {
130+ self . backend . stop ( sound)
131+ }
132+
133+ pub fn pause ( & mut self , sound : SoundId ) -> AudioResult < ( ) > {
134+ self . backend . pause ( sound)
135+ }
136+
137+ pub fn resume ( & mut self , sound : SoundId ) -> AudioResult < ( ) > {
138+ self . backend . resume ( sound)
139+ }
140+
141+ pub fn set_volume ( & mut self , sound : SoundId , volume : f32 ) -> AudioResult < ( ) > {
142+ self . backend . set_volume ( sound, volume)
143+ }
144+
145+ pub fn stop_all ( & mut self ) {
146+ self . backend . stop_all ( )
147+ }
148+
149+ pub fn set_master_volume ( & mut self , volume : f32 ) {
150+ self . backend . set_master_volume ( volume)
151+ }
152+
153+ pub fn is_playing ( & self , sound : SoundId ) -> bool {
154+ self . backend . is_playing ( sound)
155+ }
156+
157+ pub fn duration ( & self , sound : SoundId ) -> Option < Duration > {
158+ self . backend . duration ( sound)
159+ }
160+
161+ pub fn unload ( & mut self , sound : SoundId ) -> AudioResult < ( ) > {
162+ self . backend . unload ( sound)
163+ }
164+
165+ pub fn unload_all ( & mut self ) {
166+ self . backend . unload_all ( )
167+ }
31168}
0 commit comments