使用混音算法先对音频进行混音,再使用Android tinyalsa进行播放

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

提示:这里可以添加本文要记录的大概内容:

例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、混音播放源码

#include <stdio.h>  
#include <stdlib.h>  
#include <math.h>
#include <tinyalsa/asoundlib.h>
#include <stdint.h>
#include <string.h>
#include <signal.h>
#include <endian.h>  
#include <threads.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>

#define IN_FILE1 "data/1.wav"  
#define IN_FILE2 "data/2.wav"  
#define OUT_FILE "data/remix.pcm"  

#define SIZE_AUDIO_FRAME (2)  

static int stream_close_flag = 0;

void stream_close(int sig)
{
    /* allow the stream to be closed gracefully */
    signal(sig, SIG_IGN);
    stream_close_flag = 1;
}

void Mix(char sourseFile[10][SIZE_AUDIO_FRAME],int number,char *objectFile)  
{  
    //归一化混音  
    int const MAX=32767;  
    int const MIN=-32768;  

    double f=1;  
    int output;  
    int i = 0,j = 0;  
    for (i=0; i < SIZE_AUDIO_FRAME/2; i++)  
    {  
        int temp=0;  
        for (j=0;j<number;j++)  
        {  
            temp+=*(short*)(sourseFile[j]+i*2);  
        }                  
        output=(int)(temp*f);  
        if (output>MAX)  
        {  
            f=(double)MAX/(double)(output);  
            output=MAX;  
        }  
        if (output<MIN)  
        {  
            f=(double)MIN/(double)(output);  
            output=MIN;  
        }  
        if (f<1)  
        {  
            f+=((double)1-f)/(double)32;  
        }  
        *(short*)(objectFile+i*2)=(short)output;  
    }  
}  

int check_param(struct pcm_params *params, unsigned int param, unsigned int value,
                 char *param_name, char *param_unit)
{
    unsigned int min;
    unsigned int max;
    int is_within_bounds = 1;

    min = pcm_params_get_min(params, param);
    if (value < min) {
        fprintf(stderr, "%s is %u%s, device only supports >= %u%s\n", param_name, value,
                param_unit, min, param_unit);
        is_within_bounds = 0;
    }

    max = pcm_params_get_max(params, param);
    if (value > max) {
        fprintf(stderr, "%s is %u%s, device only supports <= %u%s\n", param_name, value,
                param_unit, max, param_unit);
        is_within_bounds = 0;
    }

    return is_within_bounds;
}

int sample_is_playable(unsigned int card, unsigned int device, unsigned int channels,
                        unsigned int rate, unsigned int bits, unsigned int period_size,
                        unsigned int period_count)
{
    struct pcm_params *params;
    int can_play;

    params = pcm_params_get(card, device, PCM_OUT);
    if (params == NULL) {
        fprintf(stderr, "Unable to open PCM device %u.\n", device);
        return 0;
    }

    can_play = check_param(params, PCM_PARAM_RATE, rate, "Sample rate", "Hz");
    can_play &= check_param(params, PCM_PARAM_CHANNELS, channels, "Sample", " channels");
    can_play &= check_param(params, PCM_PARAM_SAMPLE_BITS, bits, "Bitrate", " bits");
    can_play &= check_param(params, PCM_PARAM_PERIOD_SIZE, period_size, "Period size", " frames");
    can_play &= check_param(params, PCM_PARAM_PERIODS, period_count, "Period count", " periods");

    pcm_params_free(params);

    return can_play;
}


int playback_thread()
{
    printf("playback_thread excute!!!\n");
    // FILE *file;
    int file;
    struct pcm_config config;
    struct pcm *pcm;
    unsigned int size, read_sz;
    char *buffer;
    int num_read;

    config.channels = 2;
    config.rate = 11025;
    config.period_count = 4;
    config.period_size = 1024;
    config.format = PCM_FORMAT_S16_LE;
    config.start_threshold = 0;
    config.stop_threshold = 0;
    config.silence_threshold = 0;
    config.avail_min = 0;
    unsigned int flag = PCM_OUT;
    char *filename = OUT_FILE;

    file = open(filename, O_RDONLY | O_CREAT | O_TRUNC, 0777);
    if (/*!file*/ file < 0) {
        fprintf(stderr, "Unable to open file '%s'\n", filename);
        return 1;
    }
    int flags;
    flags  = fcntl(file, F_GETFL, 0);
    fcntl(file, F_SETFL, flags & ~O_NONBLOCK); 

    if (!sample_is_playable(0, 0, config.channels, config.rate, 16, config.period_size, config.period_count)) {
        printf("parameters error\n");  
        return -1;
    }

    pcm = pcm_open(0, 0, flag, &config);
    if (!pcm || !pcm_is_ready(pcm)) {
        fprintf(stderr, "Unable to open PCM device %u (%s)\n",
                0, pcm_get_error(pcm));
        return -1;
    }

    size = pcm_frames_to_bytes(pcm, pcm_get_buffer_size(pcm));
    buffer = malloc(size);
    if (!buffer) {
        fprintf(stderr, "Unable to allocate %d bytes\n", size);
        free(buffer);
        pcm_close(pcm);
        return -1;
    }

    signal(SIGINT, stream_close);

    do {
        //read_sz = size < data_sz ? size : data_sz;
        read_sz = size;
        // num_read = fread(buffer, 1, read_sz, file);
        num_read = read(file, buffer, read_sz);
        if (num_read > 3) {
            printf("---------------4-num_read = %d \n", num_read); 
            if (pcm_write(pcm, buffer, num_read)) {
                fprintf(stderr, "Error playing sample\n");
                break;
            }
            //data_sz -= num_read;
        }
        if(num_read < 2){
            printf("---------------5-num_read = %d <3 process maybe enter read block!!!--------\n", num_read);
            continue;
        } 
    } while (!stream_close_flag);
    free(buffer);
    pcm_close(pcm);
    return 0;
}

int multi_source_mix_thread()
{
    // FILE * fp1,*fp2,*fpm;
    int fd1, fd2, fdm;  
    // fp1 = fopen(IN_FILE1,"rb");  
    // fp2 = fopen(IN_FILE2,"rb");  
    // fpm = fopen(OUT_FILE,"wb");  
 
    fd1 = open(IN_FILE1, O_RDONLY);
    fd2 = open(IN_FILE2, O_RDONLY);
    fdm = open(OUT_FILE, O_WRONLY | O_CREAT | O_TRUNC, 0777);
    if(fd1 < 0 || fd2 < 0 || fdm < 0){
        printf("file open error!!!\n");  
    }
    int flags;
    flags  = fcntl(fd1, F_GETFL, 0);
    fcntl(fd1, F_SETFL, flags & ~O_NONBLOCK); 
    flags  = fcntl(fd2, F_GETFL, 0);
    fcntl(fd2, F_SETFL, flags & ~O_NONBLOCK); 


    short data1,data2,data_mix;
    int ret1,ret2;  
    char sourseFile[10][2];

    while(1)  
    {  
        //混音
        // ret1 = fread(&data1,2,1,fp1);  
        // ret2 = fread(&data2,2,1,fp2);
        ret1 = read(fd1, &data1, 2);
        ret2 = read(fd2, &data2, 2);  
        *(short*) sourseFile[0] = data1;  
        *(short*) sourseFile[1] = data2;  

        if((ret1 == 2) /*ret1>0*/ && (ret2 == 2) /*ret2>0*/)  
        {  
            Mix(sourseFile,2,(char *)&data_mix);  
            /* 
            if( data1 < 0 && data2 < 0) 
                data_mix = data1+data2 - (data1 * data2 / -(pow(2,16-1)-1)); 
            else 
                data_mix = data1+data2 - (data1 * data2 / (pow(2,16-1)-1));*/  

            if(data_mix > pow(2,16-1) || data_mix < -pow(2,16-1))  
                printf("mix error\n");  
        }  
        else if( (ret1 == 2)/*(ret1 > 0)*/ && (ret2 < 2)/*(ret2==0)*/)  
        {  
            data_mix = data1;
        }  
        else if( (ret2 == 2) && (ret1 < 2)/*(ret2 > 0) && (ret1==0)*/)  
        {  
            data_mix = data2;  
        }  
        else if( (ret1 < 2) && (ret2 < 2)/*(ret1 == 0) && (ret2 == 0)*/ )  
        {  
            printf("ret1 < 2 && ret2 < 2, process will enter block!!!\n"); 
            continue;
        }
        // fwrite(&data_mix,2,1,fpm);
        write(fdm, &data_mix, 2);
    }  
    // fclose(fp1);  
    // fclose(fp2);  
    // fclose(fpm);  
    close(fd1);
    close(fd2);
    close(fdm);
    printf("Done!\n");
    return 0;  
}

int main()  
{  
    printf("main !!!\n");
    thrd_t thread1;
    thrd_t thread2;
    thrd_create(&thread1, multi_source_mix_thread, "th1");
    thrd_create(&thread2, playback_thread, "th2");
    thrd_join(thread1,NULL);
    printf("main thread1 end!!!\n");
	thrd_join(thread2,NULL);
    printf("main thread2 end!!!\n");
} 

二、编译文件

cc_library {
    name: "libtinyalsa",
    host_supported: true,
    vendor_available: true,
    vndk: {
        enabled: true,
    },
    srcs: [
        "mixer.c",
        "pcm.c",
    ],
    cflags: ["-Werror", "-Wno-macro-redefined"],
    export_include_dirs: ["include"],
    local_include_dirs: ["include"],

    target: {
        darwin: {
            enabled: false,
        },
    },
}

cc_binary {
    name: "multiSourceMixer",
    host_supported: true,
    srcs: ["multiSourceMixer.c"],
    shared_libs: ["libtinyalsa"],
    cflags: ["-Werror"],
    target: {
        darwin: {
            enabled: false,
        },
    },
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要对通过waveInOpen采集到的音频进行混音,您可以使用Windows多媒体API中的waveOutOpen函数打开一个音频输出设备,并通过waveOutWrite函数将采集到的音频数据写入输出设备进行播放。下面是一个简单的示例代码: ```c++ #include <Windows.h> #include <mmsystem.h> #pragma comment(lib, "winmm.lib") #define NUM_BUFFERS 3 #define BUFFER_SIZE 4096 HWAVEIN hWaveIn; WAVEHDR waveHeaders[NUM_BUFFERS]; char buffers[NUM_BUFFERS][BUFFER_SIZE]; HWAVEOUT hWaveOut; WAVEHDR waveOutHeaders[NUM_BUFFERS]; char outBuffers[NUM_BUFFERS][BUFFER_SIZE]; void CALLBACK WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { if (uMsg == WIM_DATA) { // 混音处理,将录制的音频数据与已播放音频数据进行混合 LPWAVEHDR pHdr = (LPWAVEHDR)dwParam1; memcpy(outBuffers[0] + pHdr->dwBytesRecorded, pHdr->lpData, pHdr->dwBytesRecorded); // 将录音数据写入输出设备进行播放 waveOutWrite(hWaveOut, pHdr, sizeof(WAVEHDR)); // 释放已经处理完的缓冲区 waveInUnprepareHeader(hwi, pHdr, sizeof(WAVEHDR)); waveInPrepareHeader(hwi, pHdr, sizeof(WAVEHDR)); waveInAddBuffer(hwi, pHdr, sizeof(WAVEHDR)); } } void StartRecordingAndPlayback() { // 设置录音参数 WAVEFORMATEX format; format.wFormatTag = WAVE_FORMAT_PCM; format.nChannels = 1; format.nSamplesPerSec = 44100; format.wBitsPerSample = 16; format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8; format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign; format.cbSize = 0; // 打开音频输入设备 if (waveInOpen(&hWaveIn, WAVE_MAPPER, &format, (DWORD_PTR)WaveInProc, 0, CALLBACK_FUNCTION) != MMSYSERR_NOERROR) { printf("无法打开音频输入设备!\n"); return; } // 初始化录音缓冲区 for (int i = 0; i < NUM_BUFFERS; i++) { waveHeaders[i].lpData = buffers[i]; waveHeaders[i].dwBufferLength = BUFFER_SIZE; waveHeaders[i].dwBytesRecorded = 0; waveHeaders[i].dwUser = 0; waveHeaders[i].dwFlags = 0; waveHeaders[i].dwLoops = 0; waveInPrepareHeader(hWaveIn, &waveHeaders[i], sizeof(WAVEHDR)); waveInAddBuffer(hWaveIn, &waveHeaders[i], sizeof(WAVEHDR)); } // 打开音频输出设备 if (waveOutOpen(&hWaveOut, WAVE_MAPPER, &format, 0, 0, CALLBACK_NULL) != MMSYSERR_NOERROR) { printf("无法打开音频输出设备!\n"); waveInClose(hWaveIn); return; } // 初始化音频输出缓冲区 for (int i = 0; i < NUM_BUFFERS; i++) { waveOutHeaders[i].lpData = outBuffers[i]; waveOutHeaders[i].dwBufferLength = BUFFER_SIZE; waveOutHeaders[i].dwBytesRecorded = 0; waveOutHeaders[i].dwUser = 0; waveOutHeaders[i].dwFlags = 0; waveOutHeaders[i].dwLoops = 0; waveOutPrepareHeader(hWaveOut, &waveOutHeaders[i], sizeof(WAVEHDR)); } // 开始录音和播放 waveInStart(hWaveIn); for (int i = 0; i < NUM_BUFFERS; i++) { waveOutWrite(hWaveOut, &waveOutHeaders[i], sizeof(WAVEHDR)); } printf("开始录音和播放,请按任意键停止...\n"); getchar(); // 停止录音和播放 waveInStop(hWaveIn); waveInReset(hWaveIn); waveInClose(hWaveIn); waveOutReset(hWaveOut); waveOutClose(hWaveOut); printf("录音和播放已停止。\n"); } int main() { StartRecordingAndPlayback(); return 0; } ``` 这个示例代码会同时进行录音和播放,将录制的音频数据与已经播放音频数据进行混合,并通过音频输出设备进行播放。 请注意,这只是一个简单的示例,用于演示如何进行音频混音。在实际应用中,您可能需要更复杂的算法和处理来实现更高质量的混音效果。 希望这可以帮助您进行音频混音操作!如果您还有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值