【问题标题】:Cast void* to memcpy to get a float value将 void* 转换为 memcpy 以获取浮点值
【发布时间】:2020-08-23 20:06:06
【问题描述】:

这是我试图解决的问题的一个示例,我从麦克风获取缓冲区并尝试处理它的内容。正如这个问题的指导Im trying to convert a char* to float*

我声明一个向量来保存我想要的浮点数的逻辑,然后将其调整为 ArBuffer() 的大小,然后复制到向量。

ArBuffer() 是无效的,必须将其转换为 memcpy?

#include "Lib_api.h"
#include <alsa/asoundlib.h>
#include <stdio.h>
#include "audiorecorder.h"
#include "Globals.h"
#include <iostream>
#include <inttypes.h>
#include <string.h>
#include <stdlib.h>
#include <vector>
#include <cstring>

using namespace std;

//Declare Creation
void* mCore;

int main(void)
{
    // recorder
    int rc;
    int mode = 3;
    const float sampleRate = 44100; //max 22Hz
    int bufferSize = 1024; //Check this should be good 1024

    //initialise
    mCore = OXY_Create();

    //initialise audio recorder
    rc = arInitialise();

    OXY_Configure(mode, sampleRate, bufferSize, mCore);
    //initialise check hardware
    if(rc)
    {
        std::cerr << "Fatal error: Audio could not be initialised" << rc << std::endl <<std::endl;
        arFree();
        exit(1);
    }

    //start recording
    rc = arStartRecording();

    //application loop
    while(arIsRunning())
    {
        //declare vector
        std::vector<float> values;

        //resize values to size of arbuffersize
        values.resize(arBufferSize(), sizeof(float));
        //arBufferSize()/sizeof(float);

       //need to cast this arBuffer() to memcpy?

        std::memcpy(arBuffer(), &values[0], sizeof(values[0]));

        // values[0] this will hold the latest data from the microphone?
        int ret = OXY_DecodeAudioBuffer(&values[0], values.size(), mCore);

        if (ret == -2)
        {
        std::cerr << "FOUND_TOKEN ---> -2 " << std::endl << std::endl;
        }
            else if(ret>=0)
        {

        std::cerr << "Decode started ---> -2 " << ret << std::endl << std::endl;
        }
        else if (ret == -3)
        {
        //int sizeStringDecoded = OXY_GetDecodedData(mStringDecoded, mCore);

         std::cerr << "STRING DECODED ---> -2 " << std::endl << std::endl;
         // ...
        }
        else
        {
          std::cerr << "No data found in this buffer" << std::endl << std::endl;
            //no data found in this buffer
        }
    }

    //Clean up
    arFree();

  return 0;
}

按照另一个 SO question 的建议,我将格式从 SND_PCM_FORMAT_S16_LE 更改为 SND_PCM_FORMAT_FLOAT_LE。

* Use the newer ALSA API */
#define ALSA_PCM_NEW_HW_PARAMS_API

#include <stdlib.h>
#include <alsa/asoundlib.h>
#include <pthread.h>
#include "settings.h"
#include "audiorecorder.h"


pthread_t thr;
pthread_mutex_t mutex;
snd_pcm_t *handle;
snd_pcm_uframes_t frames;
unsigned char* buffer;
BOOL running;
size_t buffersize;


BOOL arIsRunning(void)
{
    return running;
}


void arAcquireBuffer(void)
{
    //printf("Acquired buffer\n");
    pthread_mutex_lock(&mutex);
}


void arReleaseBuffer(void)
{
    //printf("Released buffer\n");
    pthread_mutex_unlock(&mutex);
}


const unsigned char* arBuffer(void)
{
    return buffer;
}


const size_t arBufferSize(void)
{
    return buffersize;
}


void* entry_point(void *arg)
{
    int rc;

    fprintf(stderr, "Listening...\n");

  while (running)
    {
        arAcquireBuffer();
    rc = snd_pcm_readi(handle, buffer, frames);

    //stream to stdout - useful for testing/debugging
    //write(1, buffer, buffersize);
        arReleaseBuffer();

    if (rc == -EPIPE) {
      /* EPIPE means overrun */
      fprintf(stderr, "overrun occurred\n");
      snd_pcm_prepare(handle);
    }
        else if (rc < 0) {
      fprintf(stderr, "error from read: %s\n", snd_strerror(rc));
            running = FALSE;
    }
        else if (rc != (int)frames) {
      fprintf(stderr, "short read, read %d frames\n", rc);
    }
 }

    return NULL;
}



int arInitialise(void)
{
  snd_pcm_hw_params_t *params;
  unsigned int val;
  int rc, dir;

    running = FALSE;

  /* Open PCM device for recording (capture). */
  rc = snd_pcm_open(&handle, RECORDER_DEVICE, SND_PCM_STREAM_CAPTURE, 0);
  if (rc < 0) {
    fprintf(stderr, "unable to open pcm device: %s\n", snd_strerror(rc));
    return rc;
  }
    else
    {
        fprintf(stderr, "Successfully opened default capture device.\n");
    }

  /* Allocate a hardware parameters object. */
  snd_pcm_hw_params_alloca(&params);

  /* Fill it in with default values. */
  snd_pcm_hw_params_any(handle, params);

  /* Set the desired hardware parameters. */

  /* Interleaved mode */
  snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);

  /* Signed 16-bit little-endian format */
  snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_FLOAT_LE)


  /* Channels */
  snd_pcm_hw_params_set_channels(handle, params, NUM_CHANNELS);
    fprintf(stderr, "Channels set to %d.\n", NUM_CHANNELS);


  /* sampling rate */
  val = SAMPLE_RATE;
  snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
    fprintf(stderr, "Samplerate set to %d.\n", val);

  /* Set period to FRAMES_PER_BUFFER frames. */
  frames = FRAMES_PER_BUFFER;
  snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);

  /* Write the parameters to the driver */
  rc = snd_pcm_hw_params(handle, params);
  if (rc < 0) {
    fprintf(stderr, "unable to set hw parameters: %s\n", snd_strerror(rc));
    return rc;
  }

  /* Use a buffer large enough to hold one period */
  snd_pcm_hw_params_get_period_size(params, &frames, &dir);
  buffersize = frames * 2 * NUM_CHANNELS; /* 2 bytes/sample * channels */
  buffer = (unsigned char*) malloc(buffersize);

  /* We want to loop forever */
  //snd_pcm_hw_params_get_period_time(params, &val, &dir);

  return 0;
}


int arStartRecording(void)
{
    if(running) return 1;

  if(pthread_mutex_init(&mutex, NULL))
  {
    printf("Unable to initialize mutex\n");
    return -1;
  }

  if(pthread_create(&thr, NULL, &entry_point, NULL))
  {
    fprintf(stderr, "Could not create recorder thread!\n");
        running = FALSE;
    return -1;
  }

    running = TRUE;
    return 0;
}


void arStopRecording(void)
{
    running = FALSE;
}


void arFree(void)
{
    running = FALSE;
    sleep(500);
  snd_pcm_drain(handle);
  snd_pcm_close(handle);
  pthread_mutex_destroy(&mutex);
  free(buffer);
}

【问题讨论】:

  • 您认为您可能需要投稿的原因是什么?阅读memcpy 的文档并注意其参数的顺序。
  • 我认为我需要强制转换,因为 memcpy 说它无法使用 'const unsigned char *' 类型的右值初始化 'void *' 类型的参数我查看了stackoverflow.com/questions/24227723/… 以获得这个建议
  • 您正在调整 data 的大小以包含 arBufferSize() 元素,所有元素的值都为 sizeof(float)。
  • 您收到错误是因为您没有注意memcpy 参数的顺序。
  • void *memcpy(void *dest, const void * src, size_t n) 长夜谢谢

标签: c++ vector memcpy alsa


【解决方案1】:

values.resize(arBufferSize(), sizeof(float))

嗯,那不是我在其他评论中写的。您需要将缓冲区大小(以字节为单位)除以每个浮点数的字节数以获得浮点数:arBufferSize() / sizeof(float)

std::memcpy(arBuffer(), &amp;values[0], sizeof(values[0]));

memcpy 由于历史原因,其目的地和来源颠倒了。 const* 错误是因为您要求memcpy 写信给arBuffer。

另外,sizeof(values[0]) 是一个浮点数的大小,以字节为单位。您已经有了arBufferSize(),这正是memcpy 需要的大小。

【讨论】:

  • 我明白它纠正了我的错误我现在在我的 Raspberry Pi 上有一个已编译的程序,但仍然得到像 3.39797e-39 这样的值并且没有得到任何想要的数据我不知道这是否正确我在某处读到可能需要在浮动上定义 min max 才能尝试完成这项工作,但对我来说可能有点困难,非常感谢您的帮助。
  • @JJohn:出于技术原因,您希望 -1.0f 和 +1.0f 之间的值步长为 1/32768,因此为 0.000003。 3e-39 太小而不能成为正确的值。从另一方面解决这个问题可能会有所帮助:确保您的硬件输入完全为零。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-02-15
  • 2019-05-09
相关资源
最近更新 更多