Building a CLI Music Player in Go
Creating a terminal-based SomaFM player in Go was an interesting exercise in audio streaming and terminal UI design. This post details our implementation and the technical challenges we faced.
Why SomaFM?
SomaFM offers several advantages for a CLI project:
- High-quality streams
- Diverse music selection
- Simple streaming protocols
- No authentication required
Technical Implementation
1. Core Player Structure
type Player struct {
currentStation *Station
audioPlayer *mpg123.Decoder
output *ao.Device
volume float64
isPlaying bool
ui *UI
}
type Station struct {
Name string
URL string
Genre string
Bitrate int
Listeners int
}
func NewPlayer() (*Player, error) {
// Initialize mpg123
mpg123.Init()
// Initialize audio output
ao.Initialize()
return &Player{
volume: 1.0,
ui: NewUI(),
}, nil
}
2. Audio Streaming
func (p *Player) Play(station *Station) error {
// Stop current playback
p.Stop()
// Create new decoder
decoder, err := mpg123.NewDecoder("")
if err != nil {
return err
}
// Open stream
if err := decoder.Open(station.URL); err != nil {
return err
}
// Setup audio output
format := ao.Format{
Bits: 16,
Rate: 44100,
Channels: 2,
ByteFormat: ao.FormatNative,
}
device, err := ao.OpenLive(&format)
if err != nil {
return err
}
p.audioPlayer = decoder
p.output = device
p.currentStation = station
p.isPlaying = true
// Start playback loop
go p.playbackLoop()
return nil
}
func (p *Player) playbackLoop() {
buffer := make([]byte, 4096)
for p.isPlaying {
// Read audio data
length, err := p.audioPlayer.Read(buffer)
if err != nil {
break
}
// Apply volume
p.applyVolume(buffer[:length])
// Play audio
p.output.Play(buffer[:length])
}
}
Features
Station Management:
- List all available stations
- Search by name or genre
- Show current listeners
- Display bitrate information
Playback Controls:
- Play/Pause
- Volume control
- Station switching
- Stream quality selection
UI Features:
- Real-time station information
- Progress bar
- Keyboard shortcuts
- Color themes
Conclusion
Building a CLI music player in Go was a great exercise in working with audio streams and terminal interfaces. The combination of Go’s concurrency features and the simplicity of SomaFM’s API made it possible to create a robust and user-friendly application.
Sometimes the simplest interfaces can provide the most enjoyable user experiences.