Documentation
¶
Index ¶
- Constants
- Variables
- type Controller
- func (c *Controller) Clear() (requests int)
- func (c *Controller) ClearRequests() (n int)
- func (c *Controller) Current() (library.Track, bool)
- func (c *Controller) Enqueue(ts ...library.Track)
- func (c *Controller) EnqueueAndPlay(ctx context.Context, ts []library.Track) error
- func (c *Controller) Index() (i int)
- func (c *Controller) Jump(ctx context.Context, i int) error
- func (c *Controller) Next(ctx context.Context) error
- func (c *Controller) Pending() (ls []Lane)
- func (c *Controller) PlayTracks(ctx context.Context, ts []library.Track, start int) error
- func (c *Controller) Prev(ctx context.Context) error
- func (c *Controller) Remove(ctx context.Context, i int) error
- func (c *Controller) Repeat() (v bool)
- func (c *Controller) Request(ctx context.Context, by, name string, ts []library.Track) (int, error)
- func (c *Controller) RequesterOf(i int) (by, name string)
- func (c *Controller) Run(ctx context.Context)
- func (c *Controller) SeekBy(delta time.Duration)
- func (c *Controller) SetMaxPending(n int)
- func (c *Controller) SetTrackEnd(fn func(t library.Track, played time.Duration, by, name string))
- func (c *Controller) Shuffle() (v bool)
- func (c *Controller) TogglePause()
- func (c *Controller) ToggleRepeat()
- func (c *Controller) ToggleShuffle()
- func (c *Controller) Tracks() (ts []library.Track)
- type Engine
- func (e *Engine) Close()
- func (e *Engine) Done() <-chan struct{}
- func (e *Engine) DropNext() bool
- func (e *Engine) Err() error
- func (e *Engine) Feed() *Feed
- func (e *Engine) Format() Format
- func (e *Engine) Handover() <-chan struct{}
- func (e *Engine) Length() time.Duration
- func (e *Engine) LocalMuted() bool
- func (e *Engine) Pause()
- func (e *Engine) PeekNext() Source
- func (e *Engine) Play(src Source)
- func (e *Engine) PlayAt(src Source, at time.Duration)
- func (e *Engine) Playing() bool
- func (e *Engine) Position() time.Duration
- func (e *Engine) Rate() int
- func (e *Engine) Resume()
- func (e *Engine) Seek(d time.Duration)
- func (e *Engine) SetLocalMute(on bool)
- func (e *Engine) SetNext(src Source)
- func (e *Engine) SetVolume(v float64)
- func (e *Engine) Spectrum(n int, dst []float64) int
- func (e *Engine) Stereo(n int, l, r []float64) int
- func (e *Engine) Stop()
- func (e *Engine) TakeNext() Source
- func (e *Engine) Volume() float64
- type Feed
- type Format
- type HTTPFile
- type Lane
- type Output
- type Player
- type Queue
- func (q *Queue) Append(ts ...library.Track)
- func (q *Queue) Clear()
- func (q *Queue) Current() (library.Track, bool)
- func (q *Queue) HasNext() bool
- func (q *Queue) Index() int
- func (q *Queue) InsertNext(t library.Track, by, name string) int
- func (q *Queue) Jump(i int) bool
- func (q *Queue) Next() bool
- func (q *Queue) Prev() bool
- func (q *Queue) Remove(i int) (wasCurrent, wasLast bool)
- func (q *Queue) Replace(ts []library.Track, start int)
- func (q *Queue) Tag(i int) (by, name string)
- func (q *Queue) Tracks() []library.Track
- type Resampler
- type Ring
- type Source
- type Tap
Constants ¶
const OutRate = 44100
OutRate is the default device rate; the engine runs at whatever rate it was opened with.
Variables ¶
var ErrTooManyPending = errors.New("too many pending")
Functions ¶
This section is empty.
Types ¶
type Controller ¶
type Controller struct {
// contains filtered or unexported fields
}
Controller joins the queue, the library, and the engine: it opens streams, advances on track end, prefetches the next track, and reports skips.
func NewController ¶
func NewController(lib library.Library, eng *Engine, notify func(string)) *Controller
func (*Controller) Clear ¶ added in v0.9.1
func (c *Controller) Clear() (requests int)
Clear empties the queue and every request lane and stops playback. It returns how many requested songs were dropped.
func (*Controller) ClearRequests ¶ added in v0.17.0
func (c *Controller) ClearRequests() (n int)
ClearRequests drops every lane; it returns the songs dropped.
func (*Controller) Enqueue ¶
func (c *Controller) Enqueue(ts ...library.Track)
func (*Controller) EnqueueAndPlay ¶ added in v0.17.1
EnqueueAndPlay appends ts and, when nothing is playing, starts the first of them: what someone typing /play into a silent room expects.
func (*Controller) Index ¶
func (c *Controller) Index() (i int)
func (*Controller) Pending ¶ added in v0.17.0
func (c *Controller) Pending() (ls []Lane)
Pending is every lane with its waiting songs, in rotation order.
func (*Controller) PlayTracks ¶
func (*Controller) Remove ¶ added in v0.9.1
func (c *Controller) Remove(ctx context.Context, i int) error
Remove drops the track at i from the queue. Removing the playing track moves playback to the one that followed it, or stops when it was last. A prefetched copy of the removed track is discarded so the gapless handover cannot play it.
func (*Controller) Repeat ¶
func (c *Controller) Repeat() (v bool)
func (*Controller) Request ¶ added in v0.17.0
Request queues songs for someone in the room. With nothing playing it starts the first one at once.
func (*Controller) RequesterOf ¶ added in v0.17.0
func (c *Controller) RequesterOf(i int) (by, name string)
RequesterOf is who asked for queue row i; empty for the DJ's own rows.
func (*Controller) Run ¶
func (c *Controller) Run(ctx context.Context)
Run advances the queue when a track ends and prefetches the next track shortly before. It returns when ctx is cancelled.
func (*Controller) SeekBy ¶
func (c *Controller) SeekBy(delta time.Duration)
func (*Controller) SetMaxPending ¶ added in v0.17.0
func (c *Controller) SetMaxPending(n int)
SetMaxPending caps the songs one requester may have waiting; 0 = unlimited.
func (*Controller) SetTrackEnd ¶ added in v0.17.0
SetTrackEnd is told every track that stops being current: how much of it was heard and who asked for it.
func (*Controller) Shuffle ¶
func (c *Controller) Shuffle() (v bool)
func (*Controller) TogglePause ¶
func (c *Controller) TogglePause()
func (*Controller) ToggleRepeat ¶
func (c *Controller) ToggleRepeat()
func (*Controller) ToggleShuffle ¶
func (c *Controller) ToggleShuffle()
func (*Controller) Tracks ¶
func (c *Controller) Tracks() (ts []library.Track)
type Engine ¶
type Engine struct {
// contains filtered or unexported fields
}
Engine runs Sources through decode → resample → ring → output, and taps the output for the analyzer. A second source can be queued with SetNext: the decoder continues straight into it when the first ends, so the ring never empties and the handover is gapless. The reader flips the audible source when it consumes past the boundary, which is when the deck changes.
func (*Engine) DropNext ¶ added in v0.17.0
DropNext discards the queued next source, but only while the decoder has not read from it; once it has, the ring already holds its start and the source must play. It reports whether nothing is queued afterwards. Unlike TakeNext it never halts the decoder, so the current track plays on.
func (*Engine) Format ¶ added in v0.7.2
Format is what the audible source is decoding, or zero when nothing plays.
func (*Engine) LocalMuted ¶ added in v0.16.0
func (*Engine) PlayAt ¶
PlayAt starts src from position at, for resuming a stream that dropped. A source that cannot seek there plays from its start with the clock at 0. Any queued next source other than src is discarded.
func (*Engine) SetLocalMute ¶ added in v0.16.0
SetLocalMute silences the device without touching the volume setting; the feed and the visualizer tap keep flowing.
func (*Engine) SetNext ¶
SetNext queues src to follow the current source without a gap. It replaces any source queued earlier.
type Feed ¶ added in v0.16.0
type Feed struct {
// contains filtered or unexported fields
}
Feed hands a copy of the engine's output, before the volume knob, to one consumer such as a Discord broadcast. Writes never block: when the consumer falls behind, the oldest audio is dropped.
type Format ¶ added in v0.7.2
type Format struct {
Codec string
SampleRate int
BitDepth int // 0 for lossy codecs
Bitrate int // kbps
}
Format is what a decoder knows about the file it is playing. Bitrate is derived from size and length when the container does not state one.
type HTTPFile ¶
type HTTPFile struct {
// contains filtered or unexported fields
}
HTTPFile is an io.ReadSeekCloser over an HTTP resource that honours Range. A Seek closes the current body; the next Read opens a new request at the new offset. Decoders that seek through the seek table or by byte offset therefore cost one request per seek and nothing while streaming.
func (*HTTPFile) Interrupt ¶
func (f *HTTPFile) Interrupt()
Interrupt closes the in-flight body so a blocked Read returns. The next Read reopens at the current offset; a Seek reopens at the new one.
type Output ¶
Output creates players that read 32-bit float stereo at the engine's rate from r.
func NewOtoOutput ¶
NewOtoOutput opens the process's single audio context. Call once.
func NewSilentOutput ¶ added in v0.8.0
NewSilentOutput returns an Output whose players consume audio at the sample rate and discard it. It lets dotamp run where there is no sound device, such as a headless box rendering the README's screenshots, with the visualizers moving exactly as they would over speakers.
type Player ¶
type Player interface {
Play()
Pause()
BufferedSize() int // bytes of float32 stereo still queued in the device
Close() error
}
Player is the slice of oto.Player the engine needs; tests supply a fake.
type Queue ¶
type Queue struct {
Shuffle, Repeat bool
// contains filtered or unexported fields
}
Queue is the ordered list of tracks and a cursor. With Shuffle on, Next walks a random permutation that starts at the current track and is rebuilt when the list changes.
func (*Queue) HasNext ¶ added in v0.17.0
HasNext reports whether Next would move on without Repeat wrapping.
func (*Queue) InsertNext ¶ added in v0.17.0
InsertNext puts t right after the current track, tagged with who asked, and makes it the next track even under Shuffle. It returns the index.
func (*Queue) Remove ¶ added in v0.9.1
Remove drops the track at i. It reports whether that was the current track and, if so, whether it was the last in the list, in which case the cursor moves back onto the new last track. Otherwise the cursor keeps pointing at the same track, or at the one that followed the removed one.
type Resampler ¶
type Resampler struct {
// contains filtered or unexported fields
}
Resampler converts interleaved stereo float32 between sample rates with a windowed-sinc filter: every output sample is a weighted sum of the nearby input samples, the weights being a sinc cut off at the lower of the two Nyquist frequencies under a Kaiser window. Downsampling therefore removes what cannot be represented instead of folding it back as aliasing, and a tone passes through within a fraction of a decibel.
The filter looks sincTaps input frames ahead, so the last sincTaps frames of a stream are only produced once more input arrives; at the end of a track that is about a millisecond, which the next track's first frames cover.
func NewResampler ¶
type Ring ¶
type Ring struct {
// contains filtered or unexported fields
}
Ring is a single-producer single-consumer ring of float32 samples. Only the consumer moves head, so a writer never touches a slot the reader may be copying; a producer-side Drain is a request the consumer applies on its next Read.
func (*Ring) Drain ¶
func (r *Ring) Drain()
Drain marks everything written so far as stale. The consumer skips it on its next Read; until then Len still counts it, so a full ring stays full.
type Source ¶
type Source interface {
SampleRate() int
Read(dst []float32) (int, error)
Seek(d time.Duration) error
Length() time.Duration
Format() Format
// Interrupt makes a Read blocked on I/O return promptly with an error.
// The source is then only good for Seek or Close.
Interrupt()
Close() error
}
Source is a decoded audio stream: interleaved stereo float32 in [-1, 1].
type Tap ¶
type Tap struct {
// contains filtered or unexported fields
}
Tap keeps the most recent frames handed to the output so the analyzer can read what the speaker is playing now. Left and right are kept apart; the mono view mixes them on the way out.
func (*Tap) Latest ¶
Latest fills dst with n mono-mixed frames ending lagFrames before the newest. It returns 0 when there is not enough history yet.
func (*Tap) LatestStereo ¶ added in v0.5.0
LatestStereo is Latest with the channels kept apart.