6#include <mach/mach_time.h>
15 struct mach_timebase_info timeBaseInfo;
16 mach_timebase_info(&timeBaseInfo);
17 sFrequency =
static_cast<
double>(timeBaseInfo.denom) /
static_cast<
double>(timeBaseInfo.numer);
18 sFrequency *= 1000000000.0;
20 sIsInitialized =
true;
26 return mach_absolute_time();
36QAudioFormat
CoreAudioUtils::toQAudioFormat(AudioStreamBasicDescription
const& sf)
38 QAudioFormat audioFormat;
40 if ((sf.mFormatFlags & kAudioFormatFlagIsBigEndian) != 0 && QSysInfo::ByteOrder != QSysInfo::LittleEndian)
44 QAudioFormat::SampleFormat format = QAudioFormat::Unknown;
45 switch (sf.mBitsPerChannel) {
47 if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) == 0)
48 format = QAudioFormat::UInt8;
51 if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
52 format = QAudioFormat::Int16;
55 if ((sf.mFormatFlags & kAudioFormatFlagIsSignedInteger) != 0)
56 format = QAudioFormat::Int32;
57 else if ((sf.mFormatFlags & kAudioFormatFlagIsFloat) != 0)
58 format = QAudioFormat::Float;
64 audioFormat.setSampleFormat(format);
65 audioFormat.setSampleRate(sf.mSampleRate);
66 audioFormat.setChannelCount(sf.mChannelsPerFrame);
71AudioStreamBasicDescription
CoreAudioUtils::toAudioStreamBasicDescription(QAudioFormat
const& audioFormat)
73 AudioStreamBasicDescription sf;
75 sf.mFormatFlags = kAudioFormatFlagIsPacked;
76 sf.mSampleRate = audioFormat.sampleRate();
77 sf.mFramesPerPacket = 1;
78 sf.mChannelsPerFrame = audioFormat.channelCount();
79 sf.mBitsPerChannel = audioFormat.bytesPerSample() * 8;
80 sf.mBytesPerFrame = audioFormat.bytesPerFrame();
81 sf.mBytesPerPacket = sf.mFramesPerPacket * sf.mBytesPerFrame;
82 sf.mFormatID = kAudioFormatLinearPCM;
84 switch (audioFormat.sampleFormat()) {
85 case QAudioFormat::Int16:
86 case QAudioFormat::Int32:
87 sf.mFormatFlags |= kAudioFormatFlagIsSignedInteger;
89 case QAudioFormat::Float:
90 sf.mFormatFlags |= kAudioFormatFlagIsFloat;
92 case QAudioFormat::UInt8:
94 case QAudioFormat::Unknown:
95 case QAudioFormat::NSampleFormats:
103static constexpr struct {
107 { QAudioFormat::FrontLeft, kAudioChannelLabel_Left },
108 { QAudioFormat::FrontRight, kAudioChannelLabel_Right },
109 { QAudioFormat::FrontCenter, kAudioChannelLabel_Center },
110 { QAudioFormat::LFE, kAudioChannelLabel_LFEScreen },
111 { QAudioFormat::BackLeft, kAudioChannelLabel_LeftSurround },
112 { QAudioFormat::BackRight, kAudioChannelLabel_RightSurround },
113 { QAudioFormat::FrontLeftOfCenter, kAudioChannelLabel_LeftCenter },
114 { QAudioFormat::FrontRightOfCenter, kAudioChannelLabel_RightCenter },
115 { QAudioFormat::BackCenter, kAudioChannelLabel_CenterSurround },
116 { QAudioFormat::LFE2, kAudioChannelLabel_LFE2 },
117 { QAudioFormat::SideLeft, kAudioChannelLabel_LeftSurroundDirect },
118 { QAudioFormat::SideRight, kAudioChannelLabel_RightSurroundDirect },
119 { QAudioFormat::TopFrontLeft, kAudioChannelLabel_VerticalHeightLeft },
120 { QAudioFormat::TopFrontRight, kAudioChannelLabel_VerticalHeightRight },
121 { QAudioFormat::TopFrontCenter, kAudioChannelLabel_VerticalHeightCenter },
122 { QAudioFormat::TopCenter, kAudioChannelLabel_CenterTopMiddle },
123 { QAudioFormat::TopBackLeft, kAudioChannelLabel_TopBackLeft },
124 { QAudioFormat::TopBackRight, kAudioChannelLabel_TopBackRight },
125 { QAudioFormat::TopSideLeft, kAudioChannelLabel_LeftTopMiddle },
126 { QAudioFormat::TopSideRight, kAudioChannelLabel_RightTopMiddle },
127 { QAudioFormat::TopBackCenter, kAudioChannelLabel_TopBackCenter },
130std::unique_ptr<AudioChannelLayout>
CoreAudioUtils::toAudioChannelLayout(
const QAudioFormat &format, UInt32 *size)
132 auto channelConfig = format.channelConfig();
133 if (channelConfig == QAudioFormat::ChannelConfigUnknown)
134 channelConfig = QAudioFormat::defaultChannelConfigForChannelCount(format.channelCount());
136 *size =
sizeof(AudioChannelLayout) +
int(QAudioFormat::NChannelPositions)*
sizeof(AudioChannelDescription);
137 auto *layout =
static_cast<AudioChannelLayout *>(malloc(*size));
138 memset(layout, 0, *size);
139 layout->mChannelLayoutTag = kAudioChannelLayoutTag_UseChannelDescriptions;
141 for (
const auto &m : channelMap) {
142 if (channelConfig & QAudioFormat::channelConfig(m.pos))
143 layout->mChannelDescriptions[layout->mNumberChannelDescriptions++].mChannelLabel = m.label;
146 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontCenter)) {
147 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
148 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
149 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
150 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 0.f;
151 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
152 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
154 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontLeft)) {
155 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
156 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
157 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
158 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = -45.f;
159 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
160 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
162 if (channelConfig & QAudioFormat::channelConfig(QAudioFormat::BottomFrontRight)) {
163 auto &desc = layout->mChannelDescriptions[layout->mNumberChannelDescriptions++];
164 desc.mChannelLabel = kAudioChannelLabel_UseCoordinates;
165 desc.mChannelFlags = kAudioChannelFlags_SphericalCoordinates;
166 desc.mCoordinates[kAudioChannelCoordinates_Azimuth] = 45.f;
167 desc.mCoordinates[kAudioChannelCoordinates_Elevation] = -20.;
168 desc.mCoordinates[kAudioChannelCoordinates_Distance] = 1.f;
171 return std::unique_ptr<AudioChannelLayout>(layout);
174static constexpr struct {
178 { kAudioChannelLayoutTag_Mono, QAudioFormat::ChannelConfigMono },
179 { kAudioChannelLayoutTag_Stereo, QAudioFormat::ChannelConfigStereo },
180 { kAudioChannelLayoutTag_StereoHeadphones, QAudioFormat::ChannelConfigStereo },
181 { kAudioChannelLayoutTag_MPEG_1_0, QAudioFormat::ChannelConfigMono },
182 { kAudioChannelLayoutTag_MPEG_2_0, QAudioFormat::ChannelConfigStereo },
183 { kAudioChannelLayoutTag_MPEG_3_0_A, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
184 QAudioFormat::FrontRight,
185 QAudioFormat::FrontCenter) },
186 { kAudioChannelLayoutTag_MPEG_4_0_A, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
187 QAudioFormat::FrontRight,
188 QAudioFormat::FrontCenter,
189 QAudioFormat::BackCenter) },
190 { kAudioChannelLayoutTag_MPEG_5_0_A, QAudioFormat::ChannelConfigSurround5Dot0 },
191 { kAudioChannelLayoutTag_MPEG_5_1_A, QAudioFormat::ChannelConfigSurround5Dot1 },
192 { kAudioChannelLayoutTag_MPEG_6_1_A, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
193 QAudioFormat::FrontRight,
194 QAudioFormat::FrontCenter,
196 QAudioFormat::BackLeft,
197 QAudioFormat::BackRight,
198 QAudioFormat::BackCenter) },
199 { kAudioChannelLayoutTag_MPEG_7_1_A, QAudioFormat::ChannelConfigSurround7Dot1 },
200 { kAudioChannelLayoutTag_SMPTE_DTV, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
201 QAudioFormat::FrontRight,
202 QAudioFormat::FrontCenter,
204 QAudioFormat::BackLeft,
205 QAudioFormat::BackRight,
206 QAudioFormat::TopFrontLeft,
207 QAudioFormat::TopFrontRight) },
209 { kAudioChannelLayoutTag_ITU_2_1, QAudioFormat::ChannelConfig2Dot1 },
210 { kAudioChannelLayoutTag_ITU_2_2, QAudioFormat::channelConfig(QAudioFormat::FrontLeft,
211 QAudioFormat::FrontRight,
212 QAudioFormat::BackLeft,
213 QAudioFormat::BackRight) }
217QAudioFormat::ChannelConfig
CoreAudioUtils::fromAudioChannelLayout(
const AudioChannelLayout *layout)
219 for (
const auto &m : layoutTagMap) {
220 if (m.tag == layout->mChannelLayoutTag)
221 return m.channelConfig;
224 quint32 channels = 0;
225 if (layout->mChannelLayoutTag == kAudioChannelLayoutTag_UseChannelDescriptions) {
227 if (layout->mNumberChannelDescriptions == 1
228 && (layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown
229 || layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Mono))
230 return QAudioFormat::ChannelConfigMono;
231 if (layout->mNumberChannelDescriptions == 2 &&
232 layout->mChannelDescriptions[0].mChannelLabel == kAudioChannelLabel_Unknown &&
233 layout->mChannelDescriptions[1].mChannelLabel == kAudioChannelLabel_Unknown)
234 return QAudioFormat::ChannelConfigStereo;
236 for (uint i = 0; i < layout->mNumberChannelDescriptions; ++i) {
237 const auto channelLabel = layout->mChannelDescriptions[i].mChannelLabel;
238 if (channelLabel == kAudioChannelLabel_Unknown) {
244 const auto found = std::find_if(channelMap, std::end(channelMap),
245 [channelLabel](
const auto &labelWithPos) {
246 return labelWithPos.label == channelLabel;
249 if (found ==
std::end(channelMap))
250 qWarning() <<
"audio device has unrecognized channel, index:" << i
251 <<
"label:" << channelLabel;
253 channels |= QAudioFormat::channelConfig(found->pos);
256 qWarning() <<
"Channel layout uses unimplemented format, channelLayoutTag:"
257 << layout->mChannelLayoutTag;
259 return QAudioFormat::ChannelConfig(channels);
static double frequency()
Combined button and popup list for selecting options.
AudioChannelLayoutTag tag
QAudioFormat::ChannelConfig channelConfig
QAudioFormat::AudioChannelPosition pos