Comments (12)
Hmm, I think you could use OpenVirtual There's an example in the tests: https://github.com/mkb218/gosndfile/blob/master/sndfile/virtual_test.go which you could probably pattern off of. I would use a bytes.Reader to encapsulate your byte array.
from gosndfile.
Thank you very much for your answer.
I read the tests. It's too complexed for me.
Can you write a little example?
from gosndfile.
I'll try later tonight.
from gosndfile.
that would be great.
I'm waiting for your answer.
from gosndfile.
Argh, I'm finding that the tests aren't passing against current libsndfile. It might be some time before I can get you a working example. Here's where I would start, but keep in mind that this panics for reasons I'm not sure about: https://gist.github.com/mkb218/fb442d05488aee5cd4b4fafc7e8275e0
from gosndfile.
Thank you. I will work this topic.
from gosndfile.
Now I have written a sample that really works but this does not work correctly for Go 1.5 and above.
Many things have changed in that release.
We can pass any Go expression to C, but c is prohibited from storing it.
How can we write callbacks better for Go 1.6>?
from gosndfile.
That's frustrating. I may have some time to look at after this weekend.
from gosndfile.
I'm currently trying to get the same accomplished. I found a hint on StackOverflow that there are disadvantages when using sf_open_virtual()
as it would make libsndfile assume that the input is seekable (which it might not be). One is supposed to use sf_open_fd()
instead.
Due to this (assumed) disadvantage in seekability and the fact that there still seems to be an issue using gosndfile's OpenVirtual (as described by the previous comments), I'm currently looking to implement my use case using memfds.
Note: I haven't verified any of this, I'm just sharing what I've found so far in the hope that it might help you as well.
from gosndfile.
Go's rules are very strict. I think we should rewrite the callback system.
If the problem is with reading bytes, then I don't know what can be done.
Is it possible to understand where the problem is?
panic
does not print a good output.
from gosndfile.
Hi @mkb218 and all,
I found a solution. The problem seemed to be sending interfaces to C.
Sory. English is not my native language :) .
I used it with OpenAL. You will also see other things in the code. However, if you delete OpenAL, you can still use it normally.
And my advice is that we shouldn't use interfaces. We need to use some global variables.
Is such a PR acceptable?
I will consider to implement this.
And I used some code in this package. I hope licensing is ok.
main go code:
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)
}
extras.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 (header file):
#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
from gosndfile.
Hey @mkb218, I'll send pr if this is applicable. Otherwise, I will close the issue.
from gosndfile.
Related Issues (13)
- Channel Maps support
- go 1.2 breaks gosndfile HOT 2
- python scikits.audiolab Sndfile special chars in file name HOT 1
- could not determine kind of name for C.uint32_t HOT 5
- Reasonable test completeness
- Support dithering commands
- Fix sErrorType
- Support Go v1 HOT 2
- Weekly 2011-10-06 changes math.Fabs to math.Abs HOT 1
- AIFF loop bug
- Some kind of segfault / mysterious problem. HOT 3
- 'go get' fails to install, gcc says C '#import' is deprecated HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from gosndfile.