예제 #1
0
파일: screen.go 프로젝트: mantyr/go-sound
// Render starts rendering a sound wave's samples to a screen of given height.
func Render(s sounds.Sound, width int, height int) {
	// Default to 15 samples-per-pixel, sampled 1-in-2.
	screen := util.NewScreen(width, height, 15)
	s.Start()
	// TODO(padster): Currently this generates and renders the samples
	// as quickly as possible. Better instead to render close to realtime?
	screen.Render(s.GetSamples(), 2)
}
예제 #2
0
파일: flacfile.go 프로젝트: mantyr/go-sound
// WriteSoundToFlac creates a file at a path, and writes the given sound in the .flac format.
func WriteSoundToFlac(sound s.Sound, path string) error {
	if !strings.HasSuffix(path, ".flac") {
		panic("Output file must be .flac")
	}

	if _, err := os.Stat(path); err == nil {
		panic("File already exists! Please delete first")
		return os.ErrExist
	}

	sampleRate := int(s.CyclesPerSecond)
	depth := 24

	fileWriter, err := goflac.NewEncoder(path, 1, depth, sampleRate)
	if err != nil {
		fmt.Printf("Error opening file to write to! %v\n", err)
		panic("Can't write file")
	}
	defer fileWriter.Close()

	// Starts the sound, and accesses its sample stream.
	sound.Start()
	samples := sound.GetSamples()
	defer sound.Stop()

	// TODO: Make a common utility for this, it's used here and in both CQ and CQI.
	frameSize := 44100
	buffer := make([]float64, frameSize, frameSize)
	at := 0
	for s := range samples {
		if at == frameSize {
			writeFrame(fileWriter, buffer)
			at = 0
		}
		buffer[at] = s
		at++
	}
	writeFrame(fileWriter, buffer[:at])

	return nil
}
예제 #3
0
파일: wavfile.go 프로젝트: mantyr/go-sound
// WriteSoundToWav creates a file at a path, and writes the given sound in the .wav format.
func WriteSoundToWav(s sounds.Sound, path string) error {
	// Create file first, only if it doesn't exist:
	if _, err := os.Stat(path); err == nil {
		panic("File already exists! Please delete first")
		return os.ErrExist
	}
	file, err := os.Create(path)
	if err != nil {
		return err
	}
	defer func() {
		file.Close()
	}()

	// Create a .wav writer for the file
	var wf = wav.File{
		SampleRate:      uint32(sounds.CyclesPerSecond),
		Channels:        1,
		SignificantBits: 16,
	}
	writer, err := wf.NewWriter(file)
	if err != nil {
		return err
	}
	defer writer.Close()

	// Starts the sound, and accesses its sample stream.
	s.Start()
	samples := s.GetSamples()
	defer s.Stop()

	// Write a single sample at a time, as per the .wav writer API.
	b := make([]byte, 2)
	for sample := range samples {
		toNumber := uint16(sample * normScale) // Inverse the read scaling
		binary.LittleEndian.PutUint16(b, uint16(toNumber))
		writer.WriteSample(b)
	}
	return nil
}
예제 #4
0
파일: pulse.go 프로젝트: mantyr/go-sound
// playSamples handles the writing of a sound's channel of samples to a pulse stream.
func playSamples(s sounds.Sound, sync_ch chan int, pa *PulseMainLoop) {
	defer func() {
		sync_ch <- 0
	}()

	// Create a pulse audio context to play the sound.
	ctx := pa.NewContext("default", 0)
	if ctx == nil {
		fmt.Println("Failed to create a new context")
		return
	}
	defer ctx.Dispose()

	// Create a single-channel pulse audio stream to write the sound to.
	st := ctx.NewStream("default", &PulseSampleSpec{
		Format:   SAMPLE_FLOAT32LE,
		Rate:     int(sounds.CyclesPerSecond),
		Channels: 1,
	})
	if st == nil {
		fmt.Println("Failed to create a new stream")
		return
	}
	defer st.Dispose()

	// Starts the sound, and accesses its sample stream.
	s.Start()
	samples := s.GetSamples()
	defer s.Stop()

	// Continually buffers data from the stream and writes to audio.
	sampleCount := 0
	st.ConnectToSink()
	for {
		toAdd := st.WritableSize()
		if toAdd == 0 {
			continue
		}

		// No buffer - write immediately.
		// TODO(padster): Play with this to see if chunked writes actually reduce delay.
		if toAdd > 441 {
			toAdd = 441
		}

		// TODO: Reuse just one of these?
		buffer := make([]float32, toAdd)
		finishedAt := toAdd

		for i := range buffer {
			sample, stream_ok := <-samples
			if !stream_ok {
				finishedAt = i
				break
			}
			buffer[i] = float32(sample)
		}
		if finishedAt == 0 {
			st.Drain()
			break
		}
		sampleCount += finishedAt
		st.Write(buffer[0:finishedAt], SEEK_RELATIVE)
	}
	fmt.Printf("Samples written: %d\n", sampleCount)
}