如何复制 C 数组的每第 N 个字节
How to copy every N-th byte(s) of a C array
我正在用 C++ 编写一些代码,我想在其中播放 .wav
文件并在文件出现时对其执行 FFT(使用 fftw
)(并最终在屏幕上显示该 FFT ncurses
)。这主要是作为一个“for giggles/to see if I can”项目,所以我对我能用或不能用的东西没有任何限制,除了想要尝试保持结果相当轻量级和跨平台(我目前正在 Linux 上执行此操作)。我也在努力做到这一点“正确”,而不仅仅是把它拼凑起来。
我正在使用 SDL2_audio 来实现播放,效果很好。回调在某个时间间隔被调用,请求 N 个字节(似乎是 desiredSamples*nChannels)。我的想法是,在将内存从我的输入缓冲区复制到 SDL 的同时,我还不如将它复制到 fftw3 的输入数组中,以 运行 在其上进行 FFT。然后我可以设置 ncurses
以我想要的任何速率刷新,与音频回调频率分开,它只会从输出数组中提取最新数据。
要注意的是输入文件的格式是通道打包在一起的地方。即“(LR)(LR)(LR)......”。因此,虽然 SDL 期待这一点,但我需要一种方法来只让一个频道发送到 FFTW。
来自 SDL 的音频回调格式如下所示:
void myAudioCallback(void* userdata, Uint8* stream, int len) {
SDL_memset(stream, 0, sizeof(stream));
SDL_memcpy(stream, audio_pos, len);
audio_pos += len;
}
其中userdata
(当前)未使用,stream
是SDL要填充的数组,len
是stream
的长度(即SDL 正在寻找的字节)。
据我所知,没有办法让 memcpy
复制所有其他样本(阅读:复制 N 个字节、跳过 M、复制 N 等)。我目前最好的想法是暴力 for
循环一个 la...
// pseudocode
for (int i=0; i<len/2; i++) {
fftw_in[i] = audio_pos + 2*i*sizeof(sample)
}
或者更蛮力,只需再次读取文件并仅获取每隔一个字节或其他内容。
是否有另一种方法可以实现此目的,或者这是我最好的选择之一?从一个漂亮的单行 memcpy 将数据发送到 SDL,再到某种奇怪的循环将其发送到 fftw,感觉有点笨拙。
可以简化非常困难的 OP 解决方案(用于复制字节):
// pseudocode
const char* s = audio_pos;
for (int d = 0; s < audio_pos + len; d++, s += 2*sizeof(sample)) {
fftw_in[d] = *s;
}
如果我更新 fftw_in
是什么,我会 memcpy 块 sizeof(*fftw_in)
。
请检查@S.M. 的解决方案生成的程序集。
如果代码未矢量化,我会使用内部函数(取决于您的硬件支持),例如 _mm_mask_blend_epi8
我正在用 C++ 编写一些代码,我想在其中播放 .wav
文件并在文件出现时对其执行 FFT(使用 fftw
)(并最终在屏幕上显示该 FFT ncurses
)。这主要是作为一个“for giggles/to see if I can”项目,所以我对我能用或不能用的东西没有任何限制,除了想要尝试保持结果相当轻量级和跨平台(我目前正在 Linux 上执行此操作)。我也在努力做到这一点“正确”,而不仅仅是把它拼凑起来。
我正在使用 SDL2_audio 来实现播放,效果很好。回调在某个时间间隔被调用,请求 N 个字节(似乎是 desiredSamples*nChannels)。我的想法是,在将内存从我的输入缓冲区复制到 SDL 的同时,我还不如将它复制到 fftw3 的输入数组中,以 运行 在其上进行 FFT。然后我可以设置 ncurses
以我想要的任何速率刷新,与音频回调频率分开,它只会从输出数组中提取最新数据。
要注意的是输入文件的格式是通道打包在一起的地方。即“(LR)(LR)(LR)......”。因此,虽然 SDL 期待这一点,但我需要一种方法来只让一个频道发送到 FFTW。
来自 SDL 的音频回调格式如下所示:
void myAudioCallback(void* userdata, Uint8* stream, int len) {
SDL_memset(stream, 0, sizeof(stream));
SDL_memcpy(stream, audio_pos, len);
audio_pos += len;
}
其中userdata
(当前)未使用,stream
是SDL要填充的数组,len
是stream
的长度(即SDL 正在寻找的字节)。
据我所知,没有办法让 memcpy
复制所有其他样本(阅读:复制 N 个字节、跳过 M、复制 N 等)。我目前最好的想法是暴力 for
循环一个 la...
// pseudocode
for (int i=0; i<len/2; i++) {
fftw_in[i] = audio_pos + 2*i*sizeof(sample)
}
或者更蛮力,只需再次读取文件并仅获取每隔一个字节或其他内容。
是否有另一种方法可以实现此目的,或者这是我最好的选择之一?从一个漂亮的单行 memcpy 将数据发送到 SDL,再到某种奇怪的循环将其发送到 fftw,感觉有点笨拙。
可以简化非常困难的 OP 解决方案(用于复制字节):
// pseudocode
const char* s = audio_pos;
for (int d = 0; s < audio_pos + len; d++, s += 2*sizeof(sample)) {
fftw_in[d] = *s;
}
如果我更新 fftw_in
是什么,我会 memcpy 块 sizeof(*fftw_in)
。
请检查@S.M. 的解决方案生成的程序集。
如果代码未矢量化,我会使用内部函数(取决于您的硬件支持),例如 _mm_mask_blend_epi8