node中使用C++模块调用调用speex完成语音文件压缩

        在最近的项目中,需要完成这样一个功能,要求app能与硬件进行语音交流,不需要实时,仅仅实现类似微信的按住说话的功能就可以。为了减少网络流量,考虑将音频文件压缩传送。成熟的压缩方式有speex、opus。目前speex已不再维护。考虑到本次需要的功能简单以及网上关于speex的文档较多的情况下,我们决定使用speex完成语音压缩功能。         我们通过node调用c++模块的方法,来实现speex的压缩(仅实现压缩,关于音频格式转换日后再码)。

ps: 先水上他一篇 :)

github

下载speex

我们选择speex的最新稳定版本进行下载:speex-1.2.0.tar.gz

具体步骤

1、将下载的speex文件放到项目中
  1. 项目根目录下新建deps文件夹,并在deps中新建文件,建好目录如下:
  2. 图中的speex-1.2.0为下载并解压好的speex。
  3. 在x64文件夹中新加config.h文件 内容如下
  4. building.gyp中的内容如下:(此部分主要用于选择性编译speex中的文件并加载到项目中)
{
    'variables': { 'target_arch%': 'x64' },

    'target_defaults': {
        'default_configuration': 'Debug',
        'configuration': {
            'Debug': {
                'defines': [ 'DEBUG', '_DEBUG' ],
                'msvs_settings': {
                    'VSSLCompilerTool': {
                        'RuntimeLibrary': 1, #static debug
                    },
                },
            },
            'Release': {
                'defines': [ 'NODEBUG' ],
                'msvs_settings': {
                    'VSSLCompilerTool': {
                        'RuntimeLibrary': 0, #static release
                    },
                },
            },
        },
        'msvs_settings': {
            'VCLinkerTool': {
                'GenerateDebugInformation': 'true',
            },
        },
    },

    'targets': [
        {
            'target_name': 'libspeexdsp',
            'type': 'static_library',
            'sources': [
                'speex-1.2.0/libspeex/bits.c',
                'speex-1.2.0/libspeex/cb_search.c',
                'speex-1.2.0/libspeex/exc_5_64_table.c',
                'speex-1.2.0/libspeex/exc_5_256_table.c',
                'speex-1.2.0/libspeex/exc_8_128_table.c',
                'speex-1.2.0/libspeex/exc_10_16_table.c',
                'speex-1.2.0/libspeex/exc_10_32_table.c',
                'speex-1.2.0/libspeex/exc_20_32_table.c',
                'speex-1.2.0/libspeex/filters.c',
                'speex-1.2.0/libspeex/gain_table.c',
                'speex-1.2.0/libspeex/gain_table_lbr.c',
                'speex-1.2.0/libspeex/hexc_10_32_table.c',
                'speex-1.2.0/libspeex/hexc_table.c',
                'speex-1.2.0/libspeex/high_lsp_tables.c',
                'speex-1.2.0/libspeex/kiss_fft.c',
                'speex-1.2.0/libspeex/kiss_fftr.c',
                'speex-1.2.0/libspeex/lpc.c',
                'speex-1.2.0/libspeex/lsp.c',
                'speex-1.2.0/libspeex/lsp_tables_nb.c',
                'speex-1.2.0/libspeex/ltp.c',
                'speex-1.2.0/libspeex/modes.c',
                'speex-1.2.0/libspeex/modes_wb.c',
                'speex-1.2.0/libspeex/nb_celp.c',
                'speex-1.2.0/libspeex/quant_lsp.c',
                'speex-1.2.0/libspeex/smallft.c',
                'speex-1.2.0/libspeex/speex.c',
                'speex-1.2.0/libspeex/speex_callbacks.c',
                'speex-1.2.0/libspeex/speex_header.c',
                'speex-1.2.0/libspeex/stereo.c',
                'speex-1.2.0/libspeex/vbr.c',
                'speex-1.2.0/libspeex/vq.c',
                'speex-1.2.0/libspeex/window.c'
            ],
            'cflags': [
                '-fvisibility=hidden',
                '-W',
                '-Wstrict-prototypes',
                '-Wno-parentheses',
                '-Wno-unused-parameter',
                '-Wno-sign-compare',
                '-Wno-unused-variable',
            ],
            'include_dirs': [
                'config/speex-1.2.0/<(OS)/<(target_arch)',
                'speex-1.2.0/include',
            ],
            'defines': [
                'PIC',
                'HAVE_CONFIG_H',
                '_USE_MATH_DEFINES',
            ]
        }
    ]
}
复制代码
2 新加c++目录,如下图所示

此目录为我们要自己动手实现的c++代码,其中hello.cc文件内容如下:(由于编码格式错误,暂时分多段显示代码,一下代码全为hello.cc)

#include <node.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
复制代码
#ifdef __cplusplus
extern "C"
{
#endif
#include <speex/speex.h>
#include <speex/speex_callbacks.h>
#ifdef __cplusplus
}
#endif
复制代码
#ifdef FIXED_DEBUG
extern long long spx_mips;
#endif
复制代码
#define FRAME_SIZE 160
#ifdef FIXED_DEBUG
extern long long spx_mips;
#endif
复制代码
using namespace v8;
复制代码
void Add(const FunctionCallbackInfo<Value>& args) {
复制代码
    Isolate* isolate = Isolate::GetCurrent();
    HandleScope scope(isolate);
    void *st;
    FILE *fin,*fout;
    short in[FRAME_SIZE];
    float input[FRAME_SIZE];
    char cbits[200];
    int nbBytes;

    SpeexBits bits;
    int i,tmp;

    st = speex_encoder_init(&speex_nb_mode);

    tmp = 8;
    speex_encoder_ctl(st,SPEEX_SET_QUALITY,&tmp);

    Local<Value> in_addr = args[0];
    Local<String> ss = in_addr->ToString();
    String::Utf8Value value(ss);
    char* c =  *value;
    fin = fopen(c,"rb");
复制代码
    Local<Value> out_addr = args[1];
    Local<String> out_addr_str = out_addr->ToString();
    String::Utf8Value value1(out_addr_str);
    char* o = *value1;
    fout = fopen(o,"wb+");


speex_bits_init(&bits);
while(1){
    fread(in,sizeof(short),FRAME_SIZE,fin);
    if(feof(fin))
        break;
    for(i = 0;i<FRAME_SIZE;i++){
        input[i] = in[i];
    }
    speex_bits_reset(&bits);
    speex_encode(st,input,&bits);
    nbBytes = speex_bits_write(&bits,cbits,200);
    fwrite(&nbBytes, sizeof(int), 1, fout);
    fwrite(cbits, 1, nbBytes, fout);
}
复制代码
   speex_encoder_destroy(st);
   /*Destroy the bit-packing struct*/
   speex_bits_destroy(&bits);
   fclose(fin);

}

void Init(Handle<Object> exports) {
  NODE_SET_METHOD(exports, "add", Add);
}

NODE_MODULE(hello, Init)
复制代码
3 根目录下新建binding.gyp

binding.gyp内容如下:

{
  "targets": [
    {
      "target_name": "hello",
      "sources": ["./c++/hello.cc", ],
      "dependencies":[
        "deps/binding.gyp:libspeexdsp"
      ],
        'cflags': [
                      '-pthread',
                      '-fno-exceptions',
                      '-fno-strict-aliasing',
                      '-Wall',
                      '-Wno-unused-parameter',
                      '-Wno-missing-field-initializers',
                      '-Wextra',
                      '-pipe',
                      '-fno-ident',
                      '-fdata-sections',
                      '-ffunction-sections',
                      '-fPIC'
                  ],
                  'defines': [
                      'LARGEFILE_SOURCE',
                      '_FILE_OFFSET_BITS=64',
                      'WEBRTC_TARGET_PC',
                      'WEBRTC_LINUX',
                      'WEBRTC_THREAD_RR',
                      'EXPAT_RELATIVE_PATH',
                      'GTEST_RELATIVE_PATH',
                      'JSONCPP_RELATIVE_PATH',
                      'WEBRTC_RELATIVE_PATH',
                      'POSIX',
                      '__STDC_FORMAT_MACROS',
                      'DYNAMIC_ANNOTATIONS_ENABLED=0'
                  ],
                        'include_dirs': [
                            'deps/speex-1.2.0/include',
                            'deps/config/speex-1.2.0/<(OS)/<(target_arch)',
                        ],
              }
  ]
}
复制代码
4 编译

在项目根目录下运行命令

node-gyp configure
node-gyp build
复制代码

如未报错并且根目录下生成build目录:

说明编译成功。若为成功,请详细检查 两个binding.gyp中的目录是否对应正确,注:使用node-gyp需要 python27环境,必须为此版本

5 测试:

新建hello.js 文件内容如下

const hello = require('./build/Release/hello');
hello.add('a.pcm', "bloom.encode");
复制代码

文件运行后会将male.wav文件压缩,并生成male.test文件 效果如下:

转载于:https://juejin.im/post/5cb6e2e56fb9a068b52fb9cd

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
node-stream-zip 是查看和提取大型 ZIP 文件Node.js 库。特性:从不加载完整的归档到内存,一切都是通过块读取大型归档支持所有操作都是非阻塞,非同步 i/o快速初始化无依赖,无二进制组件内置 zlib 模块解压deflate, deflate64, sfx, macosx/windows 内置归档ZIP64 支持安装$ npm install node-stream-zip使用var StreamZip = require('node-stream-zip');   var zip = new StreamZip({       file: 'archive.zip',       storeEntries: true     }); zip.on('error', function(err) { /*handle*/ }); zip.on('ready', function() {     console.log('Entries read: '   zip.entriesCount);     // stream to stdout     zip.stream('node/benchmark/net/tcp-raw-c2s.js', function(err, stm) {         stm.pipe(process.stdout);     });     // extract file     zip.extract('node/benchmark/net/tcp-raw-c2s.js', './temp/', function(err) {         console.log('Entry extracted');     });     // extract folder     zip.extract('node/benchmark/', './temp/', function(err, count) {         console.log('Extracted '   count   ' entries');     });     // extract all     zip.extract(null, './temp/', function(err, count) {         console.log('Extracted '   count   ' entries');     });     // read file as buffer in sync way     var data = zip.entryDataSync('README.md'); }); zip.on('extract', function(entry, file) {     console.log('Extracted '   entry.name   ' to '   file); }); zip.on('entry', function(entry) {     // called on load, when entry description has been read     // you can already stream this entry, without waiting until all entry descriptions are read (suitable for very large archives)      console.log('Read entry ', entry.name); });

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值