* @brief Converts raw audio input into CSV-formatted text and emits it; * draining the queue lock-free is safe (audio thread is the sole producer), * and the timestamp advances by frameStep * totalFrames so input jitter never * shifts the sample timeline. */
| 1077 | * shifts the sample timeline. |
| 1078 | */ |
| 1079 | void IO::Drivers::Audio::processInputBuffer() |
| 1080 | { |
| 1081 | QByteArray raw; |
| 1082 | QByteArray chunk; |
| 1083 | while (m_inputQueue.try_dequeue(chunk)) |
| 1084 | raw.append(chunk); |
| 1085 | |
| 1086 | if (raw.isEmpty()) |
| 1087 | return; |
| 1088 | |
| 1089 | const int channels = m_config.capture.channels; |
| 1090 | const ma_format format = m_config.capture.format; |
| 1091 | const int bytesPerSample = ma_get_bytes_per_sample(format); |
| 1092 | const int frameSize = bytesPerSample * channels; |
| 1093 | if (frameSize <= 0 || channels <= 0 || raw.size() % frameSize != 0) |
| 1094 | return; |
| 1095 | |
| 1096 | const int totalFrames = raw.size() / frameSize; |
| 1097 | |
| 1098 | m_csvBuffer.seek(0); |
| 1099 | |
| 1100 | const char* ptr = raw.constData(); |
| 1101 | for (int i = 0; i < totalFrames; ++i) { |
| 1102 | for (int ch = 0; ch < channels; ++ch) { |
| 1103 | switch (format) { |
| 1104 | case ma_format_u8: { |
| 1105 | const auto sample = static_cast<quint8>(*ptr); |
| 1106 | m_csvStream << static_cast<int>(sample); |
| 1107 | break; |
| 1108 | } |
| 1109 | case ma_format_s16: { |
| 1110 | const qint16 sample = qFromLittleEndian<qint16>(reinterpret_cast<const quint8*>(ptr)); |
| 1111 | m_csvStream << sample; |
| 1112 | break; |
| 1113 | } |
| 1114 | case ma_format_s24: { |
| 1115 | const quint8* b = reinterpret_cast<const quint8*>(ptr); |
| 1116 | const qint32 s24 = static_cast<qint32>(b[0]) | (static_cast<qint32>(b[1]) << 8) |
| 1117 | | (static_cast<qint32>(b[2]) << 16); |
| 1118 | const qint32 sample = (s24 & 0x800000) ? (s24 | static_cast<qint32>(0xFF000000)) : s24; |
| 1119 | m_csvStream << sample; |
| 1120 | break; |
| 1121 | } |
| 1122 | case ma_format_s32: { |
| 1123 | const qint32 sample = qFromLittleEndian<qint32>(reinterpret_cast<const quint8*>(ptr)); |
| 1124 | m_csvStream << sample; |
| 1125 | break; |
| 1126 | } |
| 1127 | case ma_format_f32: { |
| 1128 | float sample; |
| 1129 | std::memcpy(&sample, ptr, sizeof(float)); |
| 1130 | m_csvStream << sample; |
| 1131 | break; |
| 1132 | } |
| 1133 | default: |
| 1134 | return; |
| 1135 | } |
| 1136 |