#c
#c
Вопрос:
Я пытаюсь написать одну функцию, которая может деинтерлеевывать 8/16/24/32-битные аудиоданные, учитывая, что аудиоданные естественным образом поступают в 8-битный буфер.
У меня это работает для 8 бит, и оно работает для 16/24/32, но только для первого канала (канал 0). Я перепробовал так много
и *
и других операторов, что на данный момент я просто предполагаю. Я не могу найти волшебную формулу. Я использую C , но также принял бы a memcpy
в вектор, если это проще всего.
Ознакомьтесь с кодом. Если вы измените demux
вызов на другой битрейт, вы увидите проблему. Я уверен, что здесь есть простое математическое решение, я просто не могу его получить.
#include <vector>
#include <map>
#include <iostream>
#include <iomanip>
#include <string>
#include <string.h>
const int bitrate = 8;
const int channel_count = 5;
const int audio_size = bitrate * channel_count * 4;
uint8_t audio_ptr[audio_size];
const int bytes_per_channel = audio_size / channel_count;
void Demux(int bitrate){
int byterate = bitrate/8;
std::map<int, std::vector<uint8_t> > channel_audio;
for(int i = 0; i < channel_count; i ){
std::vector<uint8_t> audio;
audio.reserve(bytes_per_channel);
for(int x = 0; x < bytes_per_channel; x = byterate){
for(int z = 0; z < byterate; z ){
// What is the magic formula!
audio.push_back(audio_ptr[(x * channel_count) i z]);
}
}
channel_audio.insert(std::make_pair(i, audio));
}
int remapsize = 0;
std::cout << "nRemapped Audio";
std::map<int, std::vector<uint8_t> >::iterator it;
for(it = channel_audio.begin(); it != channel_audio.end(); it){
std::cout << "nChannel" << it->first << " ";
std::vector<uint8_t> v = it->second;
remapsize = v.size();
for(size_t i = 0; i < v.size(); i ){
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(2) << v[i] << " ";
if(i amp;amp; (i 1) % 32 == 0){
std::cout << std::endl;
}
}
}
std::cout << "Total remapped audio size is " << std::dec << remapsize << std::endl;
}
int main()
{
// External data
std::cout << "Raw Audion";
for(int i = 0; i < audio_size; i ){
audio_ptr[i] = i;
std::cout << "0x" << std::hex << std::setfill('0') << std::setw(2) << audio_ptr[i] << " ";
if(i amp;amp; (i 1) % 32 == 0){
std::cout << std::endl;
}
}
std::cout << "Total raw audio size is " << std::dec << audio_size << std::endl;
Demux(8);
//Demux(16);
//Demux(24);
//Demux(32);
}
Ответ №1:
На самом деле вы довольно близки. Но код сбивает с толку: в частности, имена переменных и то, какие фактические значения они представляют. В результате кажется, что вы просто угадываете математику. Итак, давайте вернемся к исходной точке и определим, что именно нам нужно сделать, и математика очень легко выпадет из этого.
Во-первых, просто представьте, что у нас есть один образец, охватывающий каждый из пяти каналов. Это называется аудиокадром для этого образца. Кадр выглядит следующим образом:
[channel0][channel1][channel2][channel3][channel4]
Ширина выборки в одном канале вызывается byterate
в вашем коде, но мне не нравится это имя. Я собираюсь вызвать его bytes_per_sample
вместо этого. Вы можете легко увидеть ширину всего кадра, это:
int bytes_per_frame = bytes_per_sample * channel_count;
Должно быть столь же очевидно, что для нахождения начального смещения для канала c
в пределах одного кадра вы умножаете следующим образом:
int sample_offset_in_frame = bytes_per_sample * c;
Это практически все, что вам нужно! Последний бит — это ваш z
цикл, который охватывает каждый байт в одной выборке для одного канала. Я не знаю, что z
должно представлять, кроме случайного однобуквенного идентификатора, который вы выбрали, но давайте просто оставим его.
Собрав все это вместе, вы получаете абсолютное смещение выборки s
в канале c
, а затем копируете из него отдельные байты:
int sample_offset = bytes_per_frame * s bytes_per_sample * c;
for (int z = 0; z < bytes_per_sample; z) {
audio.push_back(audio_ptr[sample_offset z]);
}
На самом деле предполагается, что вы перебираете количество выборок, а не количество байтов в вашем канале. Итак, давайте покажем все циклы для завершения:
const int bytes_per_sample = bitrate / 8;
const int bytes_per_frame = bytes_per_sample * channel_count;
const int num_samples = audio_size / bytes_per_frame;
for (int c = 0; c < channel_count; c)
{
int sample_offset = bytes_per_sample * c;
for (int s = 0; s < num_samples; s)
{
for (int z = 0; z < bytes_per_sample; z)
{
audio.push_back(audio_ptr[sample_offset z]);
}
// Skip to next frame
sample_offset = bytes_per_frame;
}
}
Здесь вы увидите, что я разделил математику так, чтобы она выполняла меньше умножений в циклах. Это в основном для удобства чтения, но также может помочь компилятору понять, что происходит, когда он пытается оптимизировать. Опасения по поводу оптимизации являются второстепенными (и в вашем случае с этими векторами и картой возникают гораздо более дорогостоящие проблемы)..
Самое главное, что у вас есть читаемый код с разумными именами переменных, который имеет логический смысл.
Комментарии:
1. Спасибо ..! Я ценю полное пошаговое руководство.