🎉 live server seems to be working now
This commit is contained in:
102
third_party/sendspin-go/pkg/sendspin/source.go
vendored
Normal file
102
third_party/sendspin-go/pkg/sendspin/source.go
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
// ABOUTME: Audio source abstraction for Sendspin streaming
|
||||
// ABOUTME: Provides AudioSource interface and common implementations
|
||||
package sendspin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// AudioSource provides PCM audio samples for streaming
|
||||
type AudioSource interface {
|
||||
// Read reads PCM samples into the buffer (int32 for 24-bit support).
|
||||
// Returns number of samples read or error.
|
||||
Read(samples []int32) (int, error)
|
||||
|
||||
// SampleRate returns the sample rate of the audio
|
||||
SampleRate() int
|
||||
|
||||
// Channels returns the number of channels
|
||||
Channels() int
|
||||
|
||||
// Metadata returns title, artist, album
|
||||
Metadata() (title, artist, album string)
|
||||
|
||||
// Close closes the audio source
|
||||
Close() error
|
||||
}
|
||||
|
||||
type TestToneSource struct {
|
||||
sampleIndex uint64
|
||||
sampleMu sync.Mutex
|
||||
frequency float64
|
||||
sampleRate int
|
||||
channels int
|
||||
}
|
||||
|
||||
// NewTestTone creates a new test tone generator
|
||||
// Generates a 440Hz sine wave at the specified sample rate and channels
|
||||
func NewTestTone(sampleRate, channels int) *TestToneSource {
|
||||
if sampleRate == 0 {
|
||||
sampleRate = DefaultSampleRate
|
||||
}
|
||||
if channels == 0 {
|
||||
channels = DefaultChannels
|
||||
}
|
||||
|
||||
return &TestToneSource{
|
||||
frequency: 440.0, // A4 note
|
||||
sampleRate: sampleRate,
|
||||
channels: channels,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *TestToneSource) Read(samples []int32) (int, error) {
|
||||
s.sampleMu.Lock()
|
||||
defer s.sampleMu.Unlock()
|
||||
|
||||
numSamples := len(samples) / s.channels
|
||||
|
||||
for i := 0; i < numSamples; i++ {
|
||||
t := float64(s.sampleIndex+uint64(i)) / float64(s.sampleRate)
|
||||
sample := math.Sin(2 * math.Pi * s.frequency * t)
|
||||
|
||||
// Scale to 24-bit range; 50% amplitude avoids clipping on decode
|
||||
const max24bit = 8388607 // 2^23 - 1
|
||||
pcmValue := int32(sample * max24bit * 0.5)
|
||||
|
||||
for ch := 0; ch < s.channels; ch++ {
|
||||
samples[i*s.channels+ch] = pcmValue
|
||||
}
|
||||
}
|
||||
|
||||
s.sampleIndex += uint64(numSamples)
|
||||
|
||||
return len(samples), nil
|
||||
}
|
||||
|
||||
func (s *TestToneSource) SampleRate() int { return s.sampleRate }
|
||||
func (s *TestToneSource) Channels() int { return s.channels }
|
||||
func (s *TestToneSource) Metadata() (string, string, string) {
|
||||
return "Test Tone", "Sendspin", "Test Signal"
|
||||
}
|
||||
func (s *TestToneSource) Close() error { return nil }
|
||||
|
||||
// FileSource streams audio from a file
|
||||
// Note: This is a placeholder - users should use server.NewAudioSource() for file streaming
|
||||
// which supports MP3, FLAC, and other formats
|
||||
type FileSource struct {
|
||||
// This is intentionally not implemented in the public API yet
|
||||
// Users can use internal/server.NewAudioSource() for now
|
||||
// TODO: Move file source implementations to pkg/audio/decode
|
||||
}
|
||||
|
||||
// NewFileSource creates an audio source from a file
|
||||
// Supported formats: MP3, FLAC
|
||||
// Returns an error if the file cannot be opened or decoded
|
||||
func NewFileSource(path string) (AudioSource, error) {
|
||||
// For now, we use the internal implementation
|
||||
// TODO: Migrate file sources to pkg/audio/decode
|
||||
return nil, fmt.Errorf("file source not implemented: use internal/server.NewAudioSource()")
|
||||
}
|
||||
Reference in New Issue
Block a user