精华内容
下载资源
问答
  • 使用WindowsAPI获取录音音频的方法
    2021-05-21 03:51:47

    本文实例介绍了使用winmm.h进行音频流的获取的方法,具体步骤如下:

    一、首先需要包含以下引用对象

    #include

    #include "mmsystem.h"

    #pragma comment(lib, "winmm.lib")

    二、音频的获取需要调用7个函数

    1. waveInGetNumDevs:返回系统中就绪的波形声音输入设备的数量

    UINT waveInGetNumDevs(VOID);

    2. waveInGetDevCaps:检查指定波形输入设备的特性

    MMRESULT waveInGetDevCaps(

    UINT_PTR uDeviceID,

    LPWAVEINCAPS pwic,

    UINT cbwic

    );

    //uDeviceID 音频输入设备标识,也可以为一个打开的音频输入设备的句柄.

    // 个人认为如果上一步获得了多个设备,可以用索引标识每一个设备.

    //

    //pwic 对WAVEINCAPS结构体的一个指针,包含设备的音频特性.

    //

    //cbwic WAVEINCAPS结构体的大小,使用sizeof即可.

    //

    //MMRESULT 函数执行的结果

    // MMSYSERR_NOERROR 表示执行成功

    // MMSYSERR_BADDEVICEID 索引越界

    // MMSYSERR_NODRIVER 没有就绪的设备

    // MMSYSERR_NOMEM 不能分配或者锁定内存

    介绍WAVEINCAPS结构体的含义:

    typedef struct {

    WORD wMid; //音频设备制造商定义的驱动程序标识

    WORD wPid; //音频输入设备的产品标识

    MMVERSION vDriverVersion; //驱动程序版本号

    TCHAR szPname[MAXPNAMELEN];//制造商名称

    DWORD dwFormats; //支持的格式,参见MSDN

    WORD wChannels; //支持的声道数

    WORD wReserved1; //保留参数

    } WAVEINCAPS;

    3. waveInOpen:打开指定的音频输入设备,进行录音

    MMRESULT waveInOpen(

    LPHWAVEIN phwi, //接收打开的音频输入设备标识的HWAVEIN结构的指针

    UINT_PTR uDeviceID, //指定一个需要打开的设备标识.可以使用WAVE_MAPPER选择一个按指定录音格式录音的设备

    LPWAVEFORMATEX pwfx, //一个所需的格式进行录音的WAVEFORMATEX结构的指针

    DWORD_PTR dwCallback, //指向一个回调函数、事件句柄、窗口句柄、线程标识,对录音事件进行处理.

    DWORD_PTR dwCallbackInstance, //传给回调机制的参数

    DWORD fdwOpen //打开设备的方法标识,指定回调的类型.参见CSDN

    );

    介绍WAVEFORMATEX结构体的含义:

    typedef struct {

    WORD wFormatTag; //波形声音的格式,单声道双声道使用WAVE_FORMAT_PCM.当包含在WAVEFORMATEXTENSIBLE结构中时,使用WAVE_FORMAT_EXTENSIBLE.

    WORD nChannels; //声道数量

    DWORD nSamplesPerSec; //采样率.wFormatTag为WAVE_FORMAT_PCM时,有8.0kHz,11.025kHz,22.05kHz,和44.1kHz.

    DWORD nAvgBytesPerSec; //每秒的采样字节数.通过nSamplesPerSec * nChannels * wBitsPerSample / 8计算

    WORD nBlockAlign; //每次采样的字节数.通过nChannels * wBitsPerSample / 8计算

    WORD wBitsPerSample; //采样位数.wFormatTag为WAVE_FORMAT_PCM时,为8或者16

    WORD cbSize; //wFormatTag为WAVE_FORMAT_PCM时,忽略此参数

    } WAVEFORMATEX;

    介绍dwCallback回调函数格式:

    void CALLBACK waveInProc(

    HWAVEIN hwi, //回调此函数的设备句柄

    UINT uMsg, //波形声音输入信息,标识关闭(WIM_CLOSE)、缓冲区满(WIM_DATA)、打开(WIM_OPEN).

    DWORD_PTR dwInstance, //用户在waveInOpen指定的数据

    DWORD_PTR dwParam1, //(LPWAVEHDR)dwParam1,用户指定的缓冲区

    DWORD_PTR dwParam2

    );

    4. waveInPrepareHeader:为音频输入设备准备一个缓冲区

    MMRESULT waveInPrepareHeader(

    HWAVEIN hwi, //音频输入设备句柄

    LPWAVEHDR pwh,//指向WAVEHDR结构的指针,标识准备的缓冲区

    UINT cbwh //WAVEHDR结构的大小,使用sizeof即可

    );

    介绍WAVEHDR结构:

    typedef struct wavehdr_tag {

    LPSTR lpData; //指向波形格式的缓冲区

    DWORD dwBufferLength; //缓冲区的大小

    DWORD dwBytesRecorded; //当前存储了多少数据

    DWORD_PTR dwUser; //用户数据

    DWORD dwFlags; //为缓冲区提供的信息,在waveInPrepareHeader函数中使用WHDR_PREPARED

    DWORD dwLoops; //输出时使用,标识播放次数

    struct wavehdr_tag * lpNext;//reserved

    DWORD_PTR reserved; //reserved

    } WAVEHDR, *LPWAVEHDR;

    5. waveInAddBuffer:将缓冲区发送给设备,若缓冲区填满,则不起作用。(参数同上)

    MMRESULT waveInAddBuffer(

    HWAVEIN hwi,

    LPWAVEHDR pwh,

    UINT cbwh

    );

    6. waveInStart:开始进行录制

    MMRESULT waveInStart(

    HWAVEIN hwi //设备句柄

    );

    7. waveInClose:关闭设备

    MRESULT waveInClose(

    HWAVEIN hwi //设备句柄

    );

    三、完整实例代码如下:

    //Run.c文件

    #include

    #include

    #include "mmsystem.h"

    #pragma comment(lib, "winmm.lib")

    void PlayMusi();

    void WaveInitFormat(LPWAVEFORMATEX m_WaveFormat, WORD nCh,DWORD nSampleRate,WORD BitsPerSample);

    DWORD CALLBACK MicCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);

    void RecordWave();

    void main()

    {

    //PlayMusi();

    RecordWave();

    while(1);

    }

    void RecordWave()

    {

    int count = waveInGetNumDevs();//1

    printf("\n音频输入数量:%d\n",count);

    WAVEINCAPS waveIncaps;

    MMRESULT mmResult = waveInGetDevCaps(0,&waveIncaps,sizeof(WAVEINCAPS));//2

    printf("\n音频输入设备:%s\n",waveIncaps.szPname);

    if(MMSYSERR_NOERROR==mmResult)

    {

    HWAVEIN phwi;

    WAVEFORMATEX pwfx;

    WaveInitFormat(&pwfx,1,8000,8);

    printf("\n请求打开音频输入设备");

    printf("\n采样参数:单声道 8kHz 8bit\n");

    mmResult=waveInOpen(&phwi,WAVE_MAPPER,&pwfx,(DWORD)(MicCallback),NULL,CALLBACK_FUNCTION);//3

    if(MMSYSERR_NOERROR==mmResult)

    {

    WAVEHDR pwh1;

    char buffer1[10240];

    pwh1.lpData=buffer1;

    pwh1.dwBufferLength=10240;

    pwh1.dwUser=1;

    pwh1.dwFlags=0;

    mmResult=waveInPrepareHeader(phwi,&pwh1,sizeof(WAVEHDR));//4

    printf("\n准备缓冲区1");

    WAVEHDR pwh2;

    char buffer2[10240];

    pwh2.lpData=buffer2;

    pwh2.dwBufferLength=10240;

    pwh2.dwUser=2;

    pwh2.dwFlags=0;

    mmResult=waveInPrepareHeader(phwi,&pwh2,sizeof(WAVEHDR));//4

    printf("\n准备缓冲区2\n");

    if(MMSYSERR_NOERROR==mmResult)

    {

    mmResult=waveInAddBuffer(phwi,&pwh1,sizeof(WAVEHDR));//5

    printf("\n将缓冲区1加入音频输入设备");

    mmResult=waveInAddBuffer(phwi,&pwh2,sizeof(WAVEHDR));//5

    printf("\n将缓冲区2加入音频输入设备\n");

    if(MMSYSERR_NOERROR==mmResult)

    {

    mmResult=waveInStart(phwi);//6

    printf("\n请求开始录音\n");

    }

    }

    }

    }

    }

    DWORD CALLBACK MicCallback(HWAVEIN hwavein, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)

    {

    switch(uMsg)

    {

    case WIM_OPEN:

    printf("\n设备已经打开...\n");

    break;

    case WIM_DATA:

    printf("\n缓冲区%d存满...\n",((LPWAVEHDR)dwParam1)->dwUser);

    waveInAddBuffer (hwavein, (LPWAVEHDR)dwParam1, sizeof (WAVEHDR)) ;

    break;

    case WIM_CLOSE:

    printf("\n设备已经关闭...\n");

    break;

    default:

    break;

    }

    return 0;

    }

    void WaveInitFormat(LPWAVEFORMATEX m_WaveFormat, WORD nCh,DWORD nSampleRate,WORD BitsPerSample)

    {

    m_WaveFormat->wFormatTag = WAVE_FORMAT_PCM;

    m_WaveFormat->nChannels = nCh;

    m_WaveFormat->nSamplesPerSec = nSampleRate;

    m_WaveFormat->nAvgBytesPerSec = nSampleRate * nCh * BitsPerSample/8;

    m_WaveFormat->nBlockAlign = m_WaveFormat->nChannels * BitsPerSample/8;

    m_WaveFormat->wBitsPerSample = BitsPerSample;

    m_WaveFormat->cbSize = 0;

    }

    void PlayMusi()

    {

    int error = mciSendString("open C:\\Users\\Angel\\Desktop\\有多少爱可以重来.mp3 alias myDivece", NULL, 0, NULL);

    if (error == 0)

    {

    mciSendString("play myDivece", NULL, 0, NULL); //播放

    }

    }

    更多相关内容
  • 声音 录制 -》设置 录影录制 声音处理 在可以记录之前,我们需要范文您的文档文件夹 需求背景 项目开发中有时需要加上一些音效,比如专场、登录成功、回答失败、以及各种按钮音效等 这时候很容易会去网上找...

    目录

    Windows 录音机录制电脑声音

    在可以记录之前,我们需要范文您的文档文件夹

    双网卡设置内外网共用


    Windows 录音机录制电脑声音

    需求背景

    1、项目开发中有时需要加上一些音效,比如专场、登录成功、回答失败、以及各种按钮音效等

    2、这时候很容易会去网上找素材,但是如果需要下载的内容需要付费或者其它原因导致无法下载时,可以使用Windows自带录影机录下来即可解决

    3、如下所示就是需要VIP才能下载的情况

     声音 录制 -》设置

    1、找到“录制”选项,如果是使用话筒自己唱歌或者讲话的声音,则应该往电脑上插上话筒设备之后,“麦克风选项”就会激活

    2、录制电脑上网页上的声音时,只需要将下面的“立体声混音”启用,并设置为默认设备即可

     录影机录制

     1、有的系统如果没有搜索框,则可以在 Windows 上右键-> 找到搜索,再输入 录音机 搜索即可:

    声音处理

     之后点击右下角的大按钮即可转换成功

    在可以记录之前,我们需要范文您的文档文件夹

     如果打开之后是这个样子,则需要修改一下系统默认的文档保存路径。

    点击Windows键->设置

     之后再打开录音机便正常了。

    双网卡设置内外网共用

    1、有些系统或者网站只允许内网访问,而自己又需要访问外网,默认情况下以太网与 WLAN无线网只能关掉一个,另一个开的才能正常访问。

    2、这显然不是我们想要的,特别麻烦,且工作效率也不高,现在的笔记本都有双网卡,通过简单的设置,即可实现内外网同时连接,如有线连接的是内网,无线连接的是外网。

    3、通常内网IP地址都是固定分配的,使用的固定IP,而外网IP可能是开的 WIFI 之类的,动态获取的IP,先保证两个网络分别都能正常访问,然后进行下面的设置,让内外网可以同时访问。

    4、比如有内网IP设置如下,每个人的实际IP地址略有不同,不过基本类似:

     5、最重要的一步:进入 cmd 命令行,输入并执行如下命令,添加路由信息:

    route add -p 10.104.0.0 mask 255.255.0.0 10.104.65.254
    --10.104.0.0 是IP的后两节用0替代,255.255.0.0. 是子网掩码的两节用0替代,10.104.65.254 是网关。
    --按着上面的IP对应的命令规律,根据实际地址做下调整即可。

    6、执行之后内外网就可以同时访问了。

    route  操作本地网络路由表
    route print打印所有路由信息
    route print 10.*打印10.开头的路由信息
    route add -p 10.104.0.0 mask 255.255.0.0 10.104.65.254添加路由信息
    route delete -p 10.104.0.0 mask 255.255.0.0 10.104.65.254删除路由信息

    展开全文
  • 现在网上用python编写的录音机小软件很多,几乎都不支持内录。 这个小程序的主要功能特点是 1 , 录制电脑上正在播放的声音,即从声卡录制,而不是从麦克风录制,这样就可以将电脑上正在播放的音乐保存下来 2, ...

    现在网上用python编写的录音机小软件很多,几乎都不支持内录。

    这个小程序的主要功能特点是

    1 , 录制电脑上正在播放的声音,即从声卡录制,而不是从麦克风录制,这样就可以将电脑上正在播放的音乐保存下来

    2, 不预先指定录制时间,而是根据用户指令开始录音或停止录音,因此要使用多线程技术来实现

    实际使用效果

    在这里插入图片描述

    技术关键点

    调用pyaudio模块进行录音,为了实现内录功能,有一个关键点是要找出支持内录的音频输入设备。

    为此专门定义了一个方法,找出支持内录的设备的序号

    #获取内录设备序号,在windows操作系统上测试通过,hostAPI = 0 表明是MME设备
        def findInternalRecordingDevice(self,p):
            #要找查的设备名称中的关键字
            target = '立体声混音'
            #逐一查找声音设备  
            for i in range(p.get_device_count()):
                devInfo = p.get_device_info_by_index(i)   
                if devInfo['name'].find(target)>=0 and devInfo['hostApi'] == 0 :      
                    #print('已找到内录设备,序号是 ',i)
                    return i
            print('无法找到内录设备!')
            return -1
    

    此外在创建音频输入流时,要通过参数 input_device_index 指定内录设备
    相关代码如下:

    #在打开输入流时指定输入设备
            stream = p.open(input_device_index=dev_idx,
                            format=self.FORMAT,
                            channels=self.CHANNELS,
                            rate=self.RATE,
                            input=True,
                            frames_per_buffer=self.CHUNK)
    

    完整的python代码

    pyRecorder.py

    # _*_ coding: utf-8 _*_
    
    # 录音机,用于录制声卡播放的声音(内录)
    
    import os
    import pyaudio
    import threading
    import wave
    import time
    from datetime import datetime
    
    #录音类 
    class Recorder():
        def __init__(self, chunk=1024, channels=2, rate=44100):
            self.CHUNK = chunk
            self.FORMAT = pyaudio.paInt16
            self.CHANNELS = channels
            self.RATE = rate
            self._running = True
            self._frames = []
    
        #获取内录设备序号,在windows操作系统上测试通过,hostAPI = 0 表明是MME设备
        def findInternalRecordingDevice(self,p):
            #要找查的设备名称中的关键字
            target = '立体声混音'
            #逐一查找声音设备  
            for i in range(p.get_device_count()):
                devInfo = p.get_device_info_by_index(i)   
                if devInfo['name'].find(target)>=0 and devInfo['hostApi'] == 0 :      
                    #print('已找到内录设备,序号是 ',i)
                    return i
            print('无法找到内录设备!')
            return -1
    
        #开始录音,开启一个新线程进行录音操作
        def start(self):
            threading._start_new_thread(self.__record, ())
    
        #执行录音的线程函数
        def __record(self):
            self._running = True
            self._frames = []
    
            p = pyaudio.PyAudio()
            #查找内录设备
            dev_idx = self.findInternalRecordingDevice(p)
            if dev_idx < 0 :            
                return
            #在打开输入流时指定输入设备
            stream = p.open(input_device_index=dev_idx,
                            format=self.FORMAT,
                            channels=self.CHANNELS,
                            rate=self.RATE,
                            input=True,
                            frames_per_buffer=self.CHUNK)
            #循环读取输入流
            while(self._running):
                data = stream.read(self.CHUNK)
                self._frames.append(data)
    
            #停止读取输入流  
            stream.stop_stream()
            #关闭输入流
            stream.close()
            #结束pyaudio
            p.terminate()
            return
     
        #停止录音
        def stop(self):
            self._running = False
     
        #保存到文件
        def save(self, fileName):   
            #创建pyAudio对象
            p = pyaudio.PyAudio()
            #打开用于保存数据的文件
            wf = wave.open(fileName, 'wb')
            #设置音频参数
            wf.setnchannels(self.CHANNELS)
            wf.setsampwidth(p.get_sample_size(self.FORMAT))
            wf.setframerate(self.RATE)
            #写入数据
            wf.writeframes(b''.join(self._frames))
            #关闭文件
            wf.close()
            #结束pyaudio
            p.terminate()
    
            
     
    if __name__ == "__main__":
    
        #检测当前目录下是否有record子目录
        if not os.path.exists('record'):
            os.makedirs('record')
    
        print("\npython 录音机 ....\n")
        print("提示:按 r 键并回车 开始录音\n")    
        
        i = input('请输入操作码:')
        if i == 'r':           
            rec = Recorder()
            begin = time.time()
    
            print("\n开始录音,按 s 键并回车 停止录音,自动保存到 record 子目录\n")
            rec.start()
    
            running = True
            while running:
                i = input("请输入操作码:")
                if i == 's':
                    running =False
                    print("录音已停止")
                    rec.stop()               
                    t = time.time() - begin
                    print('录音时间为%ds'%t)
                    #以当前时间为关键字保存wav文件
                    rec.save("record/rec_"+datetime.now().strftime("%Y-%m-%d_%H-%M-%S")+".wav")
    

    将以上内容保存在本地,在安装好python3 及 pyaudio 模块的前提下,执行 python pyRecorder.py 就可以开始录音了。

    以上代码在 win10 下测试通过,linux或其它操作系统未测试,可能要做一些小的改动才能正常运行。

    补充说明:

    在录制网上音乐时,如果想做到:点击网页上的播放按钮时自动开始录音,可参看python录音机的改进版

    展开全文
  • 基于STM32的录音机设计(STM32F103+VS1053B)

    千次阅读 多人点赞 2021-06-09 19:06:35
    录音文件存储设备: SD卡,采用SPI协议驱动 显示屏: SPI接口的0.96寸OLED 代码风格: 采用寄存器编程,代码简洁、执行效率高、注释到位、移植方便。 项目完整源代码下载地址(下载即可编译运行测试):...

    一、环境介绍

    MCU:  STM32F103C8T6

    开发软件:  Keil5

    音频模块:  VS1053B

    录音文件存储设备:  SD卡,采用SPI协议驱动

    显示屏:  SPI接口的0.96寸OLED

    代码风格:  采用寄存器编程,代码简洁、执行效率高、注释到位、移植方便。

    项目完整源代码下载地址(下载即可编译运行测试):  https://download.csdn.net/download/xiaolong1126626497/19520781

    二、功能介绍

    这是基于STM32F103C8T6设计的录音机功能,支持的功能如下:

    1.  按下按键1启动自动录音,默认为5秒录音一次,录音完毕自动保存在SD指定目录下。文件名称采用当前时间命名;音频文件格式采用WAV格式存储。

    2.  按下按键2启动手动录音,按键按下之后开始录音,再次按下结束录音,录音完毕之后,文件也是一样的保存在SD卡里。

    3. SD卡文件系统采用FAT32格式,STM32移植了FATFS开源文件系统对SD卡进行读写操作。

    4. OLED显示屏用于显示当前录音机的状态:  空闲、录音、回放等状态。

    5. 按下按键3,启动自动回放功能。自动扫描目录,按顺序播放录音文件。

    技术介绍:

    1.  SD卡采用SPI协议驱动,因为对速度没有很高要求,SPI协议已经完全满足;如果要更高的速度,可以采用SDIO协议。

    2.  音频模块采用VS1053B,这个芯片支持IIS和SPI协议。我这里采用的是SPI协议驱动,SPI比较简单,代码也好移植,可以很方便的移植到其他单片机上运行。VS1053功能比较强大,支持录音、解码播放。

    3.  文件系统采用的是FATFS文件系统,这个文件系统功能比较完善,使用免费,支持FAT16、FAT32等格式。底层也比较好适配移植。当前,除了FATFS以外,还有很多其他的嵌入式文件系统可以选择,移植都大同小异。

    4. OLED显示屏是0.96寸的。采用SPI协议驱动,主要是显示一些状态,SPI刷屏比较快,这款OLED也支持IIC接口。

    5. VS1053模块上没有喇叭设备,可以适应耳机或者音箱听回放的录音。

     

    硬件与STM32的接线说明:

    OLED显示屏:
    D0----SCK-----PB14
    D1----MOSI----PB13
    RES—复位(低电平有效)—PB12
    DC---数据和命令控制管脚—PB1
    CS---片选引脚-----PA7

    VS1053:
    #define VS1053_DREQ     PAin(11)      //DREQ  数据请求
    #define VS1053_RESET    PAout(12)   //RST   硬件复位--低电平有效
    #define VS1053_XCS      PAout(13)      //XCS   片选--低电平有效
    #define VS1053_XDCS     PAout(14)      //XDCS  用于数据片选、字节同步
    #define VS1053_SCLK     PAout(15)
    #define VS1053_OUTPUT   PBout(3)
    #define VS1053_INPUT    PBin(4)

    SD卡接口:
    5V----5V
    GND---GND
    SPI1_MOSI---PA7
    SPI1_MISO---PA6
    SPI1_CS---PA4
    SPI1_SCK--PA5
     

    三、使用的相关硬件

    STM32F103C8T6系统板: 

    OLED显示屏: 

    VS1053: 

    SD卡卡槽: 

     

     

    四、操作说明

    开发板有一个复位键和一个K0按键。

    程序下载:

     

    程序支持三种模式:

    因为开发板只有一个K0按键,所以三种模式都是通过一个按键进行切换的。

    一个按键是通过按下的计数方式进行切换的,切换的顺序是自动录音模式、手动录音模式、回放模式。

    (1)自动录音模式:按下一次按键后,进入自动录音模式,自动录音模式下,录音5秒自动退出,退出后自动启动播放状态,就是播放刚才5秒录制的音频,播放过程中按下按键可以退出播放状态。

    (2)手动录音模式:第二次按下K0按键后,进入手动录音模式,手动录音模式下,可以长时间录音,如果要结束录音,按下K0按键即可结束;结束后自动启动播放状态,就是播放刚才录制的音频,播放过程中按下按键可以退出播放状态。

    (3)回放模式:第三次按下K0按键后,进入回放模式,自动扫描wav目录,进行顺序播放音频文件。

        播放过程中可以按下K0按键退出回放模式。
    每次录音后的文件是存放在SD卡根目录下的wav目录下。
    每个状态都会在OLED显示屏上显示
    也会同时通过串口打印到串口调试助手终端。

    五、SD卡上存放的文件

    SD卡上有两个目录:font目录和wav目录。
    font目录下存放16x16字库文件。
    wav目录下存放录音的音频文件。
     

    六、部分源码

    6.1 VS1053.c   这是VS1053的驱动代码

    #include "vs1053b.h"	
    
    /*
    函数功能:移植接口--SPI时序读写一个字节
    函数参数:data:要写入的数据
    返 回 值:读到的数据
    */
    u8 VS1053_SPI_ReadWriteByte(u8 tx_data)
    {			  	 
    	u8 rx_data=0;				 
      u8 i;
      for(i=0;i<8;i++)
    	{
    		VS1053_SCLK=0;  
    		if(tx_data&0x80){VS1053_OUTPUT=1;}
    		else {VS1053_OUTPUT=0;}
    		tx_data<<=1;	
    		VS1053_SCLK=1;
    		rx_data<<=1;
    		if(VS1053_INPUT)rx_data|=0x01;
    	}
    	return rx_data; 
    }
    
    
    /*
    函数功能:初始化VS1053的IO口	 
    */
    void VS1053_Init(void)
    {
    	 RCC->APB2ENR|=1<<0;
    	 AFIO->MAPR&=~(0x7<<24);  //释放PA13/14/15
    	 AFIO->MAPR|=0x4<<24;
    	
    	 RCC->APB2ENR|=1<<2;
    	 RCC->APB2ENR|=1<<3;
    	 
    	 GPIOA->CRH&=0x00000FFF;
    	 GPIOA->CRH|=0x33338000;
    	  
    	 GPIOB->CRL&=0xFFF00FFF;
    	 GPIOB->CRL|=0x00083000;
    	
    	 VS1053_SCLK=1;
    	 VS1053_XCS=1;
         VS1053_RESET=1;
    
    }	
    
    
    /*
    函数功能:软复位VS10XX
    */
    void VS1053_SoftReset(void)
    {	 
    	u8 retry=0;  				   
    	while(VS1053_DREQ==0); 							//等待软件复位结束	   
    	VS1053_SPI_ReadWriteByte(0Xff);			//启动传输
    	retry=0;
    	while(VS1053_ReadReg(SPI_MODE)!=0x0800)	// 软件复位,新模式  
    	{
    		VS1053_WriteCmd(SPI_MODE,0x0804);		// 软件复位,新模式	    
    		DelayMs(2);//等待至少1.35ms 
    		if(retry++>100)break; 	  
    	}	
    	while(VS1053_DREQ==0);//等待软件复位结束	 
    	retry=0;
    	while(VS1053_ReadReg(SPI_CLOCKF)!=0X9800)//设置VS10XX的时钟,3倍频 ,1.5xADD 
    	{
    		VS1053_WriteCmd(SPI_CLOCKF,0X9800);	//设置VS10XX的时钟,3倍频 ,1.5xADD
    		if(retry++>100)break; 	    
    	}	 
    	DelayMs(20);
    } 
    
    
    /*
    函数 功 能:硬复位MP3
    函数返回值:1:复位失败;0:复位成功	
    */
    u8 VS1053_Reset(void)
    {
    	u8 retry=0;
    	VS1053_RESET=0;
    	DelayMs(20);
    	VS1053_XDCS=1;//取消数据传输
    	VS1053_XCS=1; //取消数据传输
    	VS1053_RESET=1;	   
    	while(VS1053_DREQ==0&&retry<200)//等待DREQ为高
    	{
    		retry++;
    		DelayUs(50);
    	}
    	DelayMs(20);	
    	if(retry>=200)return 1;
    	else return 0;	    		 
    }
    
    
    /*
    函数功能:向VS10XX写命令
    函数参数:
    				address:命令地址
    				data   :命令数据
    */
    void VS1053_WriteCmd(u8 address,u16 data)
    {  
    	while(VS1053_DREQ==0);	//等待空闲		   	   
    	VS1053_XDCS=1; 	 
    	VS1053_XCS=0; 	 
    	VS1053_SPI_ReadWriteByte(VS_WRITE_COMMAND);//发送VS10XX的写命令
    	VS1053_SPI_ReadWriteByte(address); 	//地址
    	VS1053_SPI_ReadWriteByte(data>>8); 	//发送高八位
    	VS1053_SPI_ReadWriteByte(data);	 		//第八位
    	VS1053_XCS=1;            
    } 
    
    
    /*
    函数参数:向VS1053写数据
    函数参数:data:要写入的数据
    */
    void VS1053_WriteData(u8 data)
    {
    	VS1053_XDCS=0;   
    	VS1053_SPI_ReadWriteByte(data);
    	VS1053_XDCS=1;      
    }
    
    
    /*
    函数功能:读VS1053的寄存器 
    函数参数:address:寄存器地址
    返回值:读到的值
    */
    u16 VS1053_ReadReg(u8 address)
    { 
    	u16 temp=0;   	
      while(VS1053_DREQ==0);//非等待空闲状态   	
    	VS1053_XDCS=1;       
    	VS1053_XCS=0;        
    	VS1053_SPI_ReadWriteByte(VS_READ_COMMAND);//发送VS10XX的读命令
    	VS1053_SPI_ReadWriteByte(address);       	//地址
    	temp=VS1053_SPI_ReadWriteByte(0xff); 		  //读取高字节
    	temp=temp<<8;
    	temp+=VS1053_SPI_ReadWriteByte(0xff); 		//读取低字节
    	VS1053_XCS=1;      
       return temp; 
    }  
    
    
    /*
    函数功能:读取VS1053的RAM
    函数参数:addr:RAM地址
    返 回 值:读到的值
    */
    u16 VS1053_ReadRAM(u16 addr) 
    { 
    	u16 res;			   	  
     	VS1053_WriteCmd(SPI_WRAMADDR, addr); 
    	res=VS1053_ReadReg(SPI_WRAM);  
     	return res;
    } 
    
    
    /*
    函数功能:写VS1053的RAM
    函数参数:
    				addr:RAM地址
    				val:要写入的值 
    */
    void VS1053_WriteRAM(u16 addr,u16 val) 
    {  		   	  
     	VS1053_WriteCmd(SPI_WRAMADDR,addr);	//写RAM地址 
    	while(VS1053_DREQ==0); 							//等待空闲	   
    	VS1053_WriteCmd(SPI_WRAM,val); 			//写RAM值 
    } 
    
    
    /*
    函数参数:发送一次音频数据,固定为32字节
    返 回 值:0,发送成功
    				  1,本次数据未成功发送   
    */ 
    u8 VS1053_SendMusicData(u8* buf)
    {
    	u8 n;
    	if(VS1053_DREQ!=0)  //送数据给VS10XX
    	{			   	 
    		VS1053_XDCS=0;  
        for(n=0;n<32;n++)
    		{
    			VS1053_SPI_ReadWriteByte(buf[n]);	 			
    		}
    		VS1053_XDCS=1;     				   
    	}else return 1;
    	return 0;//成功发送了
    }
    
    
    /*
    函数参数:发送一次音频数据,固定为32字节
    返 回 值:0,发送成功
    				  1,本次数据未成功发送   
    */ 
    void VS1053_SendMusicByte(u8 data)
    {
    	u8 n;
    	while(VS1053_DREQ==0){}	   	 
    	VS1053_XDCS=0;  
    	VS1053_SPI_ReadWriteByte(data);	 			
    	VS1053_XDCS=1;     				   
    }
    
    
    /*
    函数功能:设定VS1053播放的音量
    函数参数:volx:音量大小(0~254)
    */
    void VS1053_SetVol(u8 volx)
    {
        u16 volt=0; 			      //暂存音量值
        volt=254-volx;			    //取反一下,得到最大值,表示最大的表示 
    	  volt<<=8;
        volt+=254-volx;					//得到音量设置后大小
        VS1053_WriteCmd(SPI_VOL,volt);//设音量 
    }
    
    
    /*--------------------------------------录音功能-----------------------------------------------------*/
    
    
    /*
    函数功能:vs10xx装载patch
    函数参数:
    				patch:patch首地址
    				len  :patch长度
    */
    void VS1053_LoadPatch(u16 *patch,u16 len) 
    {
    	u16 i; 
    	u16 addr, n, val; 	  			   
    	for(i=0;i<len;) 
    	{ 
    		addr = patch[i++]; 
    		n    = patch[i++]; 
    		if(n & 0x8000U) //RLE run, replicate n samples 
    		{ 
    			n  &= 0x7FFF; 
    			val = patch[i++]; 
    			while(n--)VS1053_WriteCmd(addr, val);  
    		}
    		else //copy run, copy n sample 
    		{ 
    			while(n--) 
    			{ 
    				val = patch[i++]; 
    				VS1053_WriteCmd(addr, val); 
    			} 
    		} 
    	} 	
    }
    
    
    /*
    函数参数:初始化WAV头
    */
    void VS1053_RecoderWavInit(__WaveHeader* wavhead) //初始化WAV头			   
    {
    	wavhead->riff.ChunkID=0X46464952;	//"RIFF"
    	wavhead->riff.ChunkSize=0;				//还未确定,最后需要计算
    	wavhead->riff.Format=0X45564157; 	//"WAVE"
    	wavhead->fmt.ChunkID=0X20746D66; 	//"fmt "
    	wavhead->fmt.ChunkSize=16; 				//大小为16个字节
    	wavhead->fmt.AudioFormat=0X01; 		//0X01,表示PCM;0X01,表示IMA ADPCM
     	wavhead->fmt.NumOfChannels=1;			//单声道
     	wavhead->fmt.SampleRate=8000;			//8Khz采样率 采样速率
     	wavhead->fmt.ByteRate=wavhead->fmt.SampleRate*2;//16位,即2个字节
     	wavhead->fmt.BlockAlign=2;				//块大小,2个字节为一个块
     	wavhead->fmt.BitsPerSample=16;		//16位PCM
      wavhead->data.ChunkID=0X61746164;	//"data"
     	wavhead->data.ChunkSize=0;				//数据大小,还需要计算  
    }
    
    //VS1053的WAV录音有bug,这个plugin可以修正这个问题 							    
    const u16 VS1053_WavPlugin[40]=/* Compressed plugin */ 
    { 
    		0x0007, 0x0001, 0x8010, 0x0006, 0x001c, 0x3e12, 0xb817, 0x3e14, /* 0 */ 
    		0xf812, 0x3e01, 0xb811, 0x0007, 0x9717, 0x0020, 0xffd2, 0x0030, /* 8 */ 
    		0x11d1, 0x3111, 0x8024, 0x3704, 0xc024, 0x3b81, 0x8024, 0x3101, /* 10 */ 
    		0x8024, 0x3b81, 0x8024, 0x3f04, 0xc024, 0x2808, 0x4800, 0x36f1, /* 18 */ 
    		0x9811, 0x0007, 0x0001, 0x8028, 0x0006, 0x0002, 0x2a00, 0x040e,  
    }; 
    
    
    /*
    函数功能:激活PCM 录音模式
    函数参数:
    				agc:0,自动增益
            1024相当于1倍
            512相当于0.5倍
            最大值65535=64倍		  
    */
    void VS1053_RecoderInit(u16 agc)
    {
    	//如果是IMA ADPCM,采样率计算公式如下:
     	//采样率=CLKI/256*d;	
    	//假设d=0,并2倍频,外部晶振为12.288M.那么Fc=(2*12288000)/256*6=16Khz
    	//如果是线性PCM,采样率直接就写采样值 
      VS1053_WriteCmd(SPI_BASS,0x0000);    
     	VS1053_WriteCmd(SPI_AICTRL0,8000);	//设置采样率,设置为8Khz
     	VS1053_WriteCmd(SPI_AICTRL1,agc);		//设置增益,0,自动增益.1024相当于1倍,512相当于0.5倍,最大值65535=64倍	
     	VS1053_WriteCmd(SPI_AICTRL2,0);		  //设置增益最大值,0,代表最大值65536=64X
     	VS1053_WriteCmd(SPI_AICTRL3,6);		  //左通道(MIC单声道输入)
    	VS1053_WriteCmd(SPI_CLOCKF,0X2000);	//设置VS10XX的时钟,MULT:2倍频;ADD:不允许;CLK:12.288Mhz
    	VS1053_WriteCmd(SPI_MODE,0x1804);		//MIC,录音激活    
     	DelayMs(5);					//等待至少1.35ms 
     	VS1053_LoadPatch((u16*)VS1053_WavPlugin,40);//VS1053的WAV录音需要patch
    }
    
    

     

    6.2   SD.c  这是SD卡的驱动代码

    #include "sdcard.h"			   
    static u8  SD_Type=0;  //存放SD卡的类型
    
    /*
    函数功能:SD卡底层接口,通过SPI时序向SD卡读写一个字节
    函数参数:data是要写入的数据
    返 回 值:读到的数据
    */
    u8 SDCardReadWriteOneByte(u8 DataTx)
    {		 
        u16 cnt=0;				 
        while((SPI1->SR&1<<1)==0)		 //等待发送区空--等待发送缓冲为空	
        {
          cnt++;
          if(cnt>=65530)return 0; 	  //超时退出  u16=2个字节
        }	
        SPI1->DR=DataTx;	 	  		      //发送一个byte 
        cnt=0;
        while((SPI1->SR&1<<0)==0) 		//等待接收完一个byte   
        {
          cnt++;
          if(cnt>=65530)return 0;	   //超时退出
        }	  						    
        return SPI1->DR;          		//返回收到的数据
    }
    
    
    /*
    函数功能:底层SD卡接口初始化
    SPI1接口---SD卡接线原理
    5V----5V
    GND---GND
    SPI1_MOSI---PA7
    SPI1_MISO---PA6
    SPI1_CS---PA4
    SPI1_SCK--PA5
    */
    void SDCardSpiInit(void)
    {
      /*1. 开启时钟*/
     	RCC->APB2ENR|=1<<2;		    //使能PORTA时钟
      
      /*2. 配置GPIO口模式*/
      GPIOA->CRL&=0x0000FFFF;
      GPIOA->CRL|=0xB8B30000;
      
      /*3. 上拉*/
      GPIOA->ODR|=1<<4;
    	
    		/*SPI1基本配置*/
    	RCC->APB2ENR|=1<<12;    //开启SPI1时钟
    	RCC->APB2RSTR|=1<<12;
    	RCC->APB2RSTR&=~(1<<12);
    	
    	SPI1->CR1=0X0; 		//清空寄存器
    	SPI1->CR1|=0<<15; //选择“双线双向”模式
    	SPI1->CR1|=0<<11; //使用8位数据帧格式进行发送/接收;
    	SPI1->CR1|=0<<10; //全双工(发送和接收);
    	SPI1->CR1|=1<<9;  //启用软件从设备管理
    	SPI1->CR1|=1<<8;  //NSS
    	SPI1->CR1|=0<<7;  //帧格式,先发送高位
    	SPI1->CR1|=0x0<<3;//当总线频率为36MHZ时,SPI速度为18MHZ,高速。
    	SPI1->CR1|=1<<2;  //配置为主设备
    	SPI1->CR1|=1<<1;  //空闲状态时, SCK保持高电平。
    	SPI1->CR1|=1<<0;  //数据采样从第二个时钟边沿开始。
    	SPI1->CR1|=1<<6;  //开启SPI设备。
    }
    
    /*
    函数功能:取消选择,释放SPI总线
    */
    void SDCardCancelCS(void)
    {
    	SDCARD_CS=1;
     	SDCardReadWriteOneByte(0xff);//提供额外的8个时钟
    }
    
    
    /*
    函数 功 能:选择sd卡,并且等待卡准备OK
    函数返回值:0,成功;1,失败;
    */
    u8 SDCardSelectCS(void)
    {
    	SDCARD_CS=0;
    	if(SDCardWaitBusy()==0)return 0;//等待成功
    	SDCardCancelCS();
    	return 1;//等待失败
    }
    
    
    /*
    函数 功 能:等待卡准备好
    函数返回值:0,准备好了;其他,错误代码
    */
    u8 SDCardWaitBusy(void)
    {
    	u32 t=0;
    	do
    	{
    		if(SDCardReadWriteOneByte(0XFF)==0XFF)return 0;//OK
    		t++;		  
    	}while(t<0xFFFFFF);//等待 
    	return 1;
    }
    
    
    /*
    函数功能:等待SD卡回应
    函数参数:
    					Response:要得到的回应值
    返 回 值:
    					0,成功得到了该回应值
    					其他,得到回应值失败
    */
    u8 SDCardGetAck(u8 Response)
    {
    	u16 Count=0xFFFF;//等待次数	   						  
    	while((SDCardReadWriteOneByte(0XFF)!=Response)&&Count)Count--;//等待得到准确的回应  	  
    	if(Count==0)return SDCard_RESPONSE_FAILURE;//得到回应失败   
    	else return SDCard_RESPONSE_NO_ERROR;//正确回应
    }
    
    
    /*
    函数功能:从sd卡读取一个数据包的内容
    函数参数:
    				buf:数据缓存区
    				len:要读取的数据长度.
    返回值:
    			0,成功;其他,失败;	
    */
    u8 SDCardRecvData(u8*buf,u16 len)
    {			  	  
    	if(SDCardGetAck(0xFE))return 1;//等待SD卡发回数据起始令牌0xFE
        while(len--)//开始接收数据
        {
            *buf=SDCardReadWriteOneByte(0xFF);
            buf++;
        }
        //下面是2个伪CRC(dummy CRC)
        SDCardReadWriteOneByte(0xFF);
        SDCardReadWriteOneByte(0xFF);									  					    
        return 0;//读取成功
    }
    
    
    /*
    函数功能:向sd卡写入一个数据包的内容 512字节
    函数参数:
    					buf 数据缓存区
    					cmd 指令
    返 回 值:0表示成功;其他值表示失败;
    */
    u8 SDCardSendData(u8*buf,u8 cmd)
    {	
    	u16 t;		  	  
    	if(SDCardWaitBusy())return 1;  //等待准备失效
    	SDCardReadWriteOneByte(cmd);
    	if(cmd!=0XFD)//不是结束指令
    	{
    		for(t=0;t<512;t++)SDCardReadWriteOneByte(buf[t]);//提高速度,减少函数传参时间
    	    SDCardReadWriteOneByte(0xFF); //忽略crc
    	    SDCardReadWriteOneByte(0xFF);
    		  t=SDCardReadWriteOneByte(0xFF); //接收响应
    		if((t&0x1F)!=0x05)return 2;   //响应错误									  					    
    	}						 									  					    
        return 0;//写入成功
    }
    
    
    
    /*
    函数功能:向SD卡发送一个命令
    函数参数:
    				u8 cmd   命令 
    				u32 arg  命令参数
    				u8 crc   crc校验值	
    返回值:SD卡返回的响应
    */												  
    u8 SendSDCardCmd(u8 cmd, u32 arg, u8 crc)
    {
    	u8 r1;	
    	u8 Retry=0; 
    		
    	SDCardCancelCS();               //取消上次片选
    	if(SDCardSelectCS())return 0XFF;//片选失效 
    	//发送数据
    	SDCardReadWriteOneByte(cmd | 0x40);//分别写入命令
    	SDCardReadWriteOneByte(arg >> 24);
    	SDCardReadWriteOneByte(arg >> 16);
    	SDCardReadWriteOneByte(arg >> 8);
    	SDCardReadWriteOneByte(arg);	  
    	SDCardReadWriteOneByte(crc); 
    	if(cmd==SDCard_CMD12)SDCardReadWriteOneByte(0xff);//Skip a stuff byte when stop reading
    	Retry=0X1F;
    	do
    	{
    		r1=SDCardReadWriteOneByte(0xFF);
    	}while((r1&0X80) && Retry--);	  //等待响应,或超时退出
       return r1;	//返回状态值
    }	
    
    
    
    /*
    函数功能:获取SD卡的CID信息,包括制造商信息
    函数参数:u8 *cid_data(存放CID的内存,至少16Byte)	  
    返 回 值:
    					0:成功,1:错误				
    */
    u8 GetSDCardCISDCardOutnfo(u8 *cid_data)
    {
        u8 r1;	   
        //发SDCard_CMD10命令,读CID
        r1=SendSDCardCmd(SDCard_CMD10,0,0x01);
        if(r1==0x00)
    	  {
    			r1=SDCardRecvData(cid_data,16);//接收16个字节的数据	 
        }
    	SDCardCancelCS();//取消片选
    	if(r1)return 1;
    	else return 0;
    }	
    
    
    /*
    函数说明:
    					获取SD卡的CSD信息,包括容量和速度信息
    函数参数:
    					u8 *cid_data(存放CID的内存,至少16Byte)	    
    返 回 值:
    					0:成功,1:错误	
    */
    u8 GetSDCardCSSDCardOutnfo(u8 *csd_data)
    {
    	u8 r1;	 
    	r1=SendSDCardCmd(SDCard_CMD9,0,0x01);    //发SDCard_CMD9命令,读CSD
    	if(r1==0)
    	{
    		r1=SDCardRecvData(csd_data, 16);//接收16个字节的数据 
    	}
    	SDCardCancelCS();//取消片选
    	if(r1)return 1;
    	else return 0;
    }  
    
    
    /*
    函数功能:获取SD卡的总扇区数(扇区数)   
    返 回 值:
    				0表示容量检测出错,其他值表示SD卡的容量(扇区数/512字节)
    说   明:
    				每扇区的字节数必为512字节,如果不是512字节,则初始化不能通过.	
    */
    u32 GetSDCardSectorCount(void)
    {
        u8 csd[16];
        u32 Capacity;  
    	  u16 csize;  					    
        if(GetSDCardCSSDCardOutnfo(csd)!=0) return 0;	//取CSD信息,如果期间出错,返回0
        if((csd[0]&0xC0)==0x40)  //SDHC卡,按照下面方式计算
        {	
    			csize = csd[9] + ((u16)csd[8] << 8) + 1;
    			Capacity = (u32)csize << 10;//得到扇区数	 		   
        }
        return Capacity;
    }
    
    
    
    /*
    函数功能: 初始化SD卡
    返 回 值: 非0表示初始化失败!
    */
    u8 SDCardDeviceInit(void)
    {
      u8 r1;      // 存放SD卡的返回值
      u16 retry;  // 用来进行超时计数
      u8 buf[4];  
    	u16 i;
    	SDCardSpiInit();		//初始化底层IO口
    	
     	for(i=0;i<10;i++)SDCardReadWriteOneByte(0XFF); //发送最少74个脉冲
    	retry=20;
    	do
    	{
    		r1=SendSDCardCmd(SDCard_CMD0,0,0x95);//进入IDLE状态 闲置
    	}while((r1!=0X01) && retry--);
     	SD_Type=0;   //默认无卡
    	if(r1==0X01)
    	{
    		if(SendSDCardCmd(SDCard_CMD8,0x1AA,0x87)==1)  //SD V2.0
    		{
    			for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);
    			if(buf[2]==0X01&&buf[3]==0XAA)    //卡是否支持2.7~3.6V
    			{
    				retry=0XFFFE;
    				do
    				{
    					SendSDCardCmd(SDCard_CMD55,0,0X01);	    //发送SDCard_CMD55
    					r1=SendSDCardCmd(SDCard_CMD41,0x40000000,0X01);//发送SDCard_CMD41
    				}while(r1&&retry--);
    				if(retry&&SendSDCardCmd(SDCard_CMD58,0,0X01)==0)//鉴别SD2.0卡版本开始
    				{
    					for(i=0;i<4;i++)buf[i]=SDCardReadWriteOneByte(0XFF);//得到OCR值
    					if(buf[0]&0x40)SD_Type=SDCard_TYPE_V2HC;    //检查CCS
    					else SD_Type=SDCard_TYPE_V2;   
    				}
    			}
    		}
    	}
    	SDCardCancelCS();       //取消片选
    	if(SD_Type)return 0;  //初始化成功返回0
    	else if(r1)return r1; //返回值错误值	   
    	return 0xaa;          //其他错误
    }
    
    
    /*
    函数功能:读SD卡
    函数参数:
    				buf:数据缓存区
    				sector:扇区
    				cnt:扇区数
    返回值:
    				0,ok;其他,失败.
    说  明:
    				SD卡一个扇区大小512字节
    */
    u8 SDCardReadData(u8*buf,u32 sector,u32 cnt)
    {
    	u8 r1;
    	if(SD_Type!=SDCard_TYPE_V2HC)sector<<=9;//转换为字节地址
    	if(cnt==1)
    	{
    		r1=SendSDCardCmd(SDCard_CMD17,sector,0X01);//读命令
    		if(r1==0)												  //指令发送成功
    		{
    			r1=SDCardRecvData(buf,512);			//接收512个字节	   
    		}
    	}else
    	{
    		r1=SendSDCardCmd(SDCard_CMD18,sector,0X01);//连续读命令
    		do
    		{
    			r1=SDCardRecvData(buf,512);//接收512个字节	 
    			buf+=512;  
    		}while(--cnt && r1==0); 	
    		SendSDCardCmd(SDCard_CMD12,0,0X01);	//发送停止命令
    	}   
    	SDCardCancelCS();//取消片选
    	return r1;//
    }
    
    /*
    函数功能:向SD卡写数据
    函数参数:
    				buf:数据缓存区
    				sector:起始扇区
    				cnt:扇区数
    返回值:
    				0,ok;其他,失败.
    说  明:
    				SD卡一个扇区大小512字节
    */
    u8 SDCardWriteData(u8*buf,u32 sector,u32 cnt)
    {
    	u8 r1;
    	if(SD_Type!=SDCard_TYPE_V2HC)sector *= 512;//转换为字节地址
    	if(cnt==1)
    	{
    		r1=SendSDCardCmd(SDCard_CMD24,sector,0X01);//读命令
    		if(r1==0)//指令发送成功
    		{
    			r1=SDCardSendData(buf,0xFE);//写512个字节	   
    		}
    	}
    	else
    	{
    		if(SD_Type!=SDCard_TYPE_MMC)
    		{
    			SendSDCardCmd(SDCard_CMD55,0,0X01);	
    			SendSDCardCmd(SDCard_CMD23,cnt,0X01);//发送指令	
    		}
     		r1=SendSDCardCmd(SDCard_CMD25,sector,0X01);//连续读命令
    		if(r1==0)
    		{
    			do
    			{
    				r1=SDCardSendData(buf,0xFC);//接收512个字节	 
    				buf+=512;  
    			}while(--cnt && r1==0);
    			r1=SDCardSendData(0,0xFD);//接收512个字节 
    		}
    	}   
    	SDCardCancelCS();//取消片选
    	return r1;//
    }	
    
    

     

     

    展开全文
  • 先说iOS吧,iOS 想要内录实在很简单,只需要在使用系统自带的「屏幕录制」时,在下方关闭麦克风就行了(关闭之后录屏就只有系统声音了)???? 而安卓就比较麻烦了,今天要分享的主要也是安卓如何内录 ▍1 Android 11...
  • 1、小小录音师,声音的获取与加工,教材分析,课题来源:声音的获取与加工是教材初中信息技术(上册)第七单元第一节的内容 课标要求:掌握获取声音信息的途径和方法,并能根据信息呈现需求,对声音文件进行适当的处理 ...
  • 目录 项目场景 ...Vue 工程在 Chrome 浏览器打开,无法获取音视频设备,控制台提示获取音频设备权限问题 Cannot read property getUserMedia of undefined 解决方案 方法一、网页使用https方式访...
  • 我有一台带连接摄像的Ubuntu 14.04机器 . 摄像通过magewell HDMI-...当我拨打arecord-l时,我会收到以下音频设备:arecord -l**** Liste der Hardware-Geräte (CAPTURE) **** Karte 1: PCH [HDA Intel PCH], Ge...
  • 全频带声音(如音乐声、风雨声、汽车声等),其带宽可达到20Hz~20kHz(人耳可听见的声音) 人耳可听到的声音统称“可听声”(audio) ,20Hz~20kH (二)波形声因 波形声音,是最常用的 Windows
  • 当我们用录音机录网上的音乐时,有一个场景让人困扰: 比如听以下页面中的一首歌,要在页面上点击一下播放按钮 如果想把这一首歌录下来,当点击了播放按钮再去点录音机的录制按钮时,中间有一个时间差。可能一不...
  • python获取win10系统声音

    千次阅读 2020-06-10 13:43:40
    首先是驱动环境这样: import pyaudio p = pyaudio.PyAudio() for i in range(p.get_device_count()): devInfo = p.get_device_...# {'index': 0, 'structVersion': 2, 'name': 'Microsoft 声音映射器 - Input
  • 要录制这个声音信号,我正在使用一个特殊的麦克风,我想通过音频输入线直接插入我的Android设备,所以我不会使用手机麦克风 .以下是我在Android网站上发现的内容:“定义音频源 . 这些常量与setAudioSource(int)...
  • 所以,本期声音课堂,我们简单梳理了3个Vlog拍摄过程中同期录音的小技巧,希望能够帮助你在今后的视频内容中获取更加优质的声音。01 请勿使用内置麦克风录音不到万不得已,请不要使用摄像、相机、手机内置的麦克风...
  • 对于想录制电脑系统声音的小伙伴,今天小编介绍一款电脑系统内部录音工具(用电脑语音通话的时候可以将语音录制保存电脑里),再也不同担心总是记不住老板语音通话里面交代的任务了哈哈。我们可以使用该录制工具做好...
  • vue实战,前端如何调用手机录音功能

    千次阅读 热门讨论 2020-08-18 11:14:11
    在web API中提供了getUserMedia这个方法,就是用来给我们获取各种媒体应用的,想了解底层的可以百度一下这个方法,介绍的很详细,了解这个东西,自己也能手动封装插件,但是既然是实战,咱们要的就是用最快的方法...
  • 音响系统速成方法学习资料1、压缩器的主要保护作用是保护音箱。2、播放迪斯科舞曲,均衡器适宜低音强烈提升,高音适当提升。3、演唱卡拉OK效果器程序宜选DELAY。...8、声音暗淡,要提升高音,应调节调音台的TREBLE。...
  • Unity 声音录音与麦克风实时播放

    千次阅读 2019-06-17 02:14:00
    Unity AudioSource与MicroPhone以及AudioClip之间的关系。 下面是一个声音,长度为7秒钟,...AudioSource播放声音时,设置其TimeSamples的意思就是从声音的第timeSamples个采样点位置开始播放,因此设置声音的播...
  • 本文对电子键盘(双排键、电子琴、电钢琴合成器等)用手机进行内录的操作方法以及所需设备进行讲解视频中的示范曲目为:EI Dorado音色伴奏数据支持琴型为:吟飞二代琴(Rs760/800/1000E)雅马哈02系列(ELB02/ELC02/ELS02...
  • 标准19寸机架式设计,可以安装在机柜里面节省空间,完全独立无须依赖电脑即可工作的录音设备,采用...录音记录查询,声音回放,即时监听等等功能,大大方便了设备的施工,安装,调试,是一台真正的嵌入式录音服务器。
  • 参数-D是指定录音设备,这里用的是USB声卡plughw:1,0 安装图像界面的录音工具 有时候我们需要看到录音时的音频曲线,这个时候我们就需要用到audacity这个图形界面的树莓派录音工具了。在线安装方法如下; apt-get...
  • AAudio 音频设备 ID 获取 IV . AAudio 音频流 默认 音频设备设置 V . AAudio 音频流构建器 设置 音频流方向 AAudioStreamBuilder_setDirection VI . AAudio 音频流方向 VII . AAudio 音频流构建器 设置 音频设备...
  • 这篇文章将会按照一般的需求开发流程,从需求、分析、开发,到总结,来给大家讲解一种“在 Android 设备上,播放视频的同时,获取实时音频流”的有效方案。一、需求在车载产品上,有这样一种...
  • 首先录音功能很容易实现,通过audiorecord或者mediarecorder都可以实现,如果要获取录音音量的大小,用audiorecord更加方便。实现录音功能可以大致分为几个步骤。一 初始化录音设备audiorecord。 二 ,开启一个线程...
  • js获取浏览器摄像头和麦克风权限

    千次阅读 2021-02-12 12:38:14
    前言项目中会使用到摄像头或麦克风设备,这就需要我们获取浏览器的摄像头和麦克风权限,权限是无法通过js操控的,必须由浏览器用户设置。下面我来告诉大家如何获取浏览器的摄像头或麦克风的权限,使浏览器弹出询问...
  • 这里,重点不是说如何通过H5获取Audio数据,重点是说这个过程中涉及的坑或者技术元素知识。直接上代码!1. HTML测试页面语音转写Voice Robot录音转写播放你好啊页面效果如下: 2. JS代码(分为两个部分,main.js,...
  • 2、教学目标知识与技能:通过贴近学生生活的实例,让学生体验在有明确的信息需求情形下信息获取的一般规律,使学生能够总结、推导出信息获取的一般过程。再进一步剖析信息获取的各个环节,使学生掌握信息来源的...
  • Linux实现音频录放

    2021-05-12 00:55:25
    一、原理简述在Linux下,录音——从dsp设备读取数据,放音——向dsp设备写入数据。开发板采用声卡UDA1341实现音频编解码,完成A/D和D/A转换,芯片UDA1341与CPU的连接图如下:为了实现全双工,数据传输需要使用两个...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 7,196
精华内容 2,878
关键字:

录音机是获取声音的设备

友情链接: ModalDialog.zip