Мне нужно найти лучший способ для записи аудиопотока.Я уже построил код низкого уровня в C ++ и связал его части с C #.
Так что у меня есть обратный вызов C ++, который дает мне массив массивов с плавающей запятой - звуковой сигнал.На данный момент моя C ++ lib записывает данные прямо в файл в формате wav, и он просто уведомляет мое приложение C # о завершении записи.
Но я хотел бы иметь больше интерактивности на стороне пользовательского интерфейсанапример, «бесконечный» индикатор выполнения, количество записанных данных, кнопка отмены и т. д., и, в худшем случае, это будет минута, может быть, лучше сохранить ее в памяти.Я очень мало знаю об управлении памятью .NET и C #, поэтому я не знаю, как сделать это эффективно.
Есть ли в C # быстрый контейнер с изменяемым размером, где я мог бы просто поместить данные внутрь и получить доступ к ним позже?это как массив?
Я также хотел бы построить из него изображение формы волны.У меня уже есть эти вещи в C ++, но почему-то мне не нравится идея писать слишком много сообщений, передавать объекты и т. Д.
Итак, чтобы собрать все воедино:
У меня есть неуправляемый обратный вызов C ++, который делает кое-что, и изнутри я хотел бы вызвать метод C # после обработки данных, прототип C будет:
void process (float ** signal, intп);(обычно [2] [n] - для стерео)
Что будет эквивалентно C # и как я могу назвать его из этого обратного вызова C ++?
Что лучшекласс для записи непрерывного потока (например, mem.put (float [] [] data, int size)), а затем считывание его в виде массива или другим простым способом (например, для сохранения из него файла WAV или создания растрового изображения формы волны).)
Будет ли значительная потеря производительности, если я сделаю это в C #?(управляемая оболочка c ++, вызывающая функцию c # и т.д ... и, возможно, некоторые вещи DSP) или я просто параноик?:)
Приветствия,
pablox
Мое решение
Хорошо, я решил это так:
В моем заголовочном файле C ++ я получил структуру передачи:
public ref struct CVAudio {
public:
float *left;
float *right;
int length;
};
Затем в управляемом классе C ++ я объявил:
delegate void GetAudioData([In, Out] CVAudio^ audio);
Затем я могу использовать его в качестве аргумента для метода инициализацииaudio:
void initializeSoundSystem(void *HWnd, GetAudioData ^audio);
Этот делегат также имеет прототип C
typedef void (CALLBACK *GETAUDIODATA)(CVAudio ^a);
, который используется во внутреннем классе C ++ как:
void initializeSoundSystem(HWND HWnd, GETAUDIODATA audio);
Тогда телопервый метод:
void VDAudio::initializeSoundSystem(void *HWnd, GetAudioData ^audio)
{
HWND h = (HWND) HWnd;
acb = audio;
pin_ptr<GetAudioData ^> tmp = &audio;
IntPtr ip = Marshal::GetFunctionPointerForDelegate(audio);
GETAUDIODATA cb = static_cast<GETAUDIODATA>(ip.ToPointer());
audioObserver->initializeSoundSystem(h, cb);
}
Тело audioObserver просто сохраняет этот обратный вызов в объекте и выполняет некоторые связанные со звуком вещи.
Затем в методе обработки вызывается обратный вызов:
VDAudio^ a = gcnew VDAudio();
a->left = VHOST->Master->getSample()[0]; //returns left channel float*
a->right = VHOST->Master->getSample()[1];
a->length = length;
(*callback)(a);
И тело делегата C #:
public void GetSamples(CVAudio audio)
{
unsafe
{
float* l = (float*)audio.left;
float* r = (float*)audio.right;
if (l != null)
{
SamplePack sample = new SamplePack();
sample.left = new float[audio.length];
sample.right = new float[audio.length];
IntPtr lptr = new IntPtr((void*)l);
IntPtr rptr = new IntPtr((void*)r);
Marshal.Copy(lptr, sample.left, 0, audio.length);
Marshal.Copy(rptr, sample.right, 0, audio.length);
this.Dispatcher.Invoke(new Action(delegate()
{
GetSamples(sample);
}));
}
}
}
Так что, вероятно, это не лучший код - я понятия не имею.Только могу сказать, что это работает, не протекает и т.д. :) 1065 *