fix bug leading to gaps in waveform image
This commit is contained in:
+13
-44
@@ -183,11 +183,12 @@ func generateWaveformImage(ctx context.Context, data *waveformData, job *Wavefor
|
|||||||
translucentColor := color.NRGBA{R: 255, G: 255, B: 255, A: 128}
|
translucentColor := color.NRGBA{R: 255, G: 255, B: 255, A: 128}
|
||||||
|
|
||||||
for x := 0; x < 1024; x++ {
|
for x := 0; x < 1024; x++ {
|
||||||
if data.progress <= x {
|
for data.progress <= x {
|
||||||
time.Sleep(10 * time.Millisecond)
|
time.Sleep(10 * time.Millisecond)
|
||||||
if ctx.Err() != nil {
|
if ctx.Err() != nil {
|
||||||
return // expired
|
return // expired
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
rms := float64(data.RMS[x]) / 255.0
|
rms := float64(data.RMS[x]) / 255.0
|
||||||
@@ -216,6 +217,7 @@ func generateWaveformImage(ctx context.Context, data *waveformData, job *Wavefor
|
|||||||
log.Println("done generating image")
|
log.Println("done generating image")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// assumes mono, 16 bit
|
||||||
func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformData, millisecs int64, fileDone func() bool) error {
|
func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformData, millisecs int64, fileDone func() bool) error {
|
||||||
if fileDone() {
|
if fileDone() {
|
||||||
log.Println("Analyzing completely written file!!")
|
log.Println("Analyzing completely written file!!")
|
||||||
@@ -226,11 +228,9 @@ func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformDat
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
//defer os.Remove(transcodeFile)
|
defer os.Remove(transcodeFile)
|
||||||
|
|
||||||
reader := trackingReader{rs: f}
|
decoder := wav.NewDecoder(f)
|
||||||
|
|
||||||
decoder := wav.NewDecoder(&reader)
|
|
||||||
if !decoder.IsValidFile() {
|
if !decoder.IsValidFile() {
|
||||||
return errors.New("invalid wav file")
|
return errors.New("invalid wav file")
|
||||||
}
|
}
|
||||||
@@ -247,6 +247,7 @@ func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformDat
|
|||||||
buf := &audio.IntBuffer{Data: make([]int, 4096)}
|
buf := &audio.IntBuffer{Data: make([]int, 4096)}
|
||||||
curChunk := 0
|
curChunk := 0
|
||||||
chunkSamples := make([]float32, 0, samplesPerChunk)
|
chunkSamples := make([]float32, 0, samplesPerChunk)
|
||||||
|
bytesPerSample := int64(2 * format.NumChannels) // 16-bit = 2 bytes per channel
|
||||||
|
|
||||||
// file read loop
|
// file read loop
|
||||||
for {
|
for {
|
||||||
@@ -266,10 +267,10 @@ func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformDat
|
|||||||
}
|
}
|
||||||
currentSize := stat.Size()
|
currentSize := stat.Size()
|
||||||
|
|
||||||
readableBytes := currentSize - reader.Pos() // how many bytes are still available
|
// how many bytes can we read without nearing EOF
|
||||||
|
readableBytes := currentSize - int64(samplesPerChunk)*int64(curChunk)*bytesPerSample - 16384 //buffer for safety
|
||||||
|
|
||||||
// Estimate how many samples we can read
|
// Estimate how many samples we can read
|
||||||
bytesPerSample := int64(2 * format.NumChannels) // 16-bit = 2 bytes per channel
|
|
||||||
maxSamples := int(readableBytes / bytesPerSample)
|
maxSamples := int(readableBytes / bytesPerSample)
|
||||||
|
|
||||||
if maxSamples <= 0 {
|
if maxSamples <= 0 {
|
||||||
@@ -279,10 +280,7 @@ func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformDat
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Resize buffer to fit only what’s safe
|
// Resize buffer to fit only what’s safe
|
||||||
safeSamples := maxSamples
|
safeSamples := min(maxSamples, cap(buf.Data))
|
||||||
if safeSamples > cap(buf.Data) {
|
|
||||||
safeSamples = cap(buf.Data)
|
|
||||||
}
|
|
||||||
buf.Data = buf.Data[:safeSamples]
|
buf.Data = buf.Data[:safeSamples]
|
||||||
} else {
|
} else {
|
||||||
// File is done being written, resize read buf to the max
|
// File is done being written, resize read buf to the max
|
||||||
@@ -293,25 +291,20 @@ func analyzeWavFile(ctx context.Context, transcodeFile string, data *waveformDat
|
|||||||
if n == 0 || err == io.EOF {
|
if n == 0 || err == io.EOF {
|
||||||
if fileDone() {
|
if fileDone() {
|
||||||
data.progress = 1024 // set progress to done
|
data.progress = 1024 // set progress to done
|
||||||
|
break
|
||||||
}
|
}
|
||||||
if err == io.EOF && !fileDone() {
|
if err == io.EOF && !fileDone() {
|
||||||
return errors.New("WAV read got premature EOF")
|
return errors.New("WAV read got premature EOF")
|
||||||
}
|
}
|
||||||
break
|
continue
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process samples
|
// Process samples
|
||||||
for i := 0; i < n; i += format.NumChannels {
|
for i := 0; i < n; i++ {
|
||||||
sum := 0
|
sample := float32(buf.Data[i]) / float32(1<<15) // Normalize to [-1, 1]
|
||||||
for c := 0; c < format.NumChannels; c++ {
|
|
||||||
sum += buf.Data[i+c]
|
|
||||||
}
|
|
||||||
avg := float64(sum) / float64(format.NumChannels)
|
|
||||||
// TODO: this assumes 16 bit
|
|
||||||
sample := float32(avg / float64(1<<15)) // Normalize to [-1, 1]
|
|
||||||
chunkSamples = append(chunkSamples, sample)
|
chunkSamples = append(chunkSamples, sample)
|
||||||
|
|
||||||
if len(chunkSamples) >= samplesPerChunk {
|
if len(chunkSamples) >= samplesPerChunk {
|
||||||
@@ -421,27 +414,3 @@ func setPixel(img *image.NRGBA, x, y int, c color.NRGBA) {
|
|||||||
img.Pix[offset+2] = c.B
|
img.Pix[offset+2] = c.B
|
||||||
img.Pix[offset+3] = c.A
|
img.Pix[offset+3] = c.A
|
||||||
}
|
}
|
||||||
|
|
||||||
// wrap an io.ReadSeeker with support for tracking bytes read (Pos())
|
|
||||||
type trackingReader struct {
|
|
||||||
rs io.ReadSeeker
|
|
||||||
pos int64
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trackingReader) Read(p []byte) (int, error) {
|
|
||||||
n, err := t.rs.Read(p)
|
|
||||||
t.pos += int64(n)
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trackingReader) Seek(offset int64, whence int) (int64, error) {
|
|
||||||
newPos, err := t.rs.Seek(offset, whence)
|
|
||||||
if err == nil {
|
|
||||||
t.pos = newPos
|
|
||||||
}
|
|
||||||
return newPos, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *trackingReader) Pos() int64 {
|
|
||||||
return t.pos
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user