mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-24 18:58:54 +01:00
audio/mp3: Move Decode_L3 to Go
This commit is contained in:
parent
1c86a90c8e
commit
e53d5920b0
@ -17,11 +17,14 @@
|
|||||||
package mp3
|
package mp3
|
||||||
|
|
||||||
// #include "pdmp3.h"
|
// #include "pdmp3.h"
|
||||||
|
//
|
||||||
|
// //extern t_mpeg1_main_data g_main_data;
|
||||||
|
// extern t_mpeg1_header g_frame_header;
|
||||||
|
// //extern t_mpeg1_side_info g_side_info;
|
||||||
import "C"
|
import "C"
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@ -36,6 +39,57 @@ var (
|
|||||||
writer io.Writer
|
writer io.Writer
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func decodeL3() error {
|
||||||
|
out := make([]int, 576)
|
||||||
|
/* Number of channels(1 for mono and 2 for stereo) */
|
||||||
|
nch := 2
|
||||||
|
if C.g_frame_header.mode == C.mpeg1_mode_single_channel {
|
||||||
|
nch = 1
|
||||||
|
}
|
||||||
|
for gr := 0; gr < 2; gr++ {
|
||||||
|
for ch := 0; ch < nch; ch++ {
|
||||||
|
L3_Requantize(C.uint(gr), C.uint(ch)) /* Requantize samples */
|
||||||
|
L3_Reorder(C.uint(gr), C.uint(ch)) /* Reorder short blocks */
|
||||||
|
}
|
||||||
|
L3_Stereo(C.uint(gr)) /* Stereo processing */
|
||||||
|
for ch := 0; ch < nch; ch++ {
|
||||||
|
L3_Antialias(C.uint(gr), C.uint(ch))
|
||||||
|
// (IMDCT,windowing,overlapp add)
|
||||||
|
L3_Hybrid_Synthesis(C.uint(gr), C.uint(ch))
|
||||||
|
L3_Frequency_Inversion(C.uint(gr), C.uint(ch))
|
||||||
|
// Polyphase subband synthesis
|
||||||
|
l3SubbandSynthesis(gr, ch, out)
|
||||||
|
}
|
||||||
|
if err := audioWriteRaw(out); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func audioWriteRaw(samples []int) error {
|
||||||
|
nch := 2
|
||||||
|
if C.g_frame_header.mode == C.mpeg1_mode_single_channel {
|
||||||
|
nch = 1
|
||||||
|
}
|
||||||
|
s := make([]uint8, len(samples)*2*nch)
|
||||||
|
for i, v := range samples {
|
||||||
|
if nch == 1 {
|
||||||
|
s[2*i] = uint8(v)
|
||||||
|
s[2*i+1] = uint8(v >> 8)
|
||||||
|
} else {
|
||||||
|
s[4*i] = uint8(v)
|
||||||
|
s[4*i+1] = uint8(v >> 8)
|
||||||
|
s[4*i+2] = uint8(v >> 16)
|
||||||
|
s[4*i+3] = uint8(v >> 24)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, err := writer.Write(s); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func getByte() (uint8, error) {
|
func getByte() (uint8, error) {
|
||||||
for len(readerCache) == 0 && !readerEOF {
|
for len(readerCache) == 0 && !readerEOF {
|
||||||
buf := make([]uint8, 4096)
|
buf := make([]uint8, 4096)
|
||||||
@ -77,23 +131,16 @@ func Get_Filepos() C.unsigned {
|
|||||||
return C.unsigned(readerPos)
|
return C.unsigned(readerPos)
|
||||||
}
|
}
|
||||||
|
|
||||||
//export writeToWriter
|
|
||||||
func writeToWriter(data unsafe.Pointer, size C.int) C.size_t {
|
|
||||||
buf := C.GoBytes(data, size)
|
|
||||||
n, err := writer.Write(buf)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
return C.size_t(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
func decode(r io.Reader, w io.Writer) error {
|
func decode(r io.Reader, w io.Writer) error {
|
||||||
|
// TODO: Decoder should know number of channels
|
||||||
reader = r
|
reader = r
|
||||||
writer = w
|
writer = w
|
||||||
for Get_Filepos() != eof {
|
for Get_Filepos() != eof {
|
||||||
err := readFrame()
|
err := readFrame()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
C.Decode_L3()
|
if err := decodeL3(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if Get_Filepos() == eof {
|
if Get_Filepos() == eof {
|
||||||
|
@ -25,7 +25,6 @@ import "C"
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"unsafe"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -565,13 +564,7 @@ var g_synth_dtbl = [512]float32{
|
|||||||
0.000015259, 0.000015259, 0.000015259, 0.000015259,
|
0.000015259, 0.000015259, 0.000015259, 0.000015259,
|
||||||
}
|
}
|
||||||
|
|
||||||
//export L3_Subband_Synthesis
|
func l3SubbandSynthesis(gr int, ch int, out []int) {
|
||||||
func L3_Subband_Synthesis(gr C.unsigned, ch C.unsigned, outdata *C.unsigned) {
|
|
||||||
out := make([]C.unsigned, 576)
|
|
||||||
for i := range out {
|
|
||||||
out[i] = *(*C.unsigned)(unsafe.Pointer(uintptr(unsafe.Pointer(outdata)) + uintptr(i)*unsafe.Sizeof(*outdata)))
|
|
||||||
}
|
|
||||||
|
|
||||||
u_vec := make([]float32, 512)
|
u_vec := make([]float32, 512)
|
||||||
s_vec := make([]float32, 32)
|
s_vec := make([]float32, 32)
|
||||||
|
|
||||||
@ -620,16 +613,13 @@ func L3_Subband_Synthesis(gr C.unsigned, ch C.unsigned, outdata *C.unsigned) {
|
|||||||
if ch == 0 { /* This function must be called for channel 0 first */
|
if ch == 0 { /* This function must be called for channel 0 first */
|
||||||
/* We always run in stereo mode,& duplicate channels here for mono */
|
/* We always run in stereo mode,& duplicate channels here for mono */
|
||||||
if nch == 1 {
|
if nch == 1 {
|
||||||
out[32*ss+i] = C.unsigned((samp << 16) | (samp))
|
out[32*ss+i] = (samp << 16) | (samp)
|
||||||
} else {
|
} else {
|
||||||
out[32*ss+i] = C.unsigned(samp << 16)
|
out[32*ss+i] = samp << 16
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
out[32*ss+i] |= C.unsigned(samp)
|
out[32*ss+i] |= samp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for i := range out {
|
|
||||||
*(*C.unsigned)(unsafe.Pointer(uintptr(unsafe.Pointer(outdata)) + uintptr(i)*unsafe.Sizeof(*outdata))) = out[i]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -41,9 +41,7 @@ static void dmp_samples(t_mpeg1_main_data *md,int gr,int ch,int type);
|
|||||||
|
|
||||||
static void audio_write(unsigned *samples,unsigned nsamples,int sample_rate);
|
static void audio_write(unsigned *samples,unsigned nsamples,int sample_rate);
|
||||||
static void audio_write_raw(unsigned *samples,unsigned nsamples);
|
static void audio_write_raw(unsigned *samples,unsigned nsamples);
|
||||||
static void Decode_L3_Init_Song(void);
|
|
||||||
static void Error(const char *s,int e);
|
static void Error(const char *s,int e);
|
||||||
static void Read_Ancillary(void);
|
|
||||||
|
|
||||||
static const unsigned g_mpeg1_bitrates[3 /* layer 1-3 */][15 /* header bitrate_index */] = {
|
static const unsigned g_mpeg1_bitrates[3 /* layer 1-3 */][15 /* header bitrate_index */] = {
|
||||||
{ /* Layer 1 */
|
{ /* Layer 1 */
|
||||||
@ -159,51 +157,6 @@ static void dmp_samples(t_mpeg1_main_data *md,int gr,int ch,int type){
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/**Description: decodes a layer 3 bitstream into audio samples.
|
|
||||||
* Parameters: Outdata vector.
|
|
||||||
* Return value: OK or ERROR if the frame contains errors.
|
|
||||||
* Author: Krister Lagerström(krister@kmlager.com) **/
|
|
||||||
int Decode_L3(void){
|
|
||||||
unsigned gr,ch,nch,out[576];
|
|
||||||
|
|
||||||
/* Number of channels(1 for mono and 2 for stereo) */
|
|
||||||
nch =(g_frame_header.mode == mpeg1_mode_single_channel ? 1 : 2);
|
|
||||||
for(gr = 0; gr < 2; gr++) {
|
|
||||||
for(ch = 0; ch < nch; ch++) {
|
|
||||||
dmp_scf(&g_side_info,&g_main_data,gr,ch); //noop unless debug
|
|
||||||
dmp_huff(&g_main_data,gr,ch); //noop unless debug
|
|
||||||
L3_Requantize(gr,ch); /* Requantize samples */
|
|
||||||
dmp_samples(&g_main_data,gr,ch,0); //noop unless debug
|
|
||||||
L3_Reorder(gr,ch); /* Reorder short blocks */
|
|
||||||
} /* end for(ch... */
|
|
||||||
L3_Stereo(gr); /* Stereo processing */
|
|
||||||
dmp_samples(&g_main_data,gr,0,1); //noop unless debug
|
|
||||||
dmp_samples(&g_main_data,gr,1,1); //noop unless debug
|
|
||||||
for(ch = 0; ch < nch; ch++) {
|
|
||||||
L3_Antialias(gr,ch); /* Antialias */
|
|
||||||
dmp_samples(&g_main_data,gr,ch,2); //noop unless debug
|
|
||||||
L3_Hybrid_Synthesis(gr,ch); /*(IMDCT,windowing,overlapp add) */
|
|
||||||
L3_Frequency_Inversion(gr,ch); /* Frequency inversion */
|
|
||||||
dmp_samples(&g_main_data,gr,ch,3); //noop unless debug
|
|
||||||
L3_Subband_Synthesis(gr,ch,out); /* Polyphase subband synthesis */
|
|
||||||
} /* end for(ch... */
|
|
||||||
#ifdef DEBUG
|
|
||||||
{
|
|
||||||
int i,ctr = 0;
|
|
||||||
printf("PCM:\n");
|
|
||||||
for(i = 0; i < 576; i++) {
|
|
||||||
printf("%d: %d\n",ctr++,(out[i] >> 16) & 0xffff);
|
|
||||||
if(nch == 2) printf("%d: %d\n",ctr++,out[i] & 0xffff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* DEBUG */
|
|
||||||
/*FIXME - replace with simple interface stream*/
|
|
||||||
audio_write((unsigned *) out,576,
|
|
||||||
g_sampling_frequency[g_frame_header.sampling_frequency]);
|
|
||||||
} /* end for(gr... */
|
|
||||||
return(OK); /* Done */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**Description: TBD
|
/**Description: TBD
|
||||||
* Parameters: TBD
|
* Parameters: TBD
|
||||||
* Return value: TBD
|
* Return value: TBD
|
||||||
@ -212,52 +165,3 @@ static void Error(const char *s,int e){
|
|||||||
(void) fwrite(s,1,strlen(s),stderr);
|
(void) fwrite(s,1,strlen(s),stderr);
|
||||||
exit(e);
|
exit(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Description: output audio data
|
|
||||||
* Parameters: Pointers to the samples,the number of samples
|
|
||||||
* Return value: None
|
|
||||||
* Author: Krister Lagerström(krister@kmlager.com) **/
|
|
||||||
static void audio_write(unsigned *samples,unsigned nsamples,int sample_rate){
|
|
||||||
static int init = 0,audio,curr_sample_rate = 0;
|
|
||||||
int tmp,dsp_speed = 44100,dsp_stereo = 2;
|
|
||||||
|
|
||||||
#ifdef OUTPUT_RAW
|
|
||||||
audio_write_raw(samples,nsamples);
|
|
||||||
#endif /* OUTPUT_RAW */
|
|
||||||
return;
|
|
||||||
} /* audio_write() */
|
|
||||||
|
|
||||||
/******************************************************************************
|
|
||||||
*
|
|
||||||
* Name: audio_write_raw
|
|
||||||
* Author: Krister Lagerström(krister@unidata.se)
|
|
||||||
* Description: This function is used to output raw data
|
|
||||||
* Parameters: Pointers to the samples,the number of samples
|
|
||||||
* Return value: None
|
|
||||||
* Revision History:
|
|
||||||
* Author Date Change
|
|
||||||
* krister 010101 Initial revision
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
static void audio_write_raw(unsigned *samples,unsigned nsamples){
|
|
||||||
char fname[1024];
|
|
||||||
unsigned lo,hi;
|
|
||||||
int i,nch;
|
|
||||||
unsigned short s[576*2];
|
|
||||||
|
|
||||||
nch =(g_frame_header.mode == mpeg1_mode_single_channel ? 1 : 2);
|
|
||||||
for(i = 0; i < nsamples; i++) {
|
|
||||||
if(nch == 1) {
|
|
||||||
lo = samples[i] & 0xffff;
|
|
||||||
s[i] = lo;
|
|
||||||
}else{
|
|
||||||
lo = samples[i] & 0xffff;
|
|
||||||
hi =(samples[i] & 0xffff0000) >> 16;
|
|
||||||
s[2*i] = hi;
|
|
||||||
s[2*i+1] = lo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(writeToWriter((char *) s,nsamples * 2 * nch) != nsamples * 2 * nch)
|
|
||||||
Error("Unable to write raw data\n",-1);
|
|
||||||
return;
|
|
||||||
} /* audio_write_raw() */
|
|
||||||
|
@ -85,21 +85,16 @@ typedef struct { /* Scale factor band indices,for long and short windows */
|
|||||||
t_sf_band_indices;
|
t_sf_band_indices;
|
||||||
|
|
||||||
unsigned Get_Filepos(void);
|
unsigned Get_Filepos(void);
|
||||||
int Decode_L3(void);
|
|
||||||
size_t writeToWriter(void* data, int size);
|
|
||||||
|
|
||||||
unsigned Get_Main_Pos(void);
|
unsigned Get_Main_Pos(void);
|
||||||
int Set_Main_Pos(unsigned bit_pos);
|
int Set_Main_Pos(unsigned bit_pos);
|
||||||
|
|
||||||
int Read_Audio_L3(void);
|
|
||||||
|
|
||||||
void L3_Requantize(unsigned gr,unsigned ch);
|
void L3_Requantize(unsigned gr,unsigned ch);
|
||||||
void L3_Reorder(unsigned gr,unsigned ch);
|
void L3_Reorder(unsigned gr,unsigned ch);
|
||||||
void L3_Stereo(unsigned gr);
|
void L3_Stereo(unsigned gr);
|
||||||
void L3_Antialias(unsigned gr,unsigned ch);
|
void L3_Antialias(unsigned gr,unsigned ch);
|
||||||
void L3_Hybrid_Synthesis(unsigned gr,unsigned ch);
|
void L3_Hybrid_Synthesis(unsigned gr,unsigned ch);
|
||||||
void L3_Frequency_Inversion(unsigned gr,unsigned ch);
|
void L3_Frequency_Inversion(unsigned gr,unsigned ch);
|
||||||
void L3_Subband_Synthesis(unsigned gr,unsigned ch, unsigned* outdata);
|
|
||||||
|
|
||||||
int Read_CRC(void);
|
int Read_CRC(void);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user