1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
|
package stb_vorbis
/*
#include "stb_vorbis.h"
#include <stdlib.h>
#cgo LDFLAGS: -lm
*/
import "C"
import (
"errors"
"fmt"
"reflect"
"unsafe"
)
type Info struct {
SampleRate uint
Channels int
}
type Decoder struct {
Ptr unsafe.Pointer
}
func (v Decoder) native() *C.stb_vorbis {
return (*C.stb_vorbis)(v.Ptr)
}
func wrapDecoder(ptr *C.stb_vorbis) Decoder {
return Decoder{Ptr: unsafe.Pointer(ptr)}
}
func OpenFile(filename string) (Decoder, error) {
filename0 := C.CString(filename)
var errCode C.int
ret := C.stb_vorbis_open_filename(filename0, &errCode, nil)
C.free(unsafe.Pointer(filename0))
if errCode != 0 {
return Decoder{}, Error{Code: int(errCode)}
}
return wrapDecoder(ret), nil
}
func DecodeFile(filename string) (result []int16, channels int, sampleRate int, err error) {
filename0 := C.CString(filename)
var channels0 C.int
var sampleRate0 C.int
var output *C.short
ret := C.stb_vorbis_decode_filename(filename0, &channels0, &sampleRate0, &output)
C.free(unsafe.Pointer(filename0))
if ret < 0 {
return nil, 0, 0, errors.New("decode filename error")
}
var slice []C.short
setSliceDataLen(unsafe.Pointer(&slice), unsafe.Pointer(output), int(ret*channels0))
result = make([]int16, len(slice))
for i, v := range slice {
result[i] = int16(v)
}
return result, int(channels0), int(sampleRate0), nil
}
func setSliceDataLen(pSlice, pData unsafe.Pointer, len int) {
header := (*reflect.SliceHeader)(pSlice)
header.Cap = len
header.Len = len
header.Data = uintptr(pData)
}
func (d Decoder) Close() {
C.stb_vorbis_close(d.native())
}
const (
NoError = C.VORBIS__no_error
NeedMoreData = C.VORBIS_need_more_data
InvalidAPIMixing = C.VORBIS_invalid_api_mixing
OutOfMem = C.VORBIS_outofmem
FeatureNotSupported = C.VORBIS_feature_not_supported
TooManyChannels = C.VORBIS_too_many_channels
FileOpenFailure = C.VORBIS_file_open_failure
SeekWithoutLength = C.VORBIS_seek_without_length
UnexpectedEOF = C.VORBIS_unexpected_eof
SeekInvalid = C.VORBIS_seek_invalid
// vorbis errors:
InvalidSetup = C.VORBIS_invalid_setup
InvalidStream = C.VORBIS_invalid_stream
// ogg errors:
MissingCapturePattern = C.VORBIS_missing_capture_pattern
InvalidStreamStructureVersion = C.VORBIS_invalid_stream_structure_version
InvalidContinuedPacketFlag = C.VORBIS_continued_packet_flag_invalid
IncorrectStreamSerialNumber = C.VORBIS_incorrect_stream_serial_number
InvalidFirstPage = C.VORBIS_invalid_first_page
BadPacketType = C.VORBIS_bad_packet_type
CantFindLastPage = C.VORBIS_cant_find_last_page
SeekFailed = C.VORBIS_seek_failed
)
type Error struct {
Code int
}
func (err Error) Error() string {
switch err.Code {
case NeedMoreData:
return "need more data"
case FeatureNotSupported:
return "feature not supported"
case FileOpenFailure:
return "file open failure"
case InvalidAPIMixing:
return "invalid API mixing"
case OutOfMem:
return "out of memory"
case SeekInvalid:
return "seek invalid"
case SeekWithoutLength:
return "seek without length"
case TooManyChannels:
return "too many channels"
case UnexpectedEOF:
return "unexpected EOF"
case InvalidSetup:
return "invalid setup"
case InvalidStream:
return "invalid stream"
case MissingCapturePattern:
return "ogg missing capture pattern"
case InvalidStreamStructureVersion:
return "ogg invalid stream structure version"
case InvalidContinuedPacketFlag:
return "ogg invalid continued packet flag"
case IncorrectStreamSerialNumber:
return "ogg incorrect stream serial number"
case InvalidFirstPage:
return "ogg invalid first page"
case BadPacketType:
return "ogg bad packet type"
case CantFindLastPage:
return "ogg can't find last page"
case SeekFailed:
return "ogg seek failed"
}
return fmt.Sprintf("other vorbis error(%d)", err.Code)
}
func (d Decoder) GetError() error {
ret := C.stb_vorbis_get_error(d.native())
if ret == NoError {
return nil
}
return Error{
Code: int(ret),
}
}
func (d Decoder) GetInfo() Info {
ret := C.stb_vorbis_get_info(d.native())
return Info{
SampleRate: uint(ret.sample_rate),
Channels: int(ret.channels),
}
}
func (d Decoder) StreamLengthInSamples() uint {
ret := C.stb_vorbis_stream_length_in_samples(d.native())
return uint(ret)
}
func (d Decoder) GetSamplesShortInterleaved(channels int, buffer []byte) int {
buf := (*C.short)(unsafe.Pointer(&buffer[0]))
ret := C.stb_vorbis_get_samples_short_interleaved(d.native(), C.int(channels), buf, C.int(len(buffer)/2))
return int(ret)
}
|