Node.js 基于频率创建音频文件

Node.js 基于频率创建音频文件,node.js,audio,frequency,midi,Node.js,Audio,Frequency,Midi,我正在用node.js做一个项目。 该项目是将单词转换成数字,然后获取这些数字并创建音频输出。 音频输出应将数字作为频率播放。例如,我有一个数字数组[9132552],现在我想把这些数字作为频率播放。 我知道我可以在浏览器中使用音频API或任何其他允许我这样做的第三个软件包播放它们。 问题是,我想创建一些音频文件,我尝试将这些数字转换为音符,然后将其保存为Midi文件,我成功了,但问题是Midi文件获取频率,将其转换为最接近的音符(例如:913将转换为932.33HZ,即音符编号81) //添加

我正在用node.js做一个项目。 该项目是将单词转换成数字,然后获取这些数字并创建音频输出。 音频输出应将数字作为频率播放。例如,我有一个数字数组[9132552],现在我想把这些数字作为频率播放。 我知道我可以在浏览器中使用音频API或任何其他允许我这样做的第三个软件包播放它们。 问题是,我想创建一些音频文件,我尝试将这些数字转换为音符,然后将其保存为Midi文件,我成功了,但问题是Midi文件获取频率,将其转换为最接近的音符(例如:913将转换为932.33HZ,即音符编号81)

//添加曲目
var数组=gematriaArray
变量计数=0
var track=midi.addTrack()
var票据
对于(var i=0;imidi音符。
midi:ftom(parseInt(note)),
时间:伯爵,
持续时间:3
})
计数++
}
//写入输出
fs.writeFileSync('./public/sounds/'+name+random+'.mid',新的Buffer.from(midi.toArray()))
我在网上搜索了一下,但找不到任何有帮助的东西。 我真的很想有一个文件,用户可以下载这些数字作为频率,有人知道可以做什么来得到这个结果


提前感谢您的帮助。

此函数将使用浮点值填充缓冲区,这些浮点值表示给定频率下原始音频曲线的高度

var pop_audio_buffer_custom = function (number_of_samples, given_freq, samples_per_second) {

    var number_of_samples = Math.round(number_of_samples);

    var audio_obj = {};
    
    var source_buffer = new Float32Array(number_of_samples);

    audio_obj.buffer = source_buffer;

    var incr_theta = (2.0 * Math.PI * given_freq) / samples_per_second;
    var theta = 0.0;

    for (var curr_sample = 0; curr_sample < number_of_samples; curr_sample++) {

        audio_obj.buffer[curr_sample] = Math.sin(theta);

        console.log(audio_obj.buffer[curr_sample] , "theta ", theta);

        theta += incr_theta;
    }
    
    return audio_obj;

};       //      pop_audio_buffer_custom

var number_of_samples = 10000; // long enough to be audible
var given_freq = 300;
var samples_per_second = 44100;  // CD quality sample rate
var wav_output_filename = "/tmp/wav_output_filename.wav"

var synthesized_obj = {};

synthesized_obj.buffer = pop_audio_buffer_custom(number_of_samples, given_freq, samples_per_second);
var pop\u audio\u buffer\u custom=函数(采样数、给定频率、每秒采样数){
变量样本数=数学四舍五入(样本数);
var audio_obj={};
var source_buffer=新的Float32Array(样本数);
音频对象缓冲区=源缓冲区;
var增量θ=(2.0*Math.PI*给定频率)/每秒采样数;
varθ=0.0;
对于(变量curr\u sample=0;curr\u sample<样本数;curr\u sample++){
音频对象缓冲区[curr\u sample]=Math.sin(θ);
log(音频对象缓冲区[curr\u sample],“theta”,theta);
θ+=增量θ;
}
返回音频对象;
};       //      pop_音频_缓冲_自定义
样本的变量数量=10000;//足够长以至于可以听见
给定的var_freq=300;
var采样率每秒钟=44100;//CD质量采样率
var wav_output_filename=“/tmp/wav_output_filename.wav”
var_obj={};
合成\u obj.buffer=pop\u audio\u buffer\u custom(采样数,给定频率,每秒采样数);
数字音频的世界是不平凡的。。。拥有音频缓冲区后的下一步是将浮点表示转换为可以以字节形式存储的内容(通常是16位整数,具体取决于您对位深度的选择)。。。然后,需要将16位整数缓冲区写入WAV文件

音频是一种有时被称为时间序列的波。。。当你把拳头砸在桌子上时,桌子上下晃动,推动微小的空气分子与那晃动一致。。。这种摆动的空气传播到整个房间,并到达麦克风振膜或可能是你的耳膜,而这反过来又摆动与此波共振。。。如果你把一支铅笔粘在横膈膜上,它会随着横膈膜摆动,然后你沿着铅笔的笔尖慢慢地滑动一条纸,你会看到一条曲线写在这条纸上。。。这是音频曲线。。。音频样本就是瞬间曲线的高度。。。如果您以恒定速率重复写下此曲线高度值X次/秒,您将拥有原始音频的数据点列表(这是上述函数创建的)。。。所以一个给定的音频样本就是给定时刻音频曲线高度的值。。。由于计算机不是连续的,而是离散的,它们不能处理整个铅笔画的曲线,所以只需要关心这个瞬时测量的曲线高度值列表。。。那些是音频样本

上述32位浮点缓冲区可输入以下函数以返回16位整数缓冲区

var convert_32_bit_float_into_signed_16_bit_int_lossy = function(input_32_bit_buffer) {

    // this method is LOSSY - intended as preliminary step when saving audio into WAV format files
    //                        output is a byte array where the 16 bit output format 
    //                        is spread across two bytes in little endian ordering

    var size_source_buffer = input_32_bit_buffer.length;

    var buffer_byte_array = new Int16Array(size_source_buffer * 2); // Int8Array 8-bit twos complement signed integer

    var value_16_bit_signed_int;
    var index_byte = 0;

    console.log("size_source_buffer", size_source_buffer);


    for (var index = 0; index < size_source_buffer; index++) {

        value_16_bit_signed_int = ~~((0 < input_32_bit_buffer[index]) ? input_32_bit_buffer[index] * 0x7FFF : 
                                                                        input_32_bit_buffer[index] * 0x8000);

        buffer_byte_array[index_byte] = value_16_bit_signed_int & 0xFF; // bitwise AND operation to pluck out only the least significant byte

        var byte_two_of_two = (value_16_bit_signed_int >> 8); //  bit shift down to access the most significant byte

        buffer_byte_array[index_byte + 1] = byte_two_of_two;

        index_byte += 2;
    };

    // ---

    return buffer_byte_array;
};
var将\u 32位\u浮点\u转换为\u有符号\u 16位\u整数\u有损=函数(输入\u 32位\u缓冲区){
//此方法是有损的-当将音频保存为WAV格式文件时,作为初步步骤
//输出是一个字节数组,其中16位输出格式
//在两个字节之间以小端序排列
变量大小\源\缓冲区=输入\ 32 \位\缓冲区长度;
var buffer_byte_array=new Int16Array(size_source_buffer*2);//Int8Array 8位双补有符号整数
var值\u 16位\u符号\u整数;
var索引_字节=0;
log(“大小\源\缓冲区”,大小\源\缓冲区);
对于(变量索引=0;索引>8);//位下移以访问最高有效字节
缓冲区字节数组[索引字节+1]=字节二的字节二;
索引字节+=2;
};
// ---
返回缓冲区\字节\数组;
};

下一步是将16位以上的int缓冲区保存到wav文件中。。。我建议您使用许多nodejs库中的一个(或者最好自己编写,因为它只有两页代码;-)

非常感谢您的回答,如果可以的话,我想知道我是否可以给出一个频率数组,我也想
var convert_32_bit_float_into_signed_16_bit_int_lossy = function(input_32_bit_buffer) {

    // this method is LOSSY - intended as preliminary step when saving audio into WAV format files
    //                        output is a byte array where the 16 bit output format 
    //                        is spread across two bytes in little endian ordering

    var size_source_buffer = input_32_bit_buffer.length;

    var buffer_byte_array = new Int16Array(size_source_buffer * 2); // Int8Array 8-bit twos complement signed integer

    var value_16_bit_signed_int;
    var index_byte = 0;

    console.log("size_source_buffer", size_source_buffer);


    for (var index = 0; index < size_source_buffer; index++) {

        value_16_bit_signed_int = ~~((0 < input_32_bit_buffer[index]) ? input_32_bit_buffer[index] * 0x7FFF : 
                                                                        input_32_bit_buffer[index] * 0x8000);

        buffer_byte_array[index_byte] = value_16_bit_signed_int & 0xFF; // bitwise AND operation to pluck out only the least significant byte

        var byte_two_of_two = (value_16_bit_signed_int >> 8); //  bit shift down to access the most significant byte

        buffer_byte_array[index_byte + 1] = byte_two_of_two;

        index_byte += 2;
    };

    // ---

    return buffer_byte_array;
};