summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rhimport/bs1770_responses.go89
-rw-r--r--rhimport/converter.go69
2 files changed, 144 insertions, 14 deletions
diff --git a/rhimport/bs1770_responses.go b/rhimport/bs1770_responses.go
new file mode 100644
index 0000000..b254b9c
--- /dev/null
+++ b/rhimport/bs1770_responses.go
@@ -0,0 +1,89 @@
+//
+// rhimportd
+//
+// The Radio Helsinki Rivendell Import Daemon
+//
+//
+// Copyright (C) 2015-2016 Christian Pointner <equinox@helsinki.at>
+//
+// This file is part of rhimportd.
+//
+// rhimportd is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// any later version.
+//
+// rhimportd is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with rhimportd. If not, see <http://www.gnu.org/licenses/>.
+//
+
+package rhimport
+
+import (
+ "encoding/xml"
+ "fmt"
+ "io"
+)
+
+type BS1770Result struct {
+ Album BS1770ResultAlbum `xml:"album"`
+}
+
+type BS1770ResultAlbum struct {
+ Tracks []BS1770ResultTrack `xml:"track"`
+ Summary BS1770ResultSummary `xml:"summary"`
+}
+
+type BS1770ResultTrack struct {
+ Total uint `xml:"total,attr"`
+ Number uint `xml:"number,attr"`
+ File string `xml:"file,attr"`
+ Integrated BS1770ResultValueLUFS `xml:"integrated"`
+ Momentary BS1770ResultValueLUFS `xml:"momentary"`
+ ShorttermMaximum BS1770ResultValueLUFS `xml:"shortterm-maximum"`
+ SamplePeak BS1770ResultValueSPFS `xml:"sample-peak"`
+ TruePeak BS1770ResultValueTPFS `xml:"true-peak"`
+}
+
+type BS1770ResultSummary struct {
+ Total uint `xml:"total,attr"`
+ Integrated BS1770ResultValueLUFS `xml:"integrated"`
+ Momentary BS1770ResultValueLUFS `xml:"momentary"`
+ ShorttermMaximum BS1770ResultValueLUFS `xml:"shortterm-maximum"`
+ SamplePeak BS1770ResultValueSPFS `xml:"sample-peak"`
+ TruePeak BS1770ResultValueTPFS `xml:"true-peak"`
+}
+
+type BS1770ResultValueLUFS struct {
+ LUFS float64 `xml:"lufs,attr"`
+ LU float64 `xml:"lu,attr"`
+}
+
+type BS1770ResultValueRange struct {
+ LUFS float64 `xml:"lufs,attr"`
+}
+
+type BS1770ResultValueSPFS struct {
+ SPFS float64 `xml:"spfs,attr"`
+ Factor float64 `xml:"factor,attr"`
+}
+
+type BS1770ResultValueTPFS struct {
+ TPFS float64 `xml:"tpfs,attr"`
+ Factor float64 `xml:"factor,attr"`
+}
+
+func NewBS1770ResultFromXML(data io.Reader) (res *BS1770Result, err error) {
+ decoder := xml.NewDecoder(data)
+ res = &BS1770Result{}
+ if xmlerr := decoder.Decode(res); xmlerr != nil {
+ err = fmt.Errorf("Error parsing XML response: %s", xmlerr)
+ return
+ }
+ return
+}
diff --git a/rhimport/converter.go b/rhimport/converter.go
index 82e7f8b..c809c3c 100644
--- a/rhimport/converter.go
+++ b/rhimport/converter.go
@@ -25,6 +25,7 @@
package rhimport
import (
+ "bytes"
"errors"
"fmt"
"io"
@@ -141,32 +142,62 @@ func (ff *FFMpegFetchConverter) GetResult() (result string, err error, loudnessC
//
type FFMpegBS1770FetchConverter struct {
- ffmpeg *exec.Cmd
- bs1770 *exec.Cmd
- pipe io.WriteCloser
- result chan ConverterResult
+ ffmpeg *exec.Cmd
+ bs1770 *exec.Cmd
+ pipe io.WriteCloser
+ resultFF chan ConverterResult
+ resultBS chan ConverterResult
}
func NewFFMpegBS1770FetchConverter(filename string, metadata map[string]string) (ff *FFMpegBS1770FetchConverter, filenameFlac string, err error) {
ff = &FFMpegBS1770FetchConverter{}
ext := filepath.Ext(filename)
filenameFlac = strings.TrimSuffix(filename, ext) + ".flac"
- rhl.Printf("ffmpeg-converter: starting ffmpeg for file '%s' (had extension: '%s')", filenameFlac, ext)
- ff.ffmpeg = exec.Command("ffmpeg", "-loglevel", "warning", "-i", "-", "-map_metadata", "0")
+ rhl.Printf("ffmpeg-bs1770-converter: starting ffmpeg for file '%s' (had extension: '%s')", filenameFlac, ext)
+ ff.ffmpeg = exec.Command("ffmpeg", "-loglevel", "warning", "-i", "pipe:0", "-map_metadata", "0")
if metadata != nil {
for key, value := range metadata {
ff.ffmpeg.Args = append(ff.ffmpeg.Args, "-metadata", fmt.Sprintf("%s=%s", key, value))
}
}
- ff.ffmpeg.Args = append(ff.ffmpeg.Args, "-f", "flac", filenameFlac)
+ ff.ffmpeg.Args = append(ff.ffmpeg.Args, "-f", "flac", filenameFlac, "-f", "flac", "pipe:1")
if ff.pipe, err = ff.ffmpeg.StdinPipe(); err != nil {
return nil, "", err
}
+ var ffStderr bytes.Buffer
+ ff.ffmpeg.Stderr = &ffStderr
- ff.result = make(chan ConverterResult, 1)
+ ff.bs1770 = exec.Command("bs1770gain", "--ebu", "-i", "--xml", "-")
+ var ffstdout io.WriteCloser
+ if ffstdout, err = ff.bs1770.StdinPipe(); err != nil {
+ return nil, "", err
+ }
+ ff.ffmpeg.Stdout = ffstdout
+
+ var bsStdout, bsStderr bytes.Buffer
+ ff.bs1770.Stdout = &bsStdout
+ ff.bs1770.Stderr = &bsStderr
+
+ ff.resultFF = make(chan ConverterResult, 1)
+ ff.resultBS = make(chan ConverterResult, 1)
go func() {
- output, err := ff.ffmpeg.CombinedOutput()
- ff.result <- ConverterResult{strings.TrimSpace(string(output)), err, 0.0}
+ err := ff.ffmpeg.Run()
+ ffstdout.Close()
+ ff.resultFF <- ConverterResult{strings.TrimSpace(string(ffStderr.String())), err, 0.0}
+ }()
+ go func() {
+ if err := ff.bs1770.Run(); err != nil {
+ ff.resultBS <- ConverterResult{strings.TrimSpace(string(bsStderr.String())), err, 0.0}
+ }
+
+ res, err := NewBS1770ResultFromXML(&bsStdout)
+ if err != nil {
+ ff.resultBS <- ConverterResult{bsStdout.String(), err, 0.0}
+ }
+ if len(res.Album.Tracks) == 0 {
+ ff.resultBS <- ConverterResult{bsStdout.String(), fmt.Errorf("bs1770gain returned no/invalid result"), 0.0}
+ }
+ ff.resultBS <- ConverterResult{"", nil, res.Album.Tracks[0].Integrated.LU}
}()
return
}
@@ -180,9 +211,19 @@ func (ff *FFMpegBS1770FetchConverter) Close() (err error) {
}
func (ff *FFMpegBS1770FetchConverter) GetResult() (result string, err error, loudnessCorr float64) {
- if ff.result != nil {
- r := <-ff.result
- return r.output, r.err, r.loudnessCorr
+ var rff, rbs ConverterResult
+ if ff.resultFF != nil {
+ rff = <-ff.resultFF
}
- return "", nil, 0.0
+ if ff.resultBS != nil {
+ rbs = <-ff.resultBS
+ }
+ if rff.err != nil {
+ return rff.output, fmt.Errorf("ffmpeg: %v", rff.err), 0.0
+ }
+ if rbs.err != nil {
+ return rbs.output, fmt.Errorf("bs1770gain: %v", rbs.err), 0.0
+ }
+
+ return "", nil, rbs.loudnessCorr
}