mirror of
https://github.com/bloeys/wavy.git
synced 2025-12-29 09:28:19 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8f19e800f1 | |||
| aa751bbedd | |||
| 989547c14e | |||
| 2d0f00175a |
16
README.md
16
README.md
@ -29,8 +29,9 @@ If you are using iOS or Linux please check [this](https://github.com/hajimehoshi
|
|||||||
|
|
||||||
## Supported audio formats
|
## Supported audio formats
|
||||||
|
|
||||||
- MP3
|
- MP3 (`.mp3`)
|
||||||
- Wav/Wave
|
- Wav (`.wav`/`.wave`)
|
||||||
|
- OGG (`.ogg`)
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
@ -49,8 +50,9 @@ import (
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|
||||||
//At the start if your program you should init wavy and tell it the sampling rate of your sounds (usually 44100),
|
//At the start if your program you should init wavy and tell it the
|
||||||
//the number of channels (usually 2) and the number of bytes per channel (usually 2).
|
//sampling rate of your sounds (usually 44100), the number of
|
||||||
|
//channels (usually 2) and the number of bytes per channel (usually 2).
|
||||||
//
|
//
|
||||||
//These settings will be used for all sounds regardless of their actual settings
|
//These settings will be used for all sounds regardless of their actual settings
|
||||||
err := wavy.Init(wavy.SampleRate_44100, wavy.SoundChannelCount_2, wavy.SoundBitDepth_2)
|
err := wavy.Init(wavy.SampleRate_44100, wavy.SoundChannelCount_2, wavy.SoundBitDepth_2)
|
||||||
@ -70,7 +72,8 @@ func main() {
|
|||||||
mySound.PlaySync()
|
mySound.PlaySync()
|
||||||
|
|
||||||
//Since the sound finished playing, lets reset to start
|
//Since the sound finished playing, lets reset to start
|
||||||
//by seeking to 0% then play again. Seeking to 0.5 then playing will start from the middle the sound.
|
//by seeking to 0% then play again. Seeking to 0.5 then playing
|
||||||
|
//will start from the middle the sound.
|
||||||
mySound.SeekToPercent(0)
|
mySound.SeekToPercent(0)
|
||||||
mySound.PlayAsync()
|
mySound.PlayAsync()
|
||||||
|
|
||||||
@ -131,7 +134,8 @@ mySound.PlaySync()
|
|||||||
//Set volume to 25%
|
//Set volume to 25%
|
||||||
mySound.SetVolume(0.25)
|
mySound.SetVolume(0.25)
|
||||||
|
|
||||||
//Play the sound three times and wait for all 3 plays to finish. Negative numbers will play infinitely till paused
|
//Play the sound three times and wait for all 3 plays to finish.
|
||||||
|
//Negative numbers will play infinitely till paused
|
||||||
mySound.LoopAsync(3)
|
mySound.LoopAsync(3)
|
||||||
mySound.WaitLoop()
|
mySound.WaitLoop()
|
||||||
|
|
||||||
|
|||||||
2
go.mod
2
go.mod
@ -6,10 +6,12 @@ require (
|
|||||||
github.com/go-audio/wav v1.1.0
|
github.com/go-audio/wav v1.1.0
|
||||||
github.com/hajimehoshi/go-mp3 v0.3.3
|
github.com/hajimehoshi/go-mp3 v0.3.3
|
||||||
github.com/hajimehoshi/oto/v2 v2.1.0
|
github.com/hajimehoshi/oto/v2 v2.1.0
|
||||||
|
github.com/jfreymuth/oggvorbis v1.0.3
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/go-audio/audio v1.0.0 // indirect
|
github.com/go-audio/audio v1.0.0 // indirect
|
||||||
github.com/go-audio/riff v1.0.0 // indirect
|
github.com/go-audio/riff v1.0.0 // indirect
|
||||||
|
github.com/jfreymuth/vorbis v1.0.2 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
|
golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
4
go.sum
4
go.sum
@ -9,6 +9,10 @@ github.com/hajimehoshi/go-mp3 v0.3.3/go.mod h1:qMJj/CSDxx6CGHiZeCgbiq2DSUkbK0Ubt
|
|||||||
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
github.com/hajimehoshi/oto v0.6.1/go.mod h1:0QXGEkbuJRohbJaxr7ZQSxnju7hEhseiPx2hrh6raOI=
|
||||||
github.com/hajimehoshi/oto/v2 v2.1.0 h1:/h+UkbKzhD7xBHOQlWgKUplBPZ+J4DK3P2Y7g2UF1X4=
|
github.com/hajimehoshi/oto/v2 v2.1.0 h1:/h+UkbKzhD7xBHOQlWgKUplBPZ+J4DK3P2Y7g2UF1X4=
|
||||||
github.com/hajimehoshi/oto/v2 v2.1.0/go.mod h1:9i0oYbpJ8BhVGkXDKdXKfFthX1JUNfXjeTp944W8TGM=
|
github.com/hajimehoshi/oto/v2 v2.1.0/go.mod h1:9i0oYbpJ8BhVGkXDKdXKfFthX1JUNfXjeTp944W8TGM=
|
||||||
|
github.com/jfreymuth/oggvorbis v1.0.3 h1:MLNGGyhOMiVcvea9Dp5+gbs2SAwqwQbtrWnonYa0M0Y=
|
||||||
|
github.com/jfreymuth/oggvorbis v1.0.3/go.mod h1:1U4pqWmghcoVsCJJ4fRBKv9peUJMBHixthRlBeD6uII=
|
||||||
|
github.com/jfreymuth/vorbis v1.0.2 h1:m1xH6+ZI4thH927pgKD8JOH4eaGRm18rEE9/0WKjvNE=
|
||||||
|
github.com/jfreymuth/vorbis v1.0.2/go.mod h1:DoftRo4AznKnShRl1GxiTFCseHr4zR9BN3TWXyuzrqQ=
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||||
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
golang.org/x/mobile v0.0.0-20190415191353-3e0bab5405d6/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||||
|
|||||||
@ -6,6 +6,7 @@ const (
|
|||||||
SoundType_Unknown SoundType = iota
|
SoundType_Unknown SoundType = iota
|
||||||
SoundType_MP3
|
SoundType_MP3
|
||||||
SoundType_WAV
|
SoundType_WAV
|
||||||
|
SoundType_OGG
|
||||||
)
|
)
|
||||||
|
|
||||||
type SampleRate int
|
type SampleRate int
|
||||||
|
|||||||
BIN
test_audio_files/camera.ogg
Executable file
BIN
test_audio_files/camera.ogg
Executable file
Binary file not shown.
50
wavy.go
50
wavy.go
@ -5,6 +5,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"math"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"time"
|
"time"
|
||||||
@ -12,6 +13,7 @@ import (
|
|||||||
"github.com/go-audio/wav"
|
"github.com/go-audio/wav"
|
||||||
"github.com/hajimehoshi/go-mp3"
|
"github.com/hajimehoshi/go-mp3"
|
||||||
"github.com/hajimehoshi/oto/v2"
|
"github.com/hajimehoshi/oto/v2"
|
||||||
|
"github.com/jfreymuth/oggvorbis"
|
||||||
)
|
)
|
||||||
|
|
||||||
//SoundInfo contains static info about a loaded sound file
|
//SoundInfo contains static info about a loaded sound file
|
||||||
@ -438,8 +440,6 @@ func soundFromReaderSeeker(r io.ReadSeeker, s *Sound) error {
|
|||||||
s.Data = sb
|
s.Data = sb
|
||||||
s.Player = Ctx.NewPlayer(sb)
|
s.Player = Ctx.NewPlayer(sb)
|
||||||
s.Info.Size = int64(len(sb.Data))
|
s.Info.Size = int64(len(sb.Data))
|
||||||
return nil
|
|
||||||
|
|
||||||
} else if s.Info.Type == SoundType_WAV {
|
} else if s.Info.Type == SoundType_WAV {
|
||||||
|
|
||||||
wavDec := wav.NewDecoder(r)
|
wavDec := wav.NewDecoder(r)
|
||||||
@ -457,10 +457,24 @@ func soundFromReaderSeeker(r io.ReadSeeker, s *Sound) error {
|
|||||||
s.Data = sb
|
s.Data = sb
|
||||||
s.Player = Ctx.NewPlayer(sb)
|
s.Player = Ctx.NewPlayer(sb)
|
||||||
s.Info.Size = int64(len(sb.Data))
|
s.Info.Size = int64(len(sb.Data))
|
||||||
return nil
|
} else if s.Info.Type == SoundType_OGG {
|
||||||
|
|
||||||
|
soundData, _, err := oggvorbis.ReadAll(r)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
sb := &SoundBuffer{Data: F32ToUnsignedPCM16(soundData)}
|
||||||
|
s.Data = sb
|
||||||
|
s.Player = Ctx.NewPlayer(sb)
|
||||||
|
s.Info.Size = int64(len(sb.Data))
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("invalid sound type")
|
if s.Data == nil {
|
||||||
|
panic("invalid sound type. This is probably a bug!")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetSoundFileType(fpath string) SoundType {
|
func GetSoundFileType(fpath string) SoundType {
|
||||||
@ -471,6 +485,8 @@ func GetSoundFileType(fpath string) SoundType {
|
|||||||
return SoundType_MP3
|
return SoundType_MP3
|
||||||
case ".wav", ".wave":
|
case ".wav", ".wave":
|
||||||
return SoundType_WAV
|
return SoundType_WAV
|
||||||
|
case ".ogg":
|
||||||
|
return SoundType_OGG
|
||||||
default:
|
default:
|
||||||
return SoundType_Unknown
|
return SoundType_Unknown
|
||||||
}
|
}
|
||||||
@ -534,3 +550,29 @@ func clamp01F64(x float64) float64 {
|
|||||||
|
|
||||||
return x
|
return x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//F32ToUnsignedPCM16 takes PCM data stored as float32 between [-1, 1]
|
||||||
|
//and returns a byte array of uint16, where each two subsequent bytes represent one uint16.
|
||||||
|
func F32ToUnsignedPCM16(fs []float32) []byte {
|
||||||
|
|
||||||
|
outBuf := make([]byte, len(fs)*2)
|
||||||
|
for i := 0; i < len(fs); i++ {
|
||||||
|
|
||||||
|
//Remap [-1,1]->[-32768, 32767], then re-interprets the int16 as a uint16.
|
||||||
|
//With this, the negative values are mapped into the higher half of the uint16 range,
|
||||||
|
//while positive values remain unchanged
|
||||||
|
x := fs[i]
|
||||||
|
var u16 uint16
|
||||||
|
if x < 0 {
|
||||||
|
u16 = uint16(x * -math.MinInt16)
|
||||||
|
} else {
|
||||||
|
u16 = uint16(x * math.MaxInt16)
|
||||||
|
}
|
||||||
|
|
||||||
|
baseIndex := i * 2
|
||||||
|
outBuf[baseIndex] = byte(u16 >> 0)
|
||||||
|
outBuf[baseIndex+1] = byte(u16 >> 8)
|
||||||
|
}
|
||||||
|
|
||||||
|
return outBuf
|
||||||
|
}
|
||||||
|
|||||||
@ -112,6 +112,15 @@ func TestSound(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
s.PlaySync()
|
s.PlaySync()
|
||||||
|
|
||||||
|
//Ogg
|
||||||
|
const oggFPath = "./test_audio_files/camera.ogg"
|
||||||
|
s, err = wavy.NewSoundMem(oggFPath)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Failed to load memory sound with path '%s'. Err: %s\n", oggFPath, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
s.PlaySync()
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestByteCountFromPlayTime(t *testing.T) {
|
func TestByteCountFromPlayTime(t *testing.T) {
|
||||||
|
|||||||
Reference in New Issue
Block a user