-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathlame.go
238 lines (193 loc) · 4.61 KB
/
lame.go
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
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
package lame
// http://www.leidinger.net/lame/doxy/html/lame_8h-source.html
/*
#cgo LDFLAGS: -lmp3lame
#include "lame/lame.h"
*/
import "C"
import (
"runtime"
"unsafe"
)
type Handle *C.struct_lame_global_struct
const (
STEREO = C.STEREO
JOINT_STEREO = C.JOINT_STEREO
DUAL_CHANNEL = C.DUAL_CHANNEL /* LAME doesn't supports this! */
MONO = C.MONO
NOT_SET = C.NOT_SET
MAX_INDICATOR = C.MAX_INDICATOR
BIT_DEPTH = 16
VBR_OFF = C.vbr_off
VBR_RH = C.vbr_rh
VBR_ABR = C.vbr_abr
VBR_MTRH = C.vbr_mtrh
VBR_DEFAULT = C.vbr_default
MAX_FRAME_SIZE = 2880
)
const (
ABR_8 = C.ABR_8
ABR_320 = C.ABR_320
V9 = C.V9
VBR_10 = C.VBR_10
V8 = C.V8
VBR_20 = C.VBR_20
V7 = C.V7
VBR_30 = C.VBR_30
V6 = C.V6
VBR_40 = C.VBR_40
V5 = C.V5
VBR_50 = C.VBR_50
V4 = C.V4
VBR_60 = C.VBR_60
V3 = C.V3
VBR_70 = C.VBR_70
V2 = C.V2
VBR_80 = C.VBR_80
V1 = C.V1
VBR_90 = C.VBR_90
V0 = C.V0
VBR_100 = C.VBR_100
)
type Encoder struct {
handle Handle
remainder []byte
closed bool
}
func Init() *Encoder {
handle := C.lame_init()
encoder := &Encoder{handle, make([]byte, 0), false}
runtime.SetFinalizer(encoder, finalize)
return encoder
}
func (e *Encoder) SetVBR(mode C.vbr_mode) {
C.lame_set_VBR(e.handle, mode)
}
func (e *Encoder) SetVBRAverageBitRate(averageBitRate int) {
C.lame_set_VBR_mean_bitrate_kbps(e.handle, C.int(averageBitRate))
}
func (e *Encoder) SetVBRQuality(quality int) {
C.lame_set_VBR_q(e.handle, C.int(quality))
}
func (e *Encoder) SetLowPassFrequency(frequency int) {
// Frequency in Hz
C.lame_set_lowpassfreq(e.handle, C.int(frequency))
}
func (e *Encoder) SetNumChannels(num int) {
C.lame_set_num_channels(e.handle, C.int(num))
}
func (e *Encoder) SetInSamplerate(sampleRate int) {
C.lame_set_in_samplerate(e.handle, C.int(sampleRate))
}
func (e *Encoder) SetBitrate(bitRate int) {
C.lame_set_brate(e.handle, C.int(bitRate))
}
func (e *Encoder) SetMode(mode C.MPEG_mode) {
C.lame_set_mode(e.handle, mode)
}
func (e *Encoder) SetQuality(quality int) {
C.lame_set_quality(e.handle, C.int(quality))
}
func (e *Encoder) InitId3Tag() {
C.id3tag_init(e.handle)
}
func (e *Encoder) SetWriteId3tagAutomatic(automaticWriteTag int) {
C.lame_set_write_id3tag_automatic(e.handle, C.int(automaticWriteTag))
}
func (e *Encoder) ID3TagAddV2() {
C.id3tag_add_v2(e.handle)
}
func (e *Encoder) SetbWriteVbrTag(writeVbrTag int) {
C.lame_set_bWriteVbrTag(e.handle, C.int(writeVbrTag))
}
func (e *Encoder) GetLametagFrame() []byte {
tagFrame := make([]byte, MAX_FRAME_SIZE)
tagFrameLen := C.lame_get_lametag_frame(e.handle, (*C.uchar)(unsafe.Pointer(&tagFrame[0])), C.size_t(len(tagFrame)))
return tagFrame[0:tagFrameLen]
}
func (e *Encoder) InitParams() int {
retcode := C.lame_init_params(e.handle)
return int(retcode)
}
func (e *Encoder) NumChannels() int {
n := C.lame_get_num_channels(e.handle)
return int(n)
}
func (e *Encoder) Bitrate() int {
br := C.lame_get_brate(e.handle)
return int(br)
}
func (e *Encoder) Mode() int {
m := C.lame_get_mode(e.handle)
return int(m)
}
func (e *Encoder) Quality() int {
q := C.lame_get_quality(e.handle)
return int(q)
}
func (e *Encoder) InSamplerate() int {
sr := C.lame_get_in_samplerate(e.handle)
return int(sr)
}
func (e *Encoder) Encode(buf []byte) []byte {
if len(e.remainder) > 0 {
buf = append(e.remainder, buf...)
}
if len(buf) == 0 {
return make([]byte, 0)
}
blockAlign := BIT_DEPTH / 8 * e.NumChannels()
remainBytes := len(buf) % blockAlign
if remainBytes > 0 {
e.remainder = buf[len(buf)-remainBytes : len(buf)]
buf = buf[0 : len(buf)-remainBytes]
} else {
e.remainder = make([]byte, 0)
}
numSamples := len(buf) / blockAlign
estimatedSize := int(1.25*float64(numSamples) + 7200)
out := make([]byte, estimatedSize)
cBuf := (*C.short)(unsafe.Pointer(&buf[0]))
cOut := (*C.uchar)(unsafe.Pointer(&out[0]))
var bytesOut C.int
if e.NumChannels() == 1 {
bytesOut = C.int(C.lame_encode_buffer(
e.handle,
cBuf,
nil,
C.int(numSamples),
cOut,
C.int(estimatedSize),
))
} else {
bytesOut = C.int(C.lame_encode_buffer_interleaved(
e.handle,
cBuf,
C.int(numSamples),
cOut,
C.int(estimatedSize),
))
}
return out[0:bytesOut]
}
func (e *Encoder) Flush() []byte {
estimatedSize := 7200
out := make([]byte, estimatedSize)
cOut := (*C.uchar)(unsafe.Pointer(&out[0]))
bytesOut := C.int(C.lame_encode_flush(
e.handle,
cOut,
C.int(estimatedSize),
))
return out[0:bytesOut]
}
func (e *Encoder) Close() {
if e.closed {
return
}
C.lame_close(e.handle)
e.closed = true
}
func finalize(e *Encoder) {
e.Close()
}