예제 #1
0
// Preload all tracks into memory as "sounds" so they are ready for use by
// the portaudio callback.
func init() {
	// Walk all files inside the tracks directory.
	filepath.Walk("tracks", func(loc string, info os.FileInfo, err error) error {
		if info.IsDir() {
			return nil
		}

		// Open .wav file with libsndfile.
		var i sndfile.Info
		snd, err := sndfile.Open(loc, sndfile.Read, &i)
		if err != nil {
			fmt.Printf("could not read %s: %v\n", loc, err)
			os.Exit(-1)
		}

		// Now, load all the contents into memory.
		var cur sound
		for {
			set := make(buffer, bufferSize)
			n, err := snd.ReadItems(set)
			if err != nil {
				fmt.Printf("could not read items from file %s: %v\n", loc, err)
				os.Exit(-1)
			}
			if int(n) < len(set) {
				// We reached the end of the file, exit loop.
				break
			}
			cur = append(cur, set)
		}

		tracks[filepath.Base(loc)] = cur
		return nil
	})
}
예제 #2
0
파일: audio.go 프로젝트: XQYCHJ/termloop
// LoadTrack reads an audio track from a file, and returns a pointer to
// a Track struct, or an error. The boolean parameter 'loop' determines
// whether or not a Track should loop when it is finished playing.
//
// Supported filetypes are whatever libsndfile supports, e.g. WAV or OGG.
func (a *Audio) LoadTrack(filename string, loop bool) (*Track, error) {
	// Load file
	var info sndfile.Info
	soundFile, err := sndfile.Open(filename, sndfile.Read, &info)
	if err != nil {
		return nil, err
	}
	buffer := make([]float32, info.Frames*int64(info.Channels))
	numRead, err := soundFile.ReadItems(buffer)
	if err != nil {
		return nil, err
	}
	defer soundFile.Close()

	// Create track
	track := Track{
		loop:   loop,
		buffer: buffer[:numRead],
		volume: 1,
	}

	a.tracks = append(a.tracks, &track)

	return &track, nil
}
예제 #3
0
파일: plotter.go 프로젝트: mkb218/ugen
func main() {
	if len(os.Args) < 3 {
		fmt.Println("Usage: go run plotter.go /path/to/wav /path/to/png")
		return
	}

	var info sndfile.Info
	soundFile, err := sndfile.Open(os.Args[1], sndfile.Read, &info)

	if err != nil {
		log.Fatal("Error", err)
	}

	defer soundFile.Close()

	imageFile, err := os.Create(os.Args[2])
	if err != nil {
		log.Fatal(err)
	}
	defer imageFile.Close()

	buffer := make([]float32, Seconds*info.Samplerate*info.Channels)

	numRead, err := soundFile.ReadItems(buffer)
	numSamples := int(numRead / int64(info.Channels))
	numChannels := int(info.Channels)

	outimage := image.NewRGBA(image.Rect(0, 0, numSamples, ImageHeight*numChannels))

	if err != nil {
		return
	}

	// Both math.Abs and math.Max operate on float64. Hm.
	max := float32(0)
	for _, v := range buffer {
		if v > max {
			max = v
		} else if v*-1 > max {
			max = v * -1
		}
	}

	// Work out scaling factor to normalise signaland get best use of space.
	mult := float32(ImageHeight/max) / 2

	// Signed float so add 1 to turn [-1, 1] into [0, 2].
	for i := 0; i < numSamples; i++ {
		for channel := 0; channel < numChannels; channel++ {
			y := int(buffer[i*numChannels+channel]*mult+ImageHeight/2) + ImageHeight*channel
			outimage.Set(i, y, color.Black)
			outimage.Set(i, y+1, color.Black)

		}

	}

	png.Encode(imageFile, outimage)
}
예제 #4
0
func (si SndFileInputRAW) Read() (sampleRate float64, channels []chan float64, errChan chan error) {
	errChan = make(chan error, 2)

	info := sndfile.Info{
		Samplerate: int32(si.SampleRate),
		Channels:   int32(si.NumChannels),
		Format:     si.Format,
	}

	f, err := sndfile.Open(si.Filename, sndfile.Read, &info)
	if err != nil {
		errChan <- err
		return 0, nil, errChan
	}

	channels = make([]chan float64, info.Channels)
	for i, _ := range channels {
		channels[i] = make(chan float64, si.BufferSize)
	}

	go func() {
		defer func() {
			err2 := f.Close()
			if err2 != nil {
				errChan <- err2
			}

			close(errChan)
			for _, channel := range channels {
				close(channel)
			}
		}()

		buffer := make([]float64, len(channels)*si.BufferSize)

		for {
			numItems, err := f.ReadItems(buffer)
			if err != nil {
				errChan <- err
				return
			}

			// EOF
			if numItems == 0 {
				break
			}

			for i, x := range buffer[:numItems] {
				channels[i%len(channels)] <- x
			}
		}
	}()

	return float64(info.Samplerate), channels, errChan
}
예제 #5
0
// LoadSample loads an audio sample from the passed in filename
// Into memory and returns the buffer.
// Returns an error if there was one in audio processing.
func LoadSample(filename string) ([]float32, error) {
	var info sndfile.Info
	soundFile, err := sndfile.Open(filename, sndfile.Read, &info)
	if err != nil {
		fmt.Printf("Could not open file: %s\n", filename)
		return nil, err
	}

	buffer := make([]float32, 10*info.Samplerate*info.Channels)
	numRead, err := soundFile.ReadItems(buffer)
	if err != nil {
		fmt.Printf("Error reading data from file: %s\n", filename)
		return nil, err
	}

	defer soundFile.Close()

	return buffer[:numRead], nil
}
예제 #6
0
func newInstrument(t *drum.Track) (*instrument, error) {
	fileName := filepath.Join(*soundDir, fmt.Sprintf("%s.wav", t.Name))
	var info sndfile.Info
	f, err := sndfile.Open(fileName, sndfile.Read, &info)
	if err != nil {
		return nil, err
	}
	defer f.Close()

	buffer := make([]int32, int(info.Frames)*int(info.Channels))
	_, err = f.ReadFrames(buffer)
	if err != nil {
		return nil, err
	}

	return &instrument{
		sample: buffer,
		cursor: len(buffer),
	}, nil
}
예제 #7
0
func (so SndFileOutput) Write(sampleRate float64, channels []chan float64) (err error) {
	info := sndfile.Info{
		Samplerate: int32(sampleRate),
		Channels:   int32(len(channels)),
		Format:     so.Format,
	}

	f, err := sndfile.Open(so.Filename, sndfile.Write, &info)
	if err != nil {
		return err
	}
	defer f.Close()

	for buffer := range soundio.Interlace(channels, so.BufferSize) {
		_, err = f.WriteItems(buffer)
		if err != nil {
			return err
		}
	}

	return nil
}
예제 #8
0
파일: sndfile.go 프로젝트: mkb218/ugen
func (s *SndfileOut) Start(op OutputParams) (err error) {
	defer func() {
		if err != nil {
			if s.file != nil {
				s.file.Close()
			}
		}
	}()

	s.start.Do(func() {
		MakeRecycleChannel(op)
		s.fi.Samplerate = int32(op.SampleRate)
		m := sndfile.Write
		if s.appendMode {
			m = sndfile.ReadWrite
		}
		bufsize := 0
		ochans := 0
		for _, u := range s.inputs {
			ochans += len(u.OutputChannels())
			bufsize += (op.BufferSize * len(u.OutputChannels()))
		}
		logger.Println(s.name, ochans, "output channels")
		s.fi.Channels = int32(ochans)
		s.file, err = sndfile.Open(s.name, m, &s.fi)
		if err != nil {
			logger.Print(err)
			s.start = new(sync.Once)
			return
		}

		if s.appendMode {
			_, err = s.file.Seek(0, sndfile.End)
			if err != nil {
				s.start = new(sync.Once)
				return
			}
		}

		for _, u := range s.inputs {
			u.Start(op)
		}

		s.stop = new(sync.Once)

		obuf := make([]float32, bufsize)

		go func() {
			// create ticker
			t := TickerFor(op)
			defer func() {
				for _, u := range s.inputs {
					u.Stop()
				}
				// stop ticker
				t.Stop()
				s.stop.Do(func() {
					s.start = new(sync.Once)
				})
			}()

			for {
				// wait for ticker
				select {
				case <-t.C:
				case <-s.quitchan:
					return
				}

				channum := 0
				var wg sync.WaitGroup
				for _, u := range s.inputs {
					for _, c := range u.OutputChannels() {
						// logger.Println(c)
						wg.Add(1)
						go func(channum int, c chan []float32) {
							select {
							case ibuf := <-c:
								for snum, sval := range ibuf {
									// if sval != 0 {
									// 	logger.Println(obuf[snum*ochans+channum], sval)
									// }
									obuf[snum*ochans+channum] = sval
									// if sval != 0 {
									// 	logger.Println(obuf[snum*ochans+channum], sval)
									// }
								}
								go func() { RecycleBuf(ibuf, op) }()
							case <-s.quitchan:
								return
							}
							wg.Done()
						}(channum, c)
						channum++
					}
				}
				wg.Wait()

				var n int64
				n, err = s.file.WriteItems(obuf)

				if n != int64(len(obuf)) || err != nil {
					logger.Print(s.name, "couldn't write from buf length", len(obuf), "wrote", n, "err", err)
					return
				}
			}
		}()
	})

	return
}