亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

如何使用 libsndfile 打開加載到內存中的聲音文件?

如何使用 libsndfile 打開加載到內存中的聲音文件?

Go
米琪卡哇伊 2022-07-11 16:48:13
為了理解這一點,我想講述以下場景:我設計了一個游戲并完成了它。我用 AES 加密了音頻數據。然后我將在游戲打開時解密這些加密文件。這些文件在內存中以字節編碼。例如,我想為 OpenAL 創建緩沖區。注意:這里沒有加密功能。因為我的例子會很復雜和困難。項目文件夾:main.go鳥22.wavlibsndfile-1.dllsndfile.h我的構建命令:go build .我不是經驗豐富的 C 開發人員。這就是我與 CGo 合作的原因。但我會嘗試使 C 代碼適應 CGO,這解釋了如何做到這一點。我使用的源代碼和我嘗試調整的代碼: libsndfile virtualio test gosndfile virtualio test
查看完整描述

1 回答

?
揚帆大魚

TA貢獻1799條經驗 獲得超9個贊

這是一個解決方案。如果要使用它,必須將 libsndfile 和 openal '庫放在正確的位置。

使用 Go 15.2 64 位測試。

我是 Windows 用戶。

從虛擬源讀取文件,打印信息(通道、幀、可搜索等)并使用 OpenAL 播放。還有 GitHub 上的問題。閱讀可能會有所幫助。#16


主要代碼:


package main


// #cgo CFLAGS: -Wall -O3 -Iinclude

// #cgo LDFLAGS: -O3 -L. -llibsndfile-1 -lopenal32

/*

    #include "extras.h"


    #include "sndfile.h"

    #include "stdlib.h"


    #include "AL/al.h"

    #include "AL/alc.h"

    #include "AL/alext.h"

*/

import "C"


import (

    "fmt"

    "unsafe"

    "io/ioutil"

    "bytes"

    "time"

    "os"

    "./oal"

)


type MyData struct {

    MyBytes     *bytes.Reader

    Count       int64

}



func main() {

fullFileByte, err := ioutil.ReadFile(os.Args[1]); errHandler(err)

    reader := bytes.NewReader(fullFileByte)



    // file info (Channels, frames, seekable etc...)

    var myInfo Info


    data := &MyData{MyBytes: reader, Count: 0}



    getLen :=  func() int64 {

        l := data.MyBytes.Len()

        println("Lenght:", l)

        return int64(l)

        }


    vRead := func(o []byte) int64 {

        //println("Read:", data.Count)

        i, _ := data.MyBytes.Read(o) // ; errHandler(err)

        data.Count += int64(i)

        return int64(i)

    }


seek := func(offset int64, whence int) int64 {

        println("Seek:", data.Count)

        goWhence := whence

        data.Count, _ = data.MyBytes.Seek(offset, goWhence) // ; errHandler(err)

        return data.Count

    }


tell := func() int64 {

        println("Tell: ", data.Count)

        return data.Count

    }



globVB.GetFileLen = getLen

    globVB.Read = vRead

    globVB.Seek = seek

globVB.Tell = tell



    f := OpenVirtual(ModeRead, &myInfo)


    fmt.Println("Channel:", myInfo.Channels, "\nFrames:", myInfo.Frames, "\nFormat:", myInfo.Format, "\nSections:", myInfo.Sections, "\nSample Rate:", myInfo.Samplerate, "\nSeekable:", myInfo.Seekable)


    s := Source{}


    s.Create(uint32(C.CreateVirtualBuffer(f.SFile, *myInfo.fromGoToCInfo())))

        s.Play()


    for {


        time.Sleep(500 * time.Millisecond)

        }

}



func OpenVirtual(mode FMode, info* Info) File { // File



We're tricking the libsndfile. It's actually unnecessary code.

    var vb *C.VirtualCallbacks



    var file File


    // Go → C

    cInfo := info.fromGoToCInfo()


    cVirtualIO := C.NewVirtualIO()




    file.SFile = C.sf_open_virtual(cVirtualIO, C.int(mode), cInfo, (unsafe.Pointer)(vb))


    if file.SFile == nil {

        panic(C.GoString(C.sf_strerror(file.SFile)))

    }

    *info = fromCToGo(cInfo)

    return file

}




type File struct {

    SFile*      C.SNDFILE

}




type Info struct {

    Frames      int64

    Samplerate      int

    Channels        int

    Format      int

    Sections        int

    Seekable        int

}


func (s Info) fromGoToCInfo() *C.SF_INFO {

    val := new(C.SF_INFO)

    val.frames = C.sf_count_t(s.Frames)

        val.samplerate = C.int(s.Samplerate)

    val.channels = C.int(s.Channels)

    val.format = C.int(s.Format)

    val.sections = C.int(s.Sections)

    val.seekable = C.int(s.Seekable)

    return val

}



type SFile C.SNDFILE




func fromCToGo(info* C.SF_INFO) Info {

    val := Info{}

    val.Frames = int64(info.frames)

    val.Samplerate = int(info.samplerate)

    val.Channels = int(info.channels)

    val.Format = int(info.format)

    val.Sections = int(info.sections)

    val.Seekable = int(info.seekable)

    return val

}



// File modes: read, write and readwrite

type FMode int


const (

    ModeRead        FMode = C.SFM_READ

    ModeWrite       FMode = C.SFM_WRITE

    ModeReadWrite       FMode = C.SFM_RDWR

)


func errHandler(e error) {

if e != nil {

        panic(e)

}

}



func init() {

    device, err := oal.OpenDevice("")

    errHandler(err)

    ctx, err := oal.CreateContext(device, nil)

    errHandler(err)

    oal.MakeContextCurrent(ctx)

}




type TGetFileLen func() int64


type TVioSeek func(offset int64, whence int) int64


type TVioRead func(o []byte) int64


type TVioWrite func( ptr unsafe.Pointer, count int64, user_data unsafe.Pointer)


type TVioTell func() int64



type SVirtualIO struct {

    GetFileLen      TGetFileLen

    Seek        TVioSeek

    Read        TVioRead

    Write       TVioWrite

    Tell        TVioTell

    // Data     interface{}

}


var globVB  SVirtualIO


//export goVirtualRead

func goVirtualRead(buffPtr unsafe.Pointer, count int64, data unsafe.Pointer) int64 {

    byteBuff := (*[1 << 31]byte) (buffPtr)[0:count]


    return globVB.Read(byteBuff)

    }



//export goGetLen

func goGetLen(userData unsafe.Pointer) int64 {


    return globVB.GetFileLen()

}


//export goVirtualSeek

func goVirtualSeek(offset int64,  whence int, userData unsafe.Pointer) int64 {


    return globVB.Seek(offset, whence)

}


//export goVirtualTell

func goVirtualTell(userData unsafe.Pointer) int64 {

    

    return globVB.Tell()

}


type Source struct {

    Source      C.ALuint

    Buffer      C.ALuint

}



func (s Source) Delete() {

    C.alDeleteSources(1, &s.Source)

    C.alDeleteBuffers(1, &s.Buffer)

}


func (s* Source) Create(b uint32) {

        var source C.ALuint

    var buffer C.ALuint = C.ALuint(b)

    source = 0

    C.alGenSources(1, &source)


    C.alSourcei(source, C.AL_BUFFER, C.ALint(buffer))


    s.Source = source

    s.Buffer = buffer

}


func (s Source) Play() {

        C.alSourcePlay(s.Source)

}

額外的.c:


#include <stdio.h>

#include <string.h>

#include <stdlib.h>

#include "extras.h"

#include "_cgo_export.h"


    #include "sndfile.h"


#include "AL/al.h"

#include "AL/alc.h"


    sf_count_t

    virtualRead(void *ptr, sf_count_t count, void *userData) {

        return goVirtualRead(ptr, count, userData);

    }



    sf_count_t

    virtualGetFileLen(void *udata) {

        return goGetLen(udata);

    }



    sf_count_t

virtualSeek(sf_count_t offset, int whence, void *user_data) {

    return goVirtualSeek(offset, whence, user_data);

}


sf_count_t

    virtualTell(void *userData) {

        return goVirtualTell(userData);

}


SF_VIRTUAL_IO*

NewVirtualIO() {

    static SF_VIRTUAL_IO sndVirtualIO;


    sndVirtualIO.read = virtualRead;


    sndVirtualIO.get_filelen  = virtualGetFileLen;

    sndVirtualIO.seek = virtualSeek;

    sndVirtualIO.tell = virtualTell;


//  sndVirtualIO.write= virtualWrite;

    return &sndVirtualIO;

}




ALuint

CreateVirtualBuffer(SNDFILE *file, SF_INFO info) {

    ALenum err, format;

    ALuint buffer;

    SNDFILE *sndfile;

    SF_INFO sfinfo;

    sfinfo = info;


    short *membuf;

    sf_count_t num_frames;

    ALsizei num_bytes;


    sndfile = file;

    if(!sndfile)  {

        return 0;

    }

    if(sfinfo.channels == 1)

        format = AL_FORMAT_MONO16;

    else if(sfinfo.channels == 2)

        format = AL_FORMAT_STEREO16;

    else {

        sf_close(sndfile);

        return 0;

    }


    membuf = malloc((size_t)(sfinfo.frames * sfinfo.channels) * sizeof(short));


    num_frames = sf_readf_short(sndfile, membuf, sfinfo.frames);

    if(num_frames < 1)

    {

        free(membuf);

        sf_close(sndfile);

        return 0;

    }

    num_bytes = (ALsizei)(num_frames * sfinfo.channels) * (ALsizei)sizeof(short);


    buffer = 0;

    alGenBuffers(1, &buffer);

    alBufferData(buffer, format, membuf, num_bytes, sfinfo.samplerate);


    free(membuf);

    sf_close(sndfile);


    err = alGetError();

    if(err != AL_NO_ERROR) {

        if(buffer && alIsBuffer(buffer))

            alDeleteBuffers(1, &buffer);

        return 0;

    }


    return buffer;

}


extras.h(頭文件):


#ifndef EXTRAS_H

#define EXTRAS_H



#include "sndfile.h"


#include "AL/al.h"

#include "AL/alc.h"


// **redundant code. Because NULL is not accepted. :)


typedef sf_count_t (*goreadfunc)(void* sf_count_t, void*);


struct VirtualCallbacks {

    goreadfunc      vRead;

    sf_vio_get_filelen      vGetFileLen;

    sf_vio_seek     vSeek;

    sf_vio_write        vWrite;


};


typedef struct VirtualCallbacks VirtualCallbacks;




sf_count_t goVirtualRead(void *ptr, sf_count_t count, void *user_data);



SF_VIRTUAL_IO*

NewVirtualIO(void);


ALuint

CreateVirtualBuffer(SNDFILE *file, SF_INFO info);


#endif


查看完整回答
反對 回復 2022-07-11
  • 1 回答
  • 0 關注
  • 202 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號