1 #pragma once
2 
3 #include "audio/types.h"
4 #include "util/assert.h"
5 #include "util/macros.h"
6 #include "util/optional.h"
7 
8 namespace mixxx {
9 
10 namespace audio {
11 
12 // Properties that characterize an uncompressed PCM audio signal.
13 class SignalInfo final {
14     // Properties
15     MIXXX_DECL_PROPERTY(ChannelCount, channelCount, ChannelCount)
16     MIXXX_DECL_PROPERTY(SampleRate, sampleRate, SampleRate)
17 
18   public:
19     constexpr SignalInfo() = default;
SignalInfo(ChannelCount channelCount,SampleRate sampleRate)20     SignalInfo(
21             ChannelCount channelCount,
22             SampleRate sampleRate)
23             : m_channelCount(channelCount),
24               m_sampleRate(sampleRate) {
25     }
26     SignalInfo(SignalInfo&&) = default;
27     SignalInfo(const SignalInfo&) = default;
28     /*non-virtual*/ ~SignalInfo() = default;
29 
isValid()30     constexpr bool isValid() const {
31         return getChannelCount().isValid() &&
32                 getSampleRate().isValid();
33     }
34 
35     SignalInfo& operator=(SignalInfo&&) = default;
36     SignalInfo& operator=(const SignalInfo&) = default;
37 
38     // Conversion: #samples / sample offset -> #frames / frame offset
39     // Only works for integer sample offsets on frame boundaries!
samples2frames(SINT samples)40     SINT samples2frames(SINT samples) const {
41         DEBUG_ASSERT(getChannelCount().isValid());
42         DEBUG_ASSERT(0 == (samples % getChannelCount()));
43         return samples / getChannelCount();
44     }
45 
46     // Conversion: #samples / sample offset -> #frames / frame offset
samples2framesFractional(double samples)47     double samples2framesFractional(double samples) const {
48         DEBUG_ASSERT(getChannelCount().isValid());
49         return samples / getChannelCount();
50     }
51 
52     // Conversion: #frames / frame offset -> #samples / sample offset
frames2samples(SINT frames)53     SINT frames2samples(SINT frames) const {
54         DEBUG_ASSERT(getChannelCount().isValid());
55         return frames * getChannelCount();
56     }
57 
58     // Conversion: #frames / frame offset -> second offset
frames2secsFractional(double frames)59     double frames2secsFractional(double frames) const {
60         DEBUG_ASSERT(getSampleRate().isValid());
61         return frames / getSampleRate();
62     }
63 
64     // Conversion: #frames / frame offset -> second offset
frames2secs(SINT frames)65     double frames2secs(SINT frames) const {
66         return frames2secsFractional(static_cast<double>(frames));
67     }
68 
69     // Conversion: second offset -> #frames / frame offset
secs2frames(double seconds)70     double secs2frames(double seconds) const {
71         DEBUG_ASSERT(getSampleRate().isValid());
72         return seconds * getSampleRate();
73     }
74 
75     // Conversion: #frames / frame offset -> millisecond offset
frames2millis(SINT frames)76     double frames2millis(SINT frames) const {
77         return frames2secs(frames) * 1000;
78     }
79 
80     // Conversion: millisecond offset -> #frames / frame offset
millis2frames(double milliseconds)81     double millis2frames(double milliseconds) const {
82         return secs2frames(milliseconds / 1000);
83     }
84 };
85 
86 bool operator==(
87         const SignalInfo& lhs,
88         const SignalInfo& rhs);
89 
90 inline bool operator!=(
91         const SignalInfo& lhs,
92         const SignalInfo& rhs) {
93     return !(lhs == rhs);
94 }
95 
96 QDebug operator<<(QDebug dbg, const SignalInfo& arg);
97 
98 } // namespace audio
99 
100 } // namespace mixxx
101 
102 Q_DECLARE_METATYPE(mixxx::audio::SignalInfo)
103