package libebur128 /* #cgo pkg-config: libebur128 #include */ import "C" import ( "fmt" "time" ) type Ebur128Mode int const ( LoudnessMomentary Ebur128Mode = C.EBUR128_MODE_M LoudnessShortTerm Ebur128Mode = C.EBUR128_MODE_S LoudnessGlobalMomentary Ebur128Mode = C.EBUR128_MODE_I LoudnessRange Ebur128Mode = C.EBUR128_MODE_LRA SamplePeak Ebur128Mode = C.EBUR128_MODE_SAMPLE_PEAK TruePeak Ebur128Mode = C.EBUR128_MODE_TRUE_PEAK Histogram Ebur128Mode = C.EBUR128_MODE_HISTOGRAM ) func GetVersion() (major, minor, patch int) { var i, j, k C.int C.ebur128_get_version(&i, &j, &k) return int(i), int(j), int(k) } type State struct { p *C.ebur128_state channels int } func NewState(channels, sampleRate int, mode Ebur128Mode) *State { p := C.ebur128_init(C.uint(channels), C.ulong(sampleRate), C.int(mode)) if p == nil { return nil } return &State{ p: p, channels: channels, } } //GetSamplePeak Get maximum sample peak from all frames that have been processed. func (s *State) GetSamplePeak() (out []float64, err error) { var j C.double for i := 0; i < s.channels; i++ { ret := C.ebur128_sample_peak(s.p, C.uint(i), &j) if ret != C.EBUR128_SUCCESS { return nil, fmt.Errorf("error calculating peak: %d", ret) } out = append(out, float64(j)) } return } //GetPreviousSamplePeak Get maximum sample peak from the last call to Add*() func (s *State) GetPreviousSamplePeak() (out []float64, err error) { var j C.double for i := 0; i < s.channels; i++ { ret := C.ebur128_prev_sample_peak(s.p, C.uint(i), &j) if ret != C.EBUR128_SUCCESS { return nil, fmt.Errorf("error calculating peak: %d", ret) } out = append(out, float64(j)) } return } //GetTruePeak Get maximum true peak from all frames that have been processed. func (s *State) GetTruePeak() (out []float64, err error) { var j C.double for i := 0; i < s.channels; i++ { ret := C.ebur128_true_peak(s.p, C.uint(i), &j) if ret != C.EBUR128_SUCCESS { return nil, fmt.Errorf("error calculating peak: %d", ret) } out = append(out, float64(j)) } return } //GetPreviousTruePeak Get maximum true peak from the last call to Add*() func (s *State) GetPreviousTruePeak() (out []float64, err error) { var j C.double for i := 0; i < s.channels; i++ { ret := C.ebur128_prev_true_peak(s.p, C.uint(i), &j) if ret != C.EBUR128_SUCCESS { return nil, fmt.Errorf("error calculating peak: %d", ret) } out = append(out, float64(j)) } return } //GetLoudnessGlobal Get global integrated loudness in LUFS. func (s *State) GetLoudnessGlobal() (out float64, err error) { var i C.double ret := C.ebur128_loudness_global(s.p, &i) if ret != C.EBUR128_SUCCESS { return float64(i), fmt.Errorf("error calculating loudness: %d", ret) } return float64(i), nil } //GetLoudnessGlobalMultiple Get global integrated loudness in LUFS across multiple instances. func GetLoudnessGlobalMultiple(states []*State) (out float64, err error) { slice := make([]*C.ebur128_state, len(states)) for i, s := range states { slice[i] = s.p } var i C.double ret := C.ebur128_loudness_global_multiple(&slice[0], C.ulong(len(slice)), &i) if ret != C.EBUR128_SUCCESS { return float64(i), fmt.Errorf("error calculating loudness: %d", ret) } return float64(i), nil } //SetMaxWindow Set the maximum window duration. func (s *State) SetMaxWindow(window time.Duration) (err error) { ret := C.ebur128_set_max_window(s.p, C.ulong(window.Milliseconds())) if ret != C.EBUR128_SUCCESS { return fmt.Errorf("error calculating loudness: %d", ret) } return nil } //GetLoudnessWindow Get loudness of the specified window in LUFS. func (s *State) GetLoudnessWindow(window time.Duration) (out float64, err error) { var i C.double ret := C.ebur128_loudness_window(s.p, C.ulong(window.Milliseconds()), &i) if ret != C.EBUR128_SUCCESS { return float64(i), fmt.Errorf("error calculating loudness: %d", ret) } return float64(i), nil } //GetLoudnessMomentary Get momentary loudness (last 400ms) in LUFS. func (s *State) GetLoudnessMomentary() (out float64, err error) { var i C.double ret := C.ebur128_loudness_momentary(s.p, &i) if ret != C.EBUR128_SUCCESS { return float64(i), fmt.Errorf("error calculating loudness: %d", ret) } return float64(i), nil } //GetLoudnessShortTerm Get short-term loudness (last 3s) in LUFS. func (s *State) GetLoudnessShortTerm() (out float64, err error) { var i C.double ret := C.ebur128_loudness_shortterm(s.p, &i) if ret != C.EBUR128_SUCCESS { return float64(i), fmt.Errorf("error calculating loudness: %d", ret) } return float64(i), nil } func (s *State) AddFloat(src []float32) error { ret := C.ebur128_add_frames_float(s.p, (*C.float)(&src[0]), C.size_t(len(src)/s.channels)) if ret != C.EBUR128_SUCCESS { return fmt.Errorf("error adding frames: %d", ret) } return nil } func (s *State) AddDouble(src []float64) error { ret := C.ebur128_add_frames_double(s.p, (*C.double)(&src[0]), C.size_t(len(src)/s.channels)) if ret != C.EBUR128_SUCCESS { return fmt.Errorf("error adding frames: %d", ret) } return nil } func (s *State) AddShort(src []int16) error { ret := C.ebur128_add_frames_short(s.p, (*C.short)(&src[0]), C.size_t(len(src)/s.channels)) if ret != C.EBUR128_SUCCESS { return fmt.Errorf("error adding frames: %d", ret) } return nil } func (s *State) AddInt(src []int32) error { ret := C.ebur128_add_frames_int(s.p, (*C.int)(&src[0]), C.size_t(len(src)/s.channels)) if ret != C.EBUR128_SUCCESS { return fmt.Errorf("error adding frames: %d", ret) } return nil } func (s *State) Close() { if s.p != nil { C.ebur128_destroy(&s.p) s.p = nil } }