87 lines
1.7 KiB
Go
87 lines
1.7 KiB
Go
package sound
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"os/exec"
|
|
)
|
|
|
|
// FMConfig defines the tunables for an FM instance
|
|
type FMConfig struct {
|
|
Frequency float32
|
|
}
|
|
|
|
// FM is a sound.Output implementation that outputs to an FM frequency
|
|
type FM struct {
|
|
config *FMConfig
|
|
}
|
|
|
|
// NewFM creates a new FM instance with the given config
|
|
func NewFM(config FMConfig) *FM {
|
|
return &FM{
|
|
config: &config,
|
|
}
|
|
}
|
|
|
|
// Play the given input to the FM frequency
|
|
func (f *FM) Play(ctx context.Context, filePath string) error {
|
|
ctx, cancel := context.WithCancel(ctx)
|
|
defer cancel()
|
|
|
|
soxCmd := exec.CommandContext(
|
|
ctx,
|
|
"sox",
|
|
filePath,
|
|
"-r", "22050",
|
|
"-c", "1",
|
|
"-b", "16",
|
|
"-t", "wav",
|
|
"-",
|
|
)
|
|
|
|
reader, err := soxCmd.StdoutPipe()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to open STDOUT pipe for converting the input file to the FM transmitter format: %w", err)
|
|
}
|
|
|
|
err = soxCmd.Start()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to start conversion for the input file for the FM transmitter: %w", err)
|
|
}
|
|
|
|
fmCmd := exec.CommandContext(
|
|
ctx,
|
|
"fm_transmitter",
|
|
"-f",
|
|
fmt.Sprintf("%.1f", f.config.Frequency),
|
|
"-",
|
|
)
|
|
|
|
writer, err := fmCmd.StdinPipe()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create STDIN pipe for FM transmitter: %w", err)
|
|
}
|
|
|
|
err = fmCmd.Start()
|
|
if err != nil {
|
|
return fmt.Errorf("failed to start FM transmitter command: %w", err)
|
|
}
|
|
|
|
_, err = io.Copy(writer, reader)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to write audio output to FM transmitter: %w", err)
|
|
}
|
|
|
|
err = soxCmd.Wait()
|
|
if err != nil {
|
|
return fmt.Errorf("audio conversion command resulted in an error: %w", err)
|
|
}
|
|
|
|
err = fmCmd.Wait()
|
|
if err != nil {
|
|
return fmt.Errorf("FM transmitter command resulted in an error: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|