WAVE音乐格式解析(讲解加代码)

2024-03-26 04:59

本文主要是介绍WAVE音乐格式解析(讲解加代码),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

之前一直想用单片机的adc播放音乐,一直有这个念头,网上找了很多的代码都很复杂,就想自己写一个兼容性高的,一眼就能看懂的WAVE解析的代码。以前基本功太差,现在感觉天清了雨晴了,我又觉得我行了!(狗头)

熬了两宿,对着两幅图把之前立的flag给补上了一部分。今天真的是写的太烦了,下边付了一份自己写的代码,代码目前的状态也就是能用吧!不稳定,bug超多,file safe啥的也没做,以后闲的蛋疼的时候在慢慢改。

代码先奉上,讲解日后心情好的时候补上。

 

 

 wave.c

#include <stdio.h>
#include<stdlib.h>
#include <string.h>
#include "wave.h"void printf_c(void * data,unsigned char num)
{unsigned int i = 0;char name[num];memcpy(name,data,num);for(i=0;i<num;i++)printf("%c",name[i]);printf("\n");
}int wave_asf(wave *ral_wave)
{unsigned int read_len = 0;unsigned int read_len_sizeof = 0;unsigned int ChunkID = 0;unsigned int local_offset = 0;unsigned char * extern_data;Wave_RIFF *baseframe;Wave_Base *miniframe;Wave_FMT *wavefmt;WAVE_DATA *wavedata;baseframe = (Wave_RIFF*)calloc(sizeof(Wave_RIFF),sizeof(char));miniframe = (Wave_Base*)calloc(sizeof(Wave_Base),sizeof(char));wavefmt   = (Wave_FMT*) calloc(sizeof(Wave_FMT),sizeof(char));wavedata  = (WAVE_DATA*)calloc(sizeof(WAVE_DATA),sizeof(char));read_len = fread(baseframe, 1, sizeof(Wave_RIFF), ral_wave->fp);if(read_len<sizeof(Wave_RIFF))printf("read file false!\n");local_offset = local_offset + read_len;bit8to32(&ChunkID,baseframe->ChunkID);if(ChunkID != RIFF_id)printf("file no wave!\n");while(TURE){memset(miniframe,0,sizeof(Wave_Base));ChunkID = 0;// 获取chunk_idread_len = fread(miniframe, 1, sizeof(Wave_Base), ral_wave->fp);if(read_len<sizeof(Wave_Base))printf("read file false!\n");local_offset = local_offset + read_len;bit8to32(&ChunkID,miniframe->ChunkID);switch(ChunkID){case fmt_id:read_len = fread(&read_len_sizeof, 1,sizeof(int) , ral_wave->fp);local_offset = local_offset + read_len;read_len = fread(wavefmt, 1,read_len_sizeof , ral_wave->fp);local_offset = local_offset + read_len;ral_wave->AudioFormate  = wavefmt->AudioFormate;ral_wave->BitePerSample = wavefmt->BitePerSample;ral_wave->BlockAilgn    = wavefmt->BlockAilgn;ral_wave->ByteRate      = wavefmt->ByteRate;ral_wave->NumChannels   = wavefmt->NumChannels;ral_wave->SampleRate    = wavefmt->SampleRate;ral_wave->ChunkSize     = read_len_sizeof;break;case data_id:read_len = fread(wavedata, 1,sizeof(WAVE_DATA) , ral_wave->fp);local_offset = local_offset + read_len;ral_wave->Subchunck2Size = wavedata->Subchunck2Size;goto out_while;default:read_len = fread(&read_len_sizeof, 1,sizeof(int) , ral_wave->fp);local_offset = local_offset + read_len;extern_data = (unsigned char*)calloc(read_len_sizeof,sizeof(char));read_len = fread(extern_data, 1,read_len_sizeof , ral_wave->fp);local_offset = local_offset + read_len;// 文件指针后移free(extern_data);break;}}
out_while:free(baseframe);free(miniframe);free(wavefmt);free(wavedata);ral_wave->DataOffset = 	local_offset;printf("ral_wave->DataOffset %x\n",ral_wave->DataOffset);printf("hello world~\n");return 0;
}int channel_select(wave *ral_wave)
{switch(ral_wave->AudioFormate){case 1:return 1;break;case 2:// 不支持其他break;default:// 不支持其他break;}return 0;
}// 声道,采样率分离
void channal_sbisample(wave *ral_wave)
{unsigned int read_len;
//	printf("ral_wave->ByteRate %d\n",ral_wave->ByteRate);
//	printf("ral_wave->BitePerSample %d\n",ral_wave->BitePerSample);
//	printf("ral_wave->BlockAilgn %d\n",ral_wave->BlockAilgn);
//	printf("ral_wave->NumChannels %d\n",ral_wave->NumChannels);
//	printf("ral_wave->SampleRate %d\n",ral_wave->SampleRate);// ByteRate == SampleRate * NumChannels * BitsPerSample/8// BlockAlign == NumChannels * BitsPerSample/8if(ral_wave->NumChannels == 1){switch(ral_wave->BitePerSample){case 8:printf("channel 1,8 bit\n");break;case 16:printf("channel 1,16 bit\n");break;default:printf("chanel 1 error!\n");break;}}else if(ral_wave->NumChannels == 2){switch(ral_wave->BitePerSample){case 8:printf("channel 2,8 bit\n");break;case 16:printf("channel 2,16 bit\n");c2b16 loca_c2b16;read_len = fread(&loca_c2b16, 1,sizeof(c2b16) , ral_wave->fp);printf("%d %d  read_len %d\n",sizeof(c2b16),sizeof(short),read_len);printf("loca_c2b16.L_c2b16 %x,loca_c2b16.R_c2b16 %x\n",loca_c2b16.L_c2b16,loca_c2b16.R_c2b16);ral_wave->DataOffset = ral_wave->DataOffset + read_len;printf("ral_wave->DataOffset %x\n",ral_wave->DataOffset);// 直接写道到DAC?break;default:printf("chanel 2 error!\n");break;}}else{printf("error!\n");}
}int main(void)
{wave *do_wave;do_wave = (wave*)calloc(sizeof(wave),sizeof(char));do_wave->fp = fopen("D:\\wave\\test.wav", "r");wave_asf(do_wave);if(channel_select(do_wave)!=1)return 0;for(int i = 0;i<1000;i++)channal_sbisample(do_wave);fclose(do_wave->fp);free(do_wave);return 0;
}

 wave.h

/** wave.h**  Created on: 2021年7月22日*      Author: uida0349*/#ifndef WAVE_H_
#define WAVE_H_#define TURE  1
#define FALSE 0// 将四个8bit的拼接成32bit的
#define bit8to32(a,b)    {*a = b[3];*a = ((*a)<<8)|b[2];*a = ((*a)<<8)|b[1];*a = ((*a)<<8)|b[0];}/*** 此处用于存储WAV的id信息* */
enum WAV_ID{RIFF_id = 0x46464952,fmt_id  = 0x20746d66,data_id = 0x61746164,
};typedef struct wave_base{//char           ExtentsID[4];unsigned char  ChunkID[4];
}Wave_Base;
typedef struct wave_riff{//char           ExtentsID[4];unsigned char  ChunkID[4];unsigned int   ChunkSize;unsigned char  Format[4];
}Wave_RIFF;
typedef struct wave_fmt{// fmt Bolckunsigned short AudioFormate;unsigned short NumChannels;unsigned int   SampleRate;unsigned int   ByteRate;unsigned short BlockAilgn;unsigned short BitePerSample;
}Wave_FMT;
typedef struct wave_data{// data Blockunsigned int   Subchunck2Size;
}WAVE_DATA;
typedef struct wave_Extents{char           ExtentsID[4];unsigned int   ExtentsSize;unsigned int   ExtentsDataLength;void *         ExtentsData;
}Extents_data;typedef struct wave_demo{FILE           *fp;// RIFF Bolckchar           ChunkID[4];unsigned int   ChunkSize;char           Format[4];// fmt Bolckchar           Subchunk1ID[4];unsigned int   Subchunk1Size;unsigned short AudioFormate;unsigned short NumChannels;unsigned int   SampleRate;unsigned int   ByteRate;unsigned short BlockAilgn;unsigned short BitePerSample;// extents BlockExtents_data   *ExtentsFrames;// data Blockchar           Subchunck2ID[4];unsigned int   Subchunck2Size;// data offsetunsigned int   DataOffset;
}wave;// 存储单声道8bit的数据
typedef unsigned char c1b8;
// 存储单声道16bit的数据
typedef unsigned short c1b16;
// 存储双声道8bit的数据
typedef struct {unsigned char L_c2b8;unsigned char R_c2b8;
}c2b8;// 存储双声道16bit的数据
typedef struct {unsigned short L_c2b16;unsigned short R_c2b16;
}c2b16;
#endif /* WAVE_H_ */

下一步的计划,一直到单片机里边,再加个timer,调度啥的,争取早点实现单片机片上DAC播放WAVE的想法。

这篇关于WAVE音乐格式解析(讲解加代码)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/847356

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

Python使用国内镜像加速pip安装的方法讲解

《Python使用国内镜像加速pip安装的方法讲解》在Python开发中,pip是一个非常重要的工具,用于安装和管理Python的第三方库,然而,在国内使用pip安装依赖时,往往会因为网络问题而导致速... 目录一、pip 工具简介1. 什么是 pip?2. 什么是 -i 参数?二、国内镜像源的选择三、如何

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

使用 sql-research-assistant进行 SQL 数据库研究的实战指南(代码实现演示)

《使用sql-research-assistant进行SQL数据库研究的实战指南(代码实现演示)》本文介绍了sql-research-assistant工具,该工具基于LangChain框架,集... 目录技术背景介绍核心原理解析代码实现演示安装和配置项目集成LangSmith 配置(可选)启动服务应用场景

Python中顺序结构和循环结构示例代码

《Python中顺序结构和循环结构示例代码》:本文主要介绍Python中的条件语句和循环语句,条件语句用于根据条件执行不同的代码块,循环语句用于重复执行一段代码,文章还详细说明了range函数的使... 目录一、条件语句(1)条件语句的定义(2)条件语句的语法(a)单分支 if(b)双分支 if-else(

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

CSS3中使用flex和grid实现等高元素布局的示例代码

《CSS3中使用flex和grid实现等高元素布局的示例代码》:本文主要介绍了使用CSS3中的Flexbox和Grid布局实现等高元素布局的方法,通过简单的两列实现、每行放置3列以及全部代码的展示,展示了这两种布局方式的实现细节和效果,详细内容请阅读本文,希望能对你有所帮助... 过往的实现方法是使用浮动加

JAVA调用Deepseek的api完成基本对话简单代码示例

《JAVA调用Deepseek的api完成基本对话简单代码示例》:本文主要介绍JAVA调用Deepseek的api完成基本对话的相关资料,文中详细讲解了如何获取DeepSeekAPI密钥、添加H... 获取API密钥首先,从DeepSeek平台获取API密钥,用于身份验证。添加HTTP客户端依赖使用Jav

Java实现状态模式的示例代码

《Java实现状态模式的示例代码》状态模式是一种行为型设计模式,允许对象根据其内部状态改变行为,本文主要介绍了Java实现状态模式的示例代码,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来... 目录一、简介1、定义2、状态模式的结构二、Java实现案例1、电灯开关状态案例2、番茄工作法状态案例