@@ -21,7 +21,7 @@ type readSeekCloser struct {
2121}
2222
2323type readCloser struct {
24- io.Reader
24+ io.ReadSeeker
2525 io.Closer
2626}
2727
@@ -38,9 +38,41 @@ func newReadSeeker(source io.ReadCloser) io.ReadSeeker {
3838
3939// -------------------------------------------------------------------------------------
4040
41+ type playerState byte
42+
43+ const (
44+ playerPlay playerState = iota
45+ playerClosed
46+ playerPaused
47+ )
48+
49+ type PlayAction int
50+
51+ const (
52+ PlayRewind PlayAction = iota
53+ PlayContinue
54+ PlayPause
55+ PlayResume
56+ PlayStop
57+ )
58+
59+ type PlayOptions struct {
60+ Action PlayAction
61+ Wait bool
62+ Loop bool
63+ }
64+
65+ type soundPlayer struct {
66+ * audio.Player
67+ media Sound
68+ state playerState
69+ loop bool
70+ }
71+
4172type soundMgr struct {
73+ g * Game
4274 audioContext * audio.Context
43- players map [* audio. Player ]chan bool
75+ players map [* soundPlayer ]chan bool
4476 playersM sync.Mutex
4577}
4678
@@ -49,26 +81,32 @@ const (
4981 defaultRatio = 100.0
5082)
5183
52- func (p * soundMgr ) addPlayer (sp * audio. Player , done chan bool ) {
84+ func (p * soundMgr ) addPlayer (sp * soundPlayer , done chan bool ) {
5385 p .playersM .Lock ()
5486 defer p .playersM .Unlock ()
5587
5688 p .players [sp ] = done
5789}
5890
59- func (p * soundMgr ) init () {
91+ func (p * soundMgr ) init (g * Game ) {
6092 audioContext := audio .NewContext (defaultSampleRate )
6193 p .audioContext = audioContext
62- p .players = make (map [* audio.Player ]chan bool )
94+ p .players = make (map [* soundPlayer ]chan bool )
95+ p .g = g
6396}
6497
6598func (p * soundMgr ) update () {
6699 p .playersM .Lock ()
67100 defer p .playersM .Unlock ()
68101
69- var closed []* audio. Player
102+ var closed []* soundPlayer
70103 for sp , done := range p .players {
71- if ! sp .IsPlaying () {
104+ if ! sp .IsPlaying () && sp .state != playerPaused {
105+ if sp .loop {
106+ sp .Rewind ()
107+ sp .Play ()
108+ continue
109+ }
72110 sp .Close ()
73111 if done != nil {
74112 done <- true
@@ -85,20 +123,59 @@ func (p *soundMgr) stopAll() {
85123 p .playersM .Lock ()
86124 defer p .playersM .Unlock ()
87125
88- closed := make ([]* audio. Player , 0 , len (p .players ))
126+ closed := make ([]* soundPlayer , 0 , len (p .players ))
89127 for sp , done := range p .players {
90128 sp .Close ()
91129 if done != nil {
92130 done <- true
93131 }
132+ sp .state = playerClosed
94133 closed = append (closed , sp )
95134 }
96135 for _ , sp := range closed {
97136 delete (p .players , sp )
98137 }
99138}
100139
101- func (p * soundMgr ) play (source io.ReadCloser , wait ... bool ) (err error ) {
140+ func (p * soundMgr ) playAction (media Sound , opts * PlayOptions ) (err error ) {
141+ switch opts .Action {
142+ case PlayRewind :
143+ err = p .play (media , opts .Wait , opts .Loop )
144+ case PlayContinue :
145+ err = p .playContinue (media , opts .Wait , opts .Loop )
146+ case PlayStop :
147+ p .stop (media )
148+ case PlayResume :
149+ p .resume (media )
150+ case PlayPause :
151+ p .pause (media )
152+ }
153+ return
154+ }
155+
156+ func (p * soundMgr ) playContinue (media Sound , wait , loop bool ) (err error ) {
157+ p .playersM .Lock ()
158+ found := false
159+ for sp := range p .players {
160+ if sp .media .Path == media .Path {
161+ sp .loop = loop
162+ found = true
163+ }
164+ }
165+ p .playersM .Unlock ()
166+
167+ if ! found {
168+ err = p .play (media , wait , loop )
169+ }
170+ return
171+ }
172+
173+ func (p * soundMgr ) play (media Sound , wait , loop bool ) (err error ) {
174+ source , err := p .g .fs .Open (media .Path )
175+ if err != nil {
176+ panic (err )
177+ }
178+
102179 audioContext := p .audioContext
103180 d , _ , err := qaudio .Decode (newReadSeeker (source ))
104181 if err != nil {
@@ -108,25 +185,73 @@ func (p *soundMgr) play(source io.ReadCloser, wait ...bool) (err error) {
108185
109186 d = convert .ToStereo16 (d )
110187 d = convert .Resample (d , audioContext .SampleRate ())
111- sp , err := audioContext .NewPlayer (& readCloser {d , source })
188+
189+ sp := & soundPlayer {media : media , loop : loop }
190+ sp .Player , err = audioContext .NewPlayer (& readCloser {d , source })
112191 if err != nil {
113192 source .Close ()
114193 return
115194 }
116195
117- var waitDone = (wait != nil )
118196 var done chan bool
119- if waitDone {
197+ if wait {
120198 done = make (chan bool , 1 )
121199 }
122200 p .addPlayer (sp , done )
123201 sp .Play ()
124- if waitDone {
202+ if wait {
125203 waitForChan (done )
126204 }
127205 return
128206}
129207
208+ func (p * soundMgr ) stop (media Sound ) {
209+ p .playersM .Lock ()
210+ defer p .playersM .Unlock ()
211+
212+ closed := make ([]* soundPlayer , 0 , len (p .players ))
213+ for sp , done := range p .players {
214+ if sp .media .Path == media .Path {
215+ sp .Close ()
216+ if done != nil {
217+ done <- true
218+ }
219+ sp .state = playerClosed
220+ closed = append (closed , sp )
221+ }
222+ }
223+ for _ , sp := range closed {
224+ delete (p .players , sp )
225+ }
226+ }
227+
228+ func (p * soundMgr ) pause (media Sound ) {
229+ p .playersM .Lock ()
230+ defer p .playersM .Unlock ()
231+
232+ for sp := range p .players {
233+ if sp .media .Path == media .Path {
234+ sp .Pause ()
235+ sp .state = playerPaused
236+
237+ }
238+
239+ }
240+ }
241+
242+ func (p * soundMgr ) resume (media Sound ) {
243+ p .playersM .Lock ()
244+ defer p .playersM .Unlock ()
245+ for sp := range p .players {
246+ if sp .media .Path == media .Path {
247+ sp .Play ()
248+ sp .state = playerPlay
249+
250+ }
251+
252+ }
253+ }
254+
130255func (p * soundMgr ) volume () float64 {
131256 for sp := range p .players {
132257 return sp .Volume () * defaultRatio
0 commit comments