Skip to content

Commit

Permalink
Replace the implementation with Ebiten's audio implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
hajimehoshi committed Aug 21, 2021
1 parent 5cfe404 commit 634126e
Show file tree
Hide file tree
Showing 154 changed files with 16,261 additions and 2,494 deletions.
48 changes: 18 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# Oto ()
# Oto (v2)

[![GoDoc](https://godoc.org/github.com/hajimehoshi/oto?status.svg)](http://godoc.org/github.com/hajimehoshi/oto)
[![Go Reference](https://pkg.go.dev/badge/github.com/hajimehoshi/oto/v2.svg)](https://pkg.go.dev/github.com/hajimehoshi/oto/v2)

A low-level library to play sound. This package offers `io.WriteCloser` to play PCM sound.
A low-level library to play sound.

## Platforms

* Windows
* macOS
* Linux
* FreeBSD
* OpenBSD
* Android
* iOS
* Web browsers ([GopherJS](https://github.com/gopherjs/gopherjs) and WebAssembly)
* Windows
* macOS
* Linux
* FreeBSD
* OpenBSD
* Android
* iOS
* Web browsers ([GopherJS](https://github.com/gopherjs/gopherjs) and WebAssembly)

## Prerequisite

Expand All @@ -25,37 +25,25 @@ Oto requies `AudioToolbox.framework`, but this is automatically linked.

Oto requies these frameworks:

* `AVFoundation.framework`
* `AudioToolbox.framework`
* `AVFoundation.framework`
* `AudioToolbox.framework`

Add them to "Linked Frameworks and Libraries" on your Xcode project.

### Linux

libasound2-dev is required. On Ubuntu or Debian, run this command:
ALSA is required. On Ubuntu or Debian, run this command:

```sh
apt install libasound2-dev
```

In most cases this command must be run by root user or through `sudo` command.

#### Crosscompiling

To crosscompile, make sure the libraries for the target architecture are installed, and set `CGO_ENABLED=1` as Go disables [Cgo](https://golang.org/cmd/cgo/#hdr-Using_cgo_with_the_go_command) on crosscompiles by default

### FreeBSD

OpenAL is required. Install openal-soft:

```sh
pkg install openal-soft
```
### FreeBSD, OpenBSD

### OpenBSD
BSD systems are not tested well. If ALSA works, Oto should work.

OpenAL is required. Install openal:
#### Crosscompiling

```sh
pkg_add -r openal
```
To crosscompile, make sure the libraries for the target architecture are installed, and set `CGO_ENABLED=1` as Go disables [Cgo](https://golang.org/cmd/cgo/#hdr-Using_cgo_with_the_go_command) on crosscompiles by default.
171 changes: 0 additions & 171 deletions context.go

This file was deleted.

142 changes: 142 additions & 0 deletions driver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright 2021 The Oto Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package oto

import (
"io"
)

// Context is the main object in Oto. It interacts with the audio drivers.
//
// To play sound with Oto, first create a context. Then use the context to create
// an arbitrary number of players. Then use the players to play sound.
//
// There can only be one context at any time. Closing a context and opening a new one is allowed.
type Context struct {
context *context
}

// NewPlayer creates a new, ready-to-use Player belonging to the Context.
//
// The r's format is as follows:
// [data] = [sample 1] [sample 2] [sample 3] ...
// [sample *] = [channel 1] ...
// [channel *] = [byte 1] [byte 2] ...
// Byte ordering is little endian.
//
// A player has some amount of an underlying buffer.
// Read data from r is queued to the player's underlying buffer.
// The underlying buffer is consumed by its playing.
// Then, r's position and the current playing position don't necessarily match.
// If you want to clear the underlying buffer for some reasons e.g., you want to seek the position of r,
// call the player's Reset function.
//
// You cannot share r by multiple players.
//
// NewPlayer is concurrent-safe.
//
// All the functions of a Player returned by NewPlayer are concurrent-safe.
func (c *Context) NewPlayer(r io.Reader) Player {
return c.context.NewPlayer(r)
}

// Suspend suspends the entire audio play.
//
// Suspend is concurrent-safe.
func (c *Context) Suspend() error {
return c.context.Suspend()
}

// Resume resumes the entire audio play, which was suspended by Suspend.
//
// Resume is concurrent-safe.
func (c *Context) Resume() error {
return c.context.Resume()
}

// NewContext creates a new context, that creates and holds ready-to-use Player objects,
// and returns a context, a channel that is closed when the context is ready, and an error if it exists.
//
// The sampleRate argument specifies the number of samples that should be played during one second.
// Usual numbers are 44100 or 48000.
//
// The channelNum argument specifies the number of channels. One channel is mono playback. Two
// channels are stereo playback. No other values are supported.
//
// The bitDepthInBytes argument specifies the number of bytes per sample per channel. The usual value
// is 2. Only values 1 and 2 are supported.
func NewContext(sampleRate int, channelNum int, bitDepthInBytes int) (*Context, chan struct{}, error) {
ctx, ready, err := newContext(sampleRate, channelNum, bitDepthInBytes)
if err != nil {
return nil, nil, err
}
return &Context{context: ctx}, ready, nil
}

// Player is a PCM (pulse-code modulation) audio player.
type Player interface {
// Pause pauses its playing.
Pause()

// Play starts its playing if it doesn't play.
Play()

// IsPlaying reports whether this player is playing.
IsPlaying() bool

// Reset clears the underyling buffer and pauses its playing.
Reset()

// Volume returns the current volume in between [0, 1].
// The default volume is 1.
Volume() float64

// SetVolume sets the current volume in between [0, 1].
SetVolume(volume float64)

// UnplayedBufferSize returns the byte size in the underlying buffer that is not played yet.
UnplayedBufferSize() int

// Err returns an error if this player has an error.
Err() error

io.Closer
}

type playerState int

const (
playerPaused playerState = iota
playerPlay
playerClosed
)

// TODO: The term 'buffer' is confusing. Name each buffer with good terms.

// oneBufferSize returns the size of one buffer in the player implementation.
func (c *context) oneBufferSize() int {
bytesPerSample := c.channelNum * c.bitDepthInBytes
s := c.sampleRate * bytesPerSample / 4

// Align s in multiples of bytes per sample, or a buffer could have extra bytes.
return s / bytesPerSample * bytesPerSample
}

// maxBufferSize returns the maximum size of the buffer for the audio source.
// This buffer is used when unreading on pausing the player.
func (c *context) maxBufferSize() int {
// The number of underlying buffers should be 2.
return c.oneBufferSize() * 2
}
Loading

0 comments on commit 634126e

Please sign in to comment.