This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] LP-EM-CC1354P10:CC1354P10-1和 CC3200 AUDBOOST 从麦克风读取并压缩数据

Guru**** 2382480 points
Other Parts Discussed in Thread: CC3200AUDBOOST, CC1354P10, CC3200
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/audio-group/audio/f/audio-forum/1491227/lp-em-cc1354p10-cc1354p10-1-and-cc3200-audboost-reading-in-from-the-microphone-and-compressing-data

部件号:LP-EM-CC1354P10
Thread 中讨论的其他器件:CC3200AUDBOOSTCC1354P10CC3200

工具/软件:

好!
我正在开发一个基于网状网络的对讲机项目、该项目使用 TI LaunchPad 和 CC3200AUDBOOST 音频 BoosterPack。 我取得了良好的进展、但我目前卡在压缩麦克风输入并通过射频发送。 我非常感谢任何指导或建议!

 目标

  • 从读取音频 单声道麦克风 使用 I2S 在 CC3200AUDBOOST 上输入。
  • 压缩音频数据(当前目标是 ADPCM 或类似的轻量级编解码器)。
  • 使用通过射频(每20ms)发送255字节数据包 CC1354P10 LaunchPad rfechorx/rfechotx 框架。
  • 在接收端、通过解压缩和播放音频 3.5mm 扬声器输出 进行评估。

电流设置

  • 消息流 i2secho.c用作音频 I/O 的基础。
  • 采样速率: 8kHz 、单声道。
  • 射频数据包:
#define PAYLOAD_LENGTH 255
#define PACKET_INTERVAL (uint32_t)(40000 * 0.2f) // 20ms
  • 现在、我将成功发送和解码简单的测试音调(如0xAA/0x55模式)。 然而、我不确定如何以最佳方式构建真实的音频输入→压缩→打包。

 发送模式示例(当前占位符音调)

静态 void handleTransmitMode (uint32_t *curtime){
//更新 LCD 和 LED
updateLCD (LCD_Transmission、0);
GPIO_TOGGLE (CONFIG_GPIO_GLED);
GPIO_WRITE (CONFIG_GPIO_RLED、CONFIG_GPIO_LED_OFF);

//准备数据包标头
txPacket[0]= walkie_ID;//第一个字节是 walkie ID
txPacket[1]=(uint8_t)(seqNumber >> 8);
txPacket[2]=(uint8_t)(seqNumber++);

//用一个简单的模式填充数据包的其余部分
//这将是一种表示音频的模式
for (int i = 3;i < payload_length;i++){
//创建重复图形(在0xAA 和0x55之间交替)
txPacket[i]=(i % 2)? 0xAA:0x55;
}

//发送数据包
*curtime += packet_interval;
RF_cmdPropTx.StartTime =*curtime;
RF_runCmd (rfHandle、(RF_Op*)&RF_cmdPropTx、RF_PriorityNormal、NULL、RF_EventCmdDone);
}

接收模式示例

目前、我模拟将此音调解码为样本、但它是占位符逻辑:

静态 void 处理 ReceivedPacket (void){
//检索数据包
currentDataEntry = RFQueue_getDataEntry ();
packetLength =*(uint8_t *)(&(currentDataEntry->data));
packetDataPointer =(uint8_t *)(&(currentDataEntry->data)+ 1);
memcpy (rxPacket、packetDataPointer、(packetLength + 1));
RFQueue_nextEntry();

//提取发件人 ID
uint8_t SenderID = rxPacket[0];
//如果这是我们自己的数据包或无效的发件人、则跳过处理
if (SenderID == walkie_ID || SenderID == 0){
return;//不处理我们自己的数据包
}

//如果需要、更新 LCD
if (currentLCDState!= LCD_Receiving){
updateLCD (LCD_Receiving、SenderID);
}

//确保音频播放处于活动状态
if (!i2sWriteRunning){
//确保扬声器已取消静音并且已设置音量
AudioCodec 扬声器 Unmute (AudioCodec _TI_3254、output_option);
AudioCodec 扬声器 VolCtrl (AudioCodec _TI_3254、output_option、100);

//启动 I2S 写入过程
I2S_startWrite (i2sHandle);
i2sWriteRunning = true;
}

//获取一个缓冲区以写入样本
I2S_Transaction *事务=(I2S_Transaction *) List_Get (&i2sWriteList);
如果(事务!=空){
//获取指向音频缓冲区的指针
int16_t *audioBuffer =(int16_t *)事务->bufPtr;
int bufferSize =事务-> bufSize / sizeof (int16_t);

//计算我们可以从数据包数据创建的样本数
//跳过前3个字节(发送方 ID 和序列号)
int dataBytes = packetLength - 3;
INT numSamples = 0;

//将原始数据包数据转换为音频样本
//数据包中的每个字节将创建两个音频样本
对于(int i = 0;i < dataBytes && numSamples < bufferSize - 1;I++){
uint8_t dataByte = rxPacket[i + 3];//跳过标头字节

//将前4位转换为样本
int16_t SAMPLE1 =(DataByte 和0x0F)* 2048 - 16384;//扩展至音频范围
audioBuffer[numSamples++]= Sample1;

//将第二个4位转换为样本
int16_t SAMPLE2 =(dataByte >> 4)* 2048 - 16384;//扩展至音频范围
audioBuffer[numSamples++]= Sample2;
}

//如果我们没有得到足够的数据、请静默填写其余部分
while (numSamples < buffersize){
AudioBuffer[numSamples++]= 0;
}

//更新事务大小
事务->bufSize = numSamples * sizeof (int16_t);

//添加以写入播放列表
list_put (&i2sWriteList、(List_Elem *)事务);

//设置 I2S 写入队列标头
I2S_Transaction * head =(I2S_Transaction *) List_head (&i2sWriteList);
如果(head != NULL){
I2S_setWriteQueueHead (i2sHandle、head);
}
}
}

 我的主要问题

  1. 从 I2S 麦克风实时读取、压缩和传输音频样本的最佳方法是什么?
    • ADPCM 这里是一个不错的选择?
    • 我是否应该将504个 PCM 样本压缩为252个 ADPCM 字节以适应每个数据包?
  2. 假设一个射频数据包=一帧压缩音频(例如20ms)是否安全?
  3. 有什么提示可以让压缩/解压缩功能可靠地处理丢弃的数据包?

 感谢任何帮助!

如果有用、我很乐意分享我的 ADPCM 代码或完整的项目设置。 提前感谢任何人通过 Sub-GHz 网状网络或类似项目进行音频流式传输!

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好 Jaiah、

    感谢您的联系。

    1. 这取决于您尝试实现的目标、需要在压缩/解压缩分辨率和延迟之间进行权衡。 例如、mSBC 编解码器等不同的编解码器具有更高的压缩率和更好的音频质量、但其代价是处理延迟高于 ADPCM。
    2. 您可以使用 ADPCM 2:1压缩来适应数据包大小。
    3. 如果您需要提高采样频率、我建议在传输 i2c 音频输入之前进行缓冲->压缩每个软件包->将 X 个数量的数据包拼接在一起(大约是最大数据包大小的大小)。 这当然会带来 RAM 增加的折衷,但如果你保持小的缓冲区大小,那么它应该是太多。 此外、将传输间隔保持在较低水平(开始测试时应该可以使用20ms)。

    使用 MIC 提供的样品尝试您的实际溶液、让我们从此处查看。

    BR、

    David。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在我的代码中、我继续点击播放正弦波测试模式的 else 语句。 这表示在尝试处理 I2S 缓冲器之前我没有正确读取这些缓冲器。 我想问一下最合适的方法是什么、以及这些缓冲区的外观/如何读取它们/如何访问和修改数据以适合我的射频数据包。 (我使用与 i2secho 演示代码相同的方式从单声道麦克风访问数据)

    如对此问题有任何澄清、将不胜感激!  

    if (!micEnabled){
    AudioCodec micUnmute (AudioCodec _TI_3254、AudioCodec _MIC_Mono);
    AudioCodec micVolCtrl (AudioCodec _TI_3254、AudioCodec _MIC_Mono、100);
    I2S_startRead (i2sHandle);
    micEnabled = true;
    }

    //从麦克风缓冲区获取音频数据
    I2S_Transaction *事务=(I2S_Transaction *) List_Get (&T);
    如果(事务!=空){
    //从缓冲区获取音频样本
    int16_t *audioBuffer =(int16_t *)事务->bufPtr;
    int numSamples =事务->bufSize / sizeof (int16_t);

    //计算我们可以发送的样本数
    INT maxSamplesToSend = PAYLOAD_LENGTH - AUDIO_HDR_SIZE;
    int samplesToProcess =(numSamples < maxSamplesToSend )? numSamples:maxSamplesToSend;

    //处理样本并将其复制到数据包中
    for (int i = 0;i <样本 ToProcess;I++){
    //获取16位样本
    int16_t SAMPLE = AudioBuffer[i];

    //映射到无符号8位(0-255)-使用简单的偏移方法
    txPacket[i + AUDIO_HDR_size]=(样本/ 256)+ 128;
    }

    //如果我们的样本数少于有效载荷大小、则用静音填充剩余部分
    对于(int i = sampleToProcess;i < maxSampleToSend;i++){
    txPacket[i + AUDIO_HDR_size]= 128;// 128 =静音
    }

    //将缓冲区返回到已读列表以供重用
    list_put (&i2sReadList、(List_Elem *)事务);

    //更新读取队列标题
    I2S_Transaction * head =(I2S_Transaction *) List_head (&i2sReadList);
    如果(head != NULL){
    I2S_setReadQueueHead (i2sHandle、head);
    }
    }其他{
    //没有可用的音频数据、使用类似于警报器的测试模式
    对于(int i = 0;i < payload_length - AUDIO_HDR_SIZE;i++){
    //简单的测试模式-正弦波近似
    uint8_t position = i % 16;
    静态常量 uint8_t sinePattern[16]={
    128,159,188,216、239、 255,239,216,188、159、 128、97、68、40、17、 0
    };
    txPacket[i + AUDIO_HDR_size]= sinePattern[position];
    }
    }

    //发送数据包
    *curtime += packet_interval;
    RF_cmdPropTx.StartTime =*curtime;
    RF_runCmd (rfHandle、(RF_Op*)&RF_cmdPropTx、RF_PriorityNormal、NULL、RF_EventCmdDone);
    }

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    你好 Jaiah、

    您能否确认仅使用 SDK 中的 I2S 示例读取了音频样本? 此外、您可以使用逻辑分析仪并对来自麦克风的信号进行解码、以确保实际有音频流式传输。

    BR、

    David。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是的、只需使用 SDK 中的示例、我可以确认可以读取/回显音频样本。 问题似乎是在对通过射频发送的音频/打包进行任何类型的处理时。 我想我想尝试将 SDK 中的 i2secho.c 示例与 rfechotx 和 Rx 示例(也来自 SDK)相结合、以实现双向音频传输。 如果您对麦克风->传输流水线有任何帮助、我们将不胜感激。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    作为参考、我使用的 PHY 类型与 RFecho 示例中使用的 PHY 类型相同、即:

    50kbps、25kHz 偏差、2-GFSK、100kHz RX 带宽

    我也会使用以下定义  

    #define walkie_ID 1 //更改每个设备
    #define PAYLOAD_LENGTH 255 //最大数据包大小
    #define PACKET_INTERVAL (uint32_t)(40000*0.375f)//数据包之间的37.5ms
    #define RX_TIMEOUT (uint32_t)(400000*0.5f)// RX 超时
    #define NUM_DATA_ENTRY 4 //从2增加到4
    #define NUM_PASSIDED_BYTES 2 //将其保持为2
    #define AUDIO_HDR_SIZE 3 // 1字节 ID、2字节序列

    /*音频设置*/
    #define SAMPLE_RATE 8000 // 8kHz 采样
    #define NUMBUFS 10.
    第384章我是你的女人

    现在、我不是超级担心延迟/清晰度的权衡、而是至少能够将录制的音频从单声道麦克风发送和接收到相反的 LaunchPad HP 扬声器输出。 我能够传输由一个对讲机定义并传输到另一个对讲机的蜂鸣声、波形和警报器等音频模式、但我在集成 CC3200 AUDBOOST 的麦克风以发送从那里录制的音频时遇到了问题。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    嗨、Jaiah、

    如有必要、请确认并更正:
    -您可以使用 Packet Rx 数据包 TX 示例发送音频?
    -您可以使用 I2S 示例读取麦克风?

    您是否正在寻找一种将您的录音转换为 PropRF 消息的方法?

    此致、
    Theo