diff --git a/cmd/convert_mp3.go b/cmd/convert_mp3.go index c5373d2..b9aa1d0 100644 --- a/cmd/convert_mp3.go +++ b/cmd/convert_mp3.go @@ -1,5 +1,3 @@ -//go:build !windows - package cmd import ( @@ -8,9 +6,9 @@ import ( "log" "os" + "github.com/braheezy/goqoa/pkg/mp3" "github.com/braheezy/goqoa/pkg/qoa" "github.com/tosone/minimp3" - "github.com/viert/go-lame" ) func decodeMp3(inputData *[]byte) ([]int16, *qoa.QOA) { @@ -39,27 +37,13 @@ func decodeMp3(inputData *[]byte) ([]int16, *qoa.QOA) { func encodeMp3(outputFile string, q *qoa.QOA, decodedData []int16) { fmt.Println("Output format is MP3") + mp3File, err := os.Create(outputFile) if err != nil { log.Fatalf("Error creating MP3 file: %v", err) } defer mp3File.Close() + mp3Encoder := mp3.NewEncoder(int(q.SampleRate), int(q.Channels)) - mp3Encoder := lame.NewEncoder(mp3File) - defer mp3Encoder.Close() - - mp3Encoder.SetNumChannels(int(q.Channels)) - mp3Encoder.SetInSamplerate(int(q.SampleRate)) - - // Convert the PCM data to a []byte - pcmBytes := make([]byte, len(decodedData)*2) // Assuming 16-bit PCM (2 bytes per sample) - for i, val := range decodedData { - binary.LittleEndian.PutUint16(pcmBytes[i*2:], uint16(val)) - } - - // Encode and write the PCM data to the MP3 file - _, err = mp3Encoder.Write(pcmBytes) - if err != nil { - log.Fatalf("Error encoding audio data to MP3: %v", err) - } + mp3Encoder.Write(mp3File, decodedData) } diff --git a/cmd/convert_mp3_windows.go b/cmd/convert_mp3_windows.go deleted file mode 100644 index aba7fef..0000000 --- a/cmd/convert_mp3_windows.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build windows - -package cmd - -import ( - "fmt" - - "github.com/braheezy/goqoa/pkg/qoa" -) - -func decodeMp3(inputData *[]byte) ([]int16, *qoa.QOA) { - fmt.Println("MP3 is not supported on Windows") - return nil, nil -} - -func encodeMp3(outputFile string, q *qoa.QOA, decodedData []int16) { - fmt.Println("MP3 is not supported on Windows") -} diff --git a/cmd/goqoa_test.go b/cmd/goqoa_test.go index 298cc04..b5f0389 100644 --- a/cmd/goqoa_test.go +++ b/cmd/goqoa_test.go @@ -6,7 +6,6 @@ import ( "encoding/hex" "fmt" "os" - "runtime" "strings" "testing" @@ -52,25 +51,16 @@ func TestConvertCmd(t *testing.T) { inputFormat: "flac", outputFormat: "qoa", }, - } - if runtime.GOOS != "windows" { - mp3TestCases := []struct { - audioFormat string - inputFormat string - outputFormat string - }{ - { - audioFormat: "mp3", - inputFormat: "mp3", - outputFormat: "qoa", - }, - { - audioFormat: "mp3", - inputFormat: "qoa", - outputFormat: "mp3", - }, - } - tt = append(tt, mp3TestCases...) + { + audioFormat: "mp3", + inputFormat: "mp3", + outputFormat: "qoa", + }, + { + audioFormat: "mp3", + inputFormat: "qoa", + outputFormat: "mp3", + }, } for _, tc := range tt { @@ -100,7 +90,7 @@ func TestConvertCmd(t *testing.T) { actualChecksumStr := hex.EncodeToString(actualChecksum[:]) // Compare the checksums - require.Equalf(t, expectedChecksumStr, actualChecksumStr, "Conversion failed for %s -> %s", tc.inputFormat, tc.outputFormat) + require.Equalf(t, expectedChecksumStr, actualChecksumStr, "(%s) Conversion failed for %s -> %s", tc.audioFormat, tc.inputFormat, tc.outputFormat) os.Remove(outputFilename) } diff --git a/cmd/testdata/mp3/test.qoa.mp3 b/cmd/testdata/mp3/test.qoa.mp3 index a7be183..7242cdb 100644 Binary files a/cmd/testdata/mp3/test.qoa.mp3 and b/cmd/testdata/mp3/test.qoa.mp3 differ diff --git a/go.mod b/go.mod index fb86d88..79be8e0 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/spf13/cobra v1.7.0 github.com/stretchr/testify v1.8.4 github.com/tosone/minimp3 v1.0.2 - github.com/viert/go-lame v0.0.0-20201108052322-bb552596b11d ) require ( diff --git a/go.sum b/go.sum index e57a083..5ee720d 100644 --- a/go.sum +++ b/go.sum @@ -40,8 +40,6 @@ github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcU github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/tosone/minimp3 v1.0.2 h1:htFE2EbP7Y4CJ8KGW9c55tKWRpzv9kXkEmCYGxFzVjA= github.com/tosone/minimp3 v1.0.2/go.mod h1:N6vjknGR7PboMTyJVhe/7RHNQiIc0jWZxFKlSWdfzwc= -github.com/viert/go-lame v0.0.0-20201108052322-bb552596b11d h1:LptdD7GTUZeklomtW5vZ1AHwBvDBUCZ2Ftpaz7uEI7g= -github.com/viert/go-lame v0.0.0-20201108052322-bb552596b11d/go.mod h1:EqTcYM7y4JlSfeTI47pmNu3EZQuCuLQefsQyg1Imlz8= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= diff --git a/pkg/mp3/bitstream.go b/pkg/mp3/bitstream.go new file mode 100644 index 0000000..73bf520 --- /dev/null +++ b/pkg/mp3/bitstream.go @@ -0,0 +1,58 @@ +// bitstream.go manages writes to the bitstream +package mp3 + +const ( + // Minimum size of the buffer in bytes + MINIMUM = 4 + // Maximum length of word written or read from bit stream + MAX_LENGTH = 32 + BUFFER_SIZE = 4096 +) + +type bitstream struct { + data []uint8 + dataSize int + dataPosition int + cache uint32 + cacheBits int +} + +func (bs *bitstream) open(size int) { + bs.data = make([]uint8, size) + bs.dataSize = size + bs.dataPosition = 0 + bs.cache = 0 + bs.cacheBits = 32 +} + +func (bs *bitstream) putBits(val uint32, N uint) { + if bs.cacheBits > int(N) { + bs.cacheBits -= int(N) + bs.cache |= val << uint32(bs.cacheBits) + } else { + if bs.dataPosition+4 >= bs.dataSize { + newCapacity := bs.dataSize + (bs.dataSize >> 1) + newSlice := make([]byte, newCapacity) + copy(newSlice, bs.data) + bs.data = newSlice + bs.dataSize = newCapacity + } + N -= uint(bs.cacheBits) + bs.cache |= val >> N + bs.data[bs.dataPosition] = uint8(bs.cache >> 24) + bs.data[bs.dataPosition+1] = uint8(bs.cache >> 16) + bs.data[bs.dataPosition+2] = uint8(bs.cache >> 8) + bs.data[bs.dataPosition+3] = uint8(bs.cache) + + bs.dataPosition += 4 + bs.cacheBits = int(32 - N) + if N != 0 { + bs.cache = val << uint(bs.cacheBits) + } else { + bs.cache = 0 + } + } +} +func (bs *bitstream) getBitsCount() int { + return bs.dataPosition*8 + 32 - bs.cacheBits +} diff --git a/pkg/mp3/huffman.go b/pkg/mp3/huffman.go new file mode 100644 index 0000000..9c52311 --- /dev/null +++ b/pkg/mp3/huffman.go @@ -0,0 +1,290 @@ +// huffman.go implements logic to calculate Huffman codes. +// https://www.wikiwand.com/en/Huffman_coding +package mp3 + +const HTN = 34 +const MXOFF = 250 + +type huffCodeTableInfo struct { + xLen uint + yLen uint + linBits uint + linMax uint + table []uint16 + hLen []uint8 +} + +var ( + t1HB = []uint16{1, 1, 1, 0} + t2HB = []uint16{1, 2, 1, 3, 1, 1, 3, 2, 0} + t3HB = []uint16{3, 2, 1, 1, 1, 1, 3, 2, 0} + t5HB = []uint16{1, 2, 6, 5, 3, 1, 4, 4, 7, 5, 7, 1, 6, 1, 1, 0} + t6HB = []uint16{7, 3, 5, 1, 6, 2, 3, 2, 5, 4, 4, 1, 3, 3, 2, 0} + t7HB = []uint16{ + 1, 2, 10, 19, 16, 10, 3, 3, 7, 10, 5, 3, + 11, 4, 13, 17, 8, 4, 12, 11, 18, 15, 11, 2, + 7, 6, 9, 14, 3, 1, 6, 4, 5, 3, 2, 0, + } + t8HB = []uint16{ + 3, 4, 6, 18, 12, 5, 5, 1, 2, 16, 9, 3, + 7, 3, 5, 14, 7, 3, 19, 17, 15, 13, 10, 4, + 13, 5, 8, 11, 5, 1, 12, 4, 4, 1, 1, 0, + } + t9HB = []uint16{ + 7, 5, 9, 14, 15, 7, 6, 4, 5, 5, 6, 7, + 7, 6, 8, 8, 8, 5, 15, 6, 9, 10, 5, 1, + 11, 7, 9, 6, 4, 1, 14, 4, 6, 2, 6, 0, + } + t10HB = []uint16{ + 1, 2, 10, 23, 35, 30, 12, 17, 3, 3, 8, 12, 18, 21, 12, 7, + 11, 9, 15, 21, 32, 40, 19, 6, 14, 13, 22, 34, 46, 23, 18, 7, + 20, 19, 33, 47, 27, 22, 9, 3, 31, 22, 41, 26, 21, 20, 5, 3, + 14, 13, 10, 11, 16, 6, 5, 1, 9, 8, 7, 8, 4, 4, 2, 0, + } + t11HB = []uint16{ + 3, 4, 10, 24, 34, 33, 21, 15, 5, 3, 4, 10, 32, 17, 11, 10, + 11, 7, 13, 18, 30, 31, 20, 5, 25, 11, 19, 59, 27, 18, 12, 5, + 35, 33, 31, 58, 30, 16, 7, 5, 28, 26, 32, 19, 17, 15, 8, 14, + 14, 12, 9, 13, 14, 9, 4, 1, 11, 4, 6, 6, 6, 3, 2, 0, + } + t12HB = []uint16{ + 9, 6, 16, 33, 41, 39, 38, 26, 7, 5, 6, 9, 23, 16, 26, 11, + 17, 7, 11, 14, 21, 30, 10, 7, 17, 10, 15, 12, 18, 28, 14, 5, + 32, 13, 22, 19, 18, 16, 9, 5, 40, 17, 31, 29, 17, 13, 4, 2, + 27, 12, 11, 15, 10, 7, 4, 1, 27, 12, 8, 12, 6, 3, 1, 0, + } + t13HB = []uint16{ + 1, 5, 14, 21, 34, 51, 46, 71, 42, 52, 68, 52, 67, 44, 43, 19, 3, 4, + 12, 19, 31, 26, 44, 33, 31, 24, 32, 24, 31, 35, 22, 14, 15, 13, 23, 36, + 59, 49, 77, 65, 29, 40, 30, 40, 27, 33, 42, 16, 22, 20, 37, 61, 56, 79, + 73, 64, 43, 76, 56, 37, 26, 31, 25, 14, 35, 16, 60, 57, 97, 75, 114, 91, + 54, 73, 55, 41, 48, 53, 23, 24, 58, 27, 50, 96, 76, 70, 93, 84, 77, 58, + 79, 29, 74, 49, 41, 17, 47, 45, 78, 74, 115, 94, 90, 79, 69, 83, 71, 50, + 59, 38, 36, 15, 72, 34, 56, 95, 92, 85, 91, 90, 86, 73, 77, 65, 51, 44, + 43, 42, 43, 20, 30, 44, 55, 78, 72, 87, 78, 61, 46, 54, 37, 30, 20, 16, + 53, 25, 41, 37, 44, 59, 54, 81, 66, 76, 57, 54, 37, 18, 39, 11, 35, 33, + 31, 57, 42, 82, 72, 80, 47, 58, 55, 21, 22, 26, 38, 22, 53, 25, 23, 38, + 70, 60, 51, 36, 55, 26, 34, 23, 27, 14, 9, 7, 34, 32, 28, 39, 49, 75, + 30, 52, 48, 40, 52, 28, 18, 17, 9, 5, 45, 21, 34, 64, 56, 50, 49, 45, + 31, 19, 12, 15, 10, 7, 6, 3, 48, 23, 20, 39, 36, 35, 53, 21, 16, 23, + 13, 10, 6, 1, 4, 2, 16, 15, 17, 27, 25, 20, 29, 11, 17, 12, 16, 8, + 1, 1, 0, 1, + } + t15HB = []uint16{ + 7, 12, 18, 53, 47, 76, 124, 108, 89, 123, 108, 119, 107, 81, 122, 63, + 13, 5, 16, 27, 46, 36, 61, 51, 42, 70, 52, 83, 65, 41, 59, 36, + 19, 17, 15, 24, 41, 34, 59, 48, 40, 64, 50, 78, 62, 80, 56, 33, + 29, 28, 25, 43, 39, 63, 55, 93, 76, 59, 93, 72, 54, 75, 50, 29, + 52, 22, 42, 40, 67, 57, 95, 79, 72, 57, 89, 69, 49, 66, 46, 27, + 77, 37, 35, 66, 58, 52, 91, 74, 62, 48, 79, 63, 90, 62, 40, 38, + 125, 32, 60, 56, 50, 92, 78, 65, 55, 87, 71, 51, 73, 51, 70, 30, + 109, 53, 49, 94, 88, 75, 66, 122, 91, 73, 56, 42, 64, 44, 21, 25, + 90, 43, 41, 77, 73, 63, 56, 92, 77, 66, 47, 67, 48, 53, 36, 20, + 71, 34, 67, 60, 58, 49, 88, 76, 67, 106, 71, 54, 38, 39, 23, 15, + 109, 53, 51, 47, 90, 82, 58, 57, 48, 72, 57, 41, 23, 27, 62, 9, + 86, 42, 40, 37, 70, 64, 52, 43, 70, 55, 42, 25, 29, 18, 11, 11, + 118, 68, 30, 55, 50, 46, 74, 65, 49, 39, 24, 16, 22, 13, 14, 7, + 91, 44, 39, 38, 34, 63, 52, 45, 31, 52, 28, 19, 14, 8, 9, 3, + 123, 60, 58, 53, 47, 43, 32, 22, 37, 24, 17, 12, 15, 10, 2, 1, + 71, 37, 34, 30, 28, 20, 17, 26, 21, 16, 10, 6, 8, 6, 2, 0, + } + t16HB = []uint16{ + 1, 5, 14, 44, 74, 63, 110, 93, 172, 149, 138, 242, 225, 195, + 376, 17, 3, 4, 12, 20, 35, 62, 53, 47, 83, 75, 68, 119, + 201, 107, 207, 9, 15, 13, 23, 38, 67, 58, 103, 90, 161, 72, + 127, 117, 110, 209, 206, 16, 45, 21, 39, 69, 64, 114, 99, 87, + 158, 140, 252, 212, 199, 387, 365, 26, 75, 36, 68, 65, 115, 101, + 179, 164, 155, 264, 246, 226, 395, 382, 362, 9, 66, 30, 59, 56, + 102, 185, 173, 265, 142, 253, 232, 400, 388, 378, 445, 16, 111, 54, + 52, 100, 184, 178, 160, 133, 257, 244, 228, 217, 385, 366, 715, 10, + 98, 48, 91, 88, 165, 157, 148, 261, 248, 407, 397, 372, 380, 889, + 884, 8, 85, 84, 81, 159, 156, 143, 260, 249, 427, 401, 392, 383, + 727, 713, 708, 7, 154, 76, 73, 141, 131, 256, 245, 426, 406, 394, + 384, 735, 359, 710, 352, 11, 139, 129, 67, 125, 247, 233, 229, 219, + 393, 743, 737, 720, 885, 882, 439, 4, 243, 120, 118, 115, 227, 223, + 396, 746, 742, 736, 721, 712, 706, 223, 436, 6, 202, 224, 222, 218, + 216, 389, 386, 381, 364, 888, 443, 707, 440, 437, 1728, 4, 747, 211, + 210, 208, 370, 379, 734, 723, 714, 1735, 883, 877, 876, 3459, 865, 2, + 377, 369, 102, 187, 726, 722, 358, 711, 709, 866, 1734, 871, 3458, 870, + 434, 0, 12, 10, 7, 11, 10, 17, 11, 9, 13, 12, 10, 7, 5, 3, 1, 3, + } + t24HB = []uint16{ + 15, 13, 46, 80, 146, 262, 248, 434, 426, 669, 653, 649, 621, 517, 1032, + 88, 14, 12, 21, 38, 71, 130, 122, 216, 209, 198, 327, 345, 319, 297, + 279, 42, 47, 22, 41, 74, 68, 128, 120, 221, 207, 194, 182, 340, 315, + 295, 541, 18, 81, 39, 75, 70, 134, 125, 116, 220, 204, 190, 178, 325, + 311, 293, 271, 16, 147, 72, 69, 135, 127, 118, 112, 210, 200, 188, 352, + 323, 306, 285, 540, 14, 263, 66, 129, 126, 119, 114, 214, 202, 192, 180, + 341, 317, 301, 281, 262, 12, 249, 123, 121, 117, 113, 215, 206, 195, 185, + 347, 330, 308, 291, 272, 520, 10, 435, 115, 111, 109, 211, 203, 196, 187, + 353, 332, 313, 298, 283, 531, 381, 17, 427, 212, 208, 205, 201, 193, 186, + 177, 169, 320, 303, 286, 268, 514, 377, 16, 335, 199, 197, 191, 189, 181, + 174, 333, 321, 305, 289, 275, 521, 379, 371, 11, 668, 184, 183, 179, 175, + 344, 331, 314, 304, 290, 277, 530, 383, 373, 366, 10, 652, 346, 171, 168, + 164, 318, 309, 299, 287, 276, 263, 513, 375, 368, 362, 6, 648, 322, 316, + 312, 307, 302, 292, 284, 269, 261, 512, 376, 370, 364, 359, 4, 620, 300, + 296, 294, 288, 282, 273, 266, 515, 380, 374, 369, 365, 361, 357, 2, 1033, + 280, 278, 274, 267, 264, 259, 382, 378, 372, 367, 363, 360, 358, 356, 0, + 43, 20, 19, 17, 15, 13, 11, 9, 7, 6, 4, 7, 5, 3, 1, 3, + } + t32HB = []uint16{ + 1, 5, 4, 5, 6, 5, 4, 4, + 7, 3, 6, 0, 7, 2, 3, 1, + } + t33HB = []uint16{ + 15, 14, 13, 12, 11, 10, 9, 8, + 7, 6, 5, 4, 3, 2, 1, 0, + } + + t1l = []uint8{1, 3, 2, 3} + t2l = []uint8{1, 3, 6, 3, 3, 5, 5, 5, 6} + t3l = []uint8{2, 2, 6, 3, 2, 5, 5, 5, 6} + t5l = []uint8{ + 1, 3, 6, 7, 3, 3, 6, 7, + 6, 6, 7, 8, 7, 6, 7, 8, + } + t6l = []uint8{ + 3, 3, 5, 7, 3, 2, 4, 5, + 4, 4, 5, 6, 6, 5, 6, 7, + } + t7l = []uint8{ + 1, 3, 6, 8, 8, 9, 3, 4, 6, 7, 7, 8, + 6, 5, 7, 8, 8, 9, 7, 7, 8, 9, 9, 9, + 7, 7, 8, 9, 9, 10, 8, 8, 9, 10, 10, 10, + } + t8l = []uint8{ + 2, 3, 6, 8, 8, 9, 3, 2, 4, 8, 8, 8, + 6, 4, 6, 8, 8, 9, 8, 8, 8, 9, 9, 10, + 8, 7, 8, 9, 10, 10, 9, 8, 9, 9, 11, 11, + } + t9l = []uint8{ + 3, 3, 5, 6, 8, 9, 3, 3, 4, 5, 6, 8, + 4, 4, 5, 6, 7, 8, 6, 5, 6, 7, 7, 8, + 7, 6, 7, 7, 8, 9, 8, 7, 8, 8, 9, 9, + } + t10l = []uint8{ + 1, 3, 6, 8, 9, 9, 9, 10, 3, 4, 6, 7, 8, 9, 8, 8, + 6, 6, 7, 8, 9, 10, 9, 9, 7, 7, 8, 9, 10, 10, 9, 10, + 8, 8, 9, 10, 10, 10, 10, 10, 9, 9, 10, 10, 11, 11, 10, 11, + 8, 8, 9, 10, 10, 10, 11, 11, 9, 8, 9, 10, 10, 11, 11, 11, + } + t11l = []uint8{ + 2, 3, 5, 7, 8, 9, 8, 9, 3, 3, 4, 6, 8, 8, 7, 8, + 5, 5, 6, 7, 8, 9, 8, 8, 7, 6, 7, 9, 8, 10, 8, 9, + 8, 8, 8, 9, 9, 10, 9, 10, 8, 8, 9, 10, 10, 11, 10, 11, + 8, 7, 7, 8, 9, 10, 10, 10, 8, 7, 8, 9, 10, 10, 10, 10, + } + t12l = []uint8{ + 4, 3, 5, 7, 8, 9, 9, 9, 3, 3, 4, 5, 7, 7, 8, 8, 5, 4, 5, 6, 7, 8, + 7, 8, 6, 5, 6, 6, 7, 8, 8, 8, 7, 6, 7, 7, 8, 8, 8, 9, 8, 7, 8, 8, + 8, 9, 8, 9, 8, 7, 7, 8, 8, 9, 9, 10, 9, 8, 8, 9, 9, 9, 9, 10, + } + t13l = []uint8{ + 1, 4, 6, 7, 8, 9, 9, 10, 9, 10, 11, 11, 12, 12, 13, 13, 3, 4, 6, + 7, 8, 8, 9, 9, 9, 9, 10, 10, 11, 12, 12, 12, 6, 6, 7, 8, 9, 9, + 10, 10, 9, 10, 10, 11, 11, 12, 13, 13, 7, 7, 8, 9, 9, 10, 10, 10, 10, + 11, 11, 11, 11, 12, 13, 13, 8, 7, 9, 9, 10, 10, 11, 11, 10, 11, 11, 12, + 12, 13, 13, 14, 9, 8, 9, 10, 10, 10, 11, 11, 11, 11, 12, 11, 13, 13, 14, + 14, 9, 9, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 13, 13, 14, 14, 10, 9, + 10, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 14, 16, 16, 9, 8, 9, 10, 10, + 11, 11, 12, 12, 12, 12, 13, 13, 14, 15, 15, 10, 9, 10, 10, 11, 11, 11, 13, + 12, 13, 13, 14, 14, 14, 16, 15, 10, 10, 10, 11, 11, 12, 12, 13, 12, 13, 14, + 13, 14, 15, 16, 17, 11, 10, 10, 11, 12, 12, 12, 12, 13, 13, 13, 14, 15, 15, + 15, 16, 11, 11, 11, 12, 12, 13, 12, 13, 14, 14, 15, 15, 15, 16, 16, 16, 12, + 11, 12, 13, 13, 13, 14, 14, 14, 14, 14, 15, 16, 15, 16, 16, 13, 12, 12, 13, + 13, 13, 15, 14, 14, 17, 15, 15, 15, 17, 16, 16, 12, 12, 13, 14, 14, 14, 15, + 14, 15, 15, 16, 16, 19, 18, 19, 16, + } + t15l = []uint8{ + 3, 4, 5, 7, 7, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 13, 4, 3, 5, + 6, 7, 7, 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 5, 5, 5, 6, 7, 7, + 8, 8, 8, 9, 9, 10, 10, 11, 11, 11, 6, 6, 6, 7, 7, 8, 8, 9, 9, + 9, 10, 10, 10, 11, 11, 11, 7, 6, 7, 7, 8, 8, 9, 9, 9, 9, 10, 10, + 10, 11, 11, 11, 8, 7, 7, 8, 8, 8, 9, 9, 9, 9, 10, 10, 11, 11, 11, + 12, 9, 7, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 11, 11, 12, 12, 9, 8, + 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 11, 12, 9, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 10, 11, 11, 12, 12, 12, 9, 8, 9, 9, 9, 9, 10, 10, + 10, 11, 11, 11, 11, 12, 12, 12, 10, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, + 11, 11, 12, 13, 12, 10, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, + 12, 13, 11, 10, 9, 10, 10, 10, 11, 11, 11, 11, 11, 11, 12, 12, 13, 13, 11, + 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 12, 11, 11, 11, + 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 12, 13, 12, 11, 11, 11, 11, 11, 11, + 12, 12, 12, 12, 12, 13, 13, 13, 13, + } + t16l = []uint8{ + 1, 4, 6, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, 13, 9, 3, 4, 6, + 7, 8, 9, 9, 9, 10, 10, 10, 11, 12, 11, 12, 8, 6, 6, 7, 8, 9, 9, + 10, 10, 11, 10, 11, 11, 11, 12, 12, 9, 8, 7, 8, 9, 9, 10, 10, 10, 11, + 11, 12, 12, 12, 13, 13, 10, 9, 8, 9, 9, 10, 10, 11, 11, 11, 12, 12, 12, + 13, 13, 13, 9, 9, 8, 9, 9, 10, 11, 11, 12, 11, 12, 12, 13, 13, 13, 14, + 10, 10, 9, 9, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 14, 10, 10, 9, + 10, 10, 11, 11, 11, 12, 12, 13, 13, 13, 13, 15, 15, 10, 10, 10, 10, 11, 11, + 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 10, 11, 10, 10, 11, 11, 12, 12, 13, + 13, 13, 13, 14, 13, 14, 13, 11, 11, 11, 10, 11, 12, 12, 12, 12, 13, 14, 14, + 14, 15, 15, 14, 10, 12, 11, 11, 11, 12, 12, 13, 14, 14, 14, 14, 14, 14, 13, + 14, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 15, 14, 14, 14, 14, 16, 11, 14, + 12, 12, 12, 13, 13, 14, 14, 14, 16, 15, 15, 15, 17, 15, 11, 13, 13, 11, 12, + 14, 14, 13, 14, 14, 15, 16, 15, 17, 15, 14, 11, 9, 8, 8, 9, 9, 10, 10, + 10, 11, 11, 11, 11, 11, 11, 11, 8, + } + t24l = []uint8{ + 4, 4, 6, 7, 8, 9, 9, 10, 10, 11, 11, 11, 11, 11, 12, 9, 4, 4, 5, + 6, 7, 8, 8, 9, 9, 9, 10, 10, 10, 10, 10, 8, 6, 5, 6, 7, 7, 8, + 8, 9, 9, 9, 9, 10, 10, 10, 11, 7, 7, 6, 7, 7, 8, 8, 8, 9, 9, + 9, 9, 10, 10, 10, 10, 7, 8, 7, 7, 8, 8, 8, 8, 9, 9, 9, 10, 10, + 10, 10, 11, 7, 9, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, + 7, 9, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 7, 10, 8, + 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 11, 11, 8, 10, 9, 9, 9, 9, + 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 8, 10, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 11, 11, 11, 8, 11, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, + 11, 11, 11, 11, 8, 11, 10, 9, 9, 9, 10, 10, 10, 10, 10, 10, 11, 11, 11, + 11, 8, 11, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 8, 11, + 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 8, 12, 10, 10, 10, + 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 8, 8, 7, 7, 7, 7, 7, 7, + 7, 7, 7, 7, 8, 8, 8, 8, 4, + } + t32l = []uint8{ + 1, 4, 4, 5, 4, 6, 5, 6, + 4, 5, 5, 6, 5, 6, 6, 6, + } + t33l = []uint8{ + 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, + } +) +var huffmanCodeTable = [HTN]huffCodeTableInfo{ + {0, 0, 0, 0, nil, nil}, + {2, 2, 0, 0, t1HB, t1l}, + {3, 3, 0, 0, t2HB, t2l}, + {3, 3, 0, 0, t3HB, t3l}, + {0, 0, 0, 0, nil, nil}, /* Apparently not used*/ + {4, 4, 0, 0, t5HB, t5l}, + {4, 4, 0, 0, t6HB, t6l}, + {6, 6, 0, 0, t7HB, t7l}, + {6, 6, 0, 0, t8HB, t8l}, + {6, 6, 0, 0, t9HB, t9l}, + {8, 8, 0, 0, t10HB, t10l}, + {8, 8, 0, 0, t11HB, t11l}, + {8, 8, 0, 0, t12HB, t12l}, + {16, 16, 0, 0, t13HB, t13l}, + {0, 0, 0, 0, nil, nil}, /* Apparently not used*/ + {16, 16, 0, 0, t15HB, t15l}, + {16, 16, 1, 1, t16HB, t16l}, + {16, 16, 2, 3, t16HB, t16l}, + {16, 16, 3, 7, t16HB, t16l}, + {16, 16, 4, 15, t16HB, t16l}, + {16, 16, 6, 63, t16HB, t16l}, + {16, 16, 8, 255, t16HB, t16l}, + {16, 16, 10, 1023, t16HB, t16l}, + {16, 16, 13, 8191, t16HB, t16l}, + {16, 16, 4, 15, t24HB, t24l}, + {16, 16, 5, 31, t24HB, t24l}, + {16, 16, 6, 63, t24HB, t24l}, + {16, 16, 7, 127, t24HB, t24l}, + {16, 16, 8, 255, t24HB, t24l}, + {16, 16, 9, 511, t24HB, t24l}, + {16, 16, 11, 2047, t24HB, t24l}, + {16, 16, 13, 8191, t24HB, t24l}, + {1, 16, 0, 0, t32HB, t32l}, + {1, 16, 0, 0, t33HB, t33l}, +} diff --git a/pkg/mp3/l3bitstream.go b/pkg/mp3/l3bitstream.go new file mode 100644 index 0000000..a08df34 --- /dev/null +++ b/pkg/mp3/l3bitstream.go @@ -0,0 +1,317 @@ +package mp3 + +// This is called after a frame of audio has been quantized and coded. +// It will write the encoded audio to the bitstream. Note that +// from a layer3 encoder's perspective the bit stream is primarily +// a series of main_data() blocks, with header and side information +// inserted at the proper locations to maintain framing. (See Figure A.7 in the IS). +func (enc *Encoder) formatBitstream() { + var ( + gr int64 + ch int64 + i int64 + ) + for ch = 0; ch < enc.Wave.Channels; ch++ { + for gr = 0; gr < enc.Mpeg.GranulesPerFrame; gr++ { + pi := &enc.l3Encoding[ch][gr] + pr := &enc.mdctFrequency[ch][gr] + for i = 0; i < GRANULE_SIZE; i++ { + + if pr[i] < 0 && pi[i] > 0 { + pi[i] *= -1 + } + } + } + } + enc.encodeSideInfo() + enc.encodeMainData() +} +func (enc *Encoder) encodeMainData() { + var ( + gr int64 + ch int64 + sfb int64 + si SideInfo = enc.sideInfo + ) + for gr = 0; gr < enc.Mpeg.GranulesPerFrame; gr++ { + for ch = 0; ch < enc.Wave.Channels; ch++ { + var ( + gi *GranuleInfo = &si.Granules[gr].Channels[ch].Tt + slen1 uint64 = uint64(slen1Table[gi.ScaleFactorCompress]) + slen2 uint64 = uint64(slen2Table[gi.ScaleFactorCompress]) + ix *[GRANULE_SIZE]int64 = &enc.l3Encoding[ch][gr] + ) + if gr == 0 || si.ScaleFactorSelectInfo[ch][0] == 0 { + for sfb = 0; sfb < 6; sfb++ { + enc.bitstream.putBits(uint32(enc.scaleFactor.L[gr][ch][sfb]), uint(slen1)) + } + } + if gr == 0 || si.ScaleFactorSelectInfo[ch][1] == 0 { + for sfb = 6; sfb < 11; sfb++ { + enc.bitstream.putBits(uint32(enc.scaleFactor.L[gr][ch][sfb]), uint(slen1)) + } + } + if gr == 0 || si.ScaleFactorSelectInfo[ch][2] == 0 { + for sfb = 11; sfb < 16; sfb++ { + enc.bitstream.putBits(uint32(enc.scaleFactor.L[gr][ch][sfb]), uint(slen2)) + } + } + if gr == 0 || si.ScaleFactorSelectInfo[ch][3] == 0 { + for sfb = 16; sfb < 21; sfb++ { + enc.bitstream.putBits(uint32(enc.scaleFactor.L[gr][ch][sfb]), uint(slen2)) + } + } + enc.huffmanCodeBits(ix, gi) + } + } +} +func (enc *Encoder) encodeSideInfo() { + var ( + gr int64 + ch int64 + scfsi_band int64 + region int64 + si SideInfo = enc.sideInfo + ) + enc.bitstream.putBits(2047, 11) + enc.bitstream.putBits(uint32(enc.Mpeg.Version), 2) + enc.bitstream.putBits(uint32(enc.Mpeg.Layer), 2) + if enc.Mpeg.Crc == 0 { + enc.bitstream.putBits(uint32(1), 1) + } else { + enc.bitstream.putBits(uint32(0), 1) + } + enc.bitstream.putBits(uint32(enc.Mpeg.BitrateIndex), 4) + enc.bitstream.putBits(uint32(enc.Mpeg.SampleRateIndex%3), 2) + enc.bitstream.putBits(uint32(enc.Mpeg.Padding), 1) + enc.bitstream.putBits(uint32(enc.Mpeg.Ext), 1) + enc.bitstream.putBits(uint32(enc.Mpeg.Mode), 2) + enc.bitstream.putBits(uint32(enc.Mpeg.ModeExt), 2) + enc.bitstream.putBits(uint32(enc.Mpeg.Copyright), 1) + enc.bitstream.putBits(uint32(enc.Mpeg.Original), 1) + enc.bitstream.putBits(uint32(enc.Mpeg.Emph), 2) + if enc.Mpeg.Version == MPEG_I { + enc.bitstream.putBits(0, 9) + if enc.Wave.Channels == 2 { + enc.bitstream.putBits(uint32(si.PrivateBits), 3) + } else { + enc.bitstream.putBits(uint32(si.PrivateBits), 5) + } + } else { + enc.bitstream.putBits(0, 8) + if enc.Wave.Channels == 2 { + enc.bitstream.putBits(uint32(si.PrivateBits), 2) + } else { + enc.bitstream.putBits(uint32(si.PrivateBits), 1) + } + } + if enc.Mpeg.Version == MPEG_I { + for ch = 0; ch < enc.Wave.Channels; ch++ { + for scfsi_band = 0; scfsi_band < 4; scfsi_band++ { + enc.bitstream.putBits(uint32(si.ScaleFactorSelectInfo[ch][scfsi_band]), 1) + } + } + } + for gr = 0; gr < enc.Mpeg.GranulesPerFrame; gr++ { + for ch = 0; ch < enc.Wave.Channels; ch++ { + var gi *GranuleInfo = &si.Granules[gr].Channels[ch].Tt + enc.bitstream.putBits(uint32(gi.Part2_3Length), 12) + enc.bitstream.putBits(uint32(gi.BigValues), 9) + enc.bitstream.putBits(uint32(gi.GlobalGain), 8) + if enc.Mpeg.Version == MPEG_I { + enc.bitstream.putBits(uint32(gi.ScaleFactorCompress), 4) + } else { + enc.bitstream.putBits(uint32(gi.ScaleFactorCompress), 9) + } + enc.bitstream.putBits(0, 1) + for region = 0; region < 3; region++ { + enc.bitstream.putBits(uint32(gi.TableSelect[region]), 5) + } + enc.bitstream.putBits(uint32(gi.Region0Count), 4) + enc.bitstream.putBits(uint32(gi.Region1Count), 3) + if enc.Mpeg.Version == MPEG_I { + enc.bitstream.putBits(uint32(gi.PreFlag), 1) + } + enc.bitstream.putBits(uint32(gi.ScaleFactorScale), 1) + enc.bitstream.putBits(uint32(gi.Count1TableSelect), 1) + } + } +} +func (enc *Encoder) huffmanCodeBits(ix *[GRANULE_SIZE]int64, gi *GranuleInfo) { + var ( + scalefac [23]int64 = scaleFactorBandIndex[enc.Mpeg.SampleRateIndex] + scalefac_index uint64 + region1Start int64 + region2Start int64 + i int64 + bigvalues int64 + count1End int64 + v int64 + w int64 + x int64 + y int64 + h *huffCodeTableInfo + bits int64 + ) + bits = int64(enc.bitstream.getBitsCount()) + bigvalues = int64(gi.BigValues << 1) + scalefac_index = gi.Region0Count + 1 + region1Start = scalefac[scalefac_index] + scalefac_index += gi.Region1Count + 1 + region2Start = scalefac[scalefac_index] + for i = 0; i < bigvalues; i += 2 { + idx := 0 + if i >= region1Start { + idx++ + } + if i >= region2Start { + idx++ + } + var tableindex uint64 = gi.TableSelect[idx] + if tableindex != 0 { + x = (*ix)[i] + y = (*ix)[i+1] + huffmanCode(&enc.bitstream, int64(tableindex), x, y) + } + } + h = &huffmanCodeTable[gi.Count1TableSelect+32] + count1End = int64(uint64(bigvalues) + (gi.Count1 << 2)) + for i = bigvalues; i < count1End; i += 4 { + v = (*ix)[i] + w = (*ix)[i+1] + x = (*ix)[i+2] + y = (*ix)[i+3] + huffmanCoderCount1(&enc.bitstream, h, v, w, x, y) + } + bits = int64(enc.bitstream.getBitsCount()) - bits + bits = int64(gi.Part2_3Length - gi.Part2Length - uint64(bits)) + if bits != 0 { + var ( + stuffingWords int64 = bits / 32 + remainingBits int64 = bits % 32 + ) + for func() int64 { + p := &stuffingWords + x := *p + *p-- + return x + }() != 0 { + enc.bitstream.putBits(^uint32(0), 32) + } + if remainingBits != 0 { + enc.bitstream.putBits(uint32((1< 0 { + return 0 + } + *x *= -1 + return 1 +} +func huffmanCoderCount1(bs *bitstream, h *huffCodeTableInfo, v int64, w int64, x int64, y int64) { + var ( + signv uint64 + signw uint64 + signx uint64 + signy uint64 + code uint64 = 0 + p int64 + cbits int64 = 0 + ) + signv = uint64(absAndSign(&v)) + signw = uint64(absAndSign(&w)) + signx = uint64(absAndSign(&x)) + signy = uint64(absAndSign(&y)) + p = v + (w << 1) + (x << 2) + (y << 3) + bs.putBits(uint32(h.table[p]), uint(h.hLen[p])) + if v != 0 { + code = signv + cbits = 1 + } + if w != 0 { + code = (code << 1) | signw + cbits++ + } + if x != 0 { + code = (code << 1) | signx + cbits++ + } + if y != 0 { + code = (code << 1) | signy + cbits++ + } + bs.putBits(uint32(code), uint(cbits)) +} +func huffmanCode(bs *bitstream, table_select int64, x int64, y int64) { + var ( + cbits int64 = 0 + xbits int64 = 0 + code uint64 = 0 + ext uint64 = 0 + signx uint64 + signy uint64 + ylen uint64 + idx uint64 + h *huffCodeTableInfo + ) + signx = uint64(absAndSign(&x)) + signy = uint64(absAndSign(&y)) + h = &(huffmanCodeTable[table_select]) + ylen = uint64(h.yLen) + if table_select > 15 { + var ( + linbitsx uint64 = 0 + linbitsy uint64 = 0 + linbits uint64 = uint64(h.linBits) + ) + if x > 14 { + linbitsx = uint64(x - 15) + x = 15 + } + if y > 14 { + linbitsy = uint64(y - 15) + y = 15 + } + idx = (uint64(x) * ylen) + uint64(y) + code = uint64(h.table[idx]) + cbits = int64(h.hLen[idx]) + if x > 14 { + ext |= linbitsx + xbits += int64(linbits) + } + if x != 0 { + ext <<= 1 + ext |= signx + xbits += 1 + } + if y > 14 { + ext <<= linbits + ext |= linbitsy + xbits += int64(linbits) + } + if y != 0 { + ext <<= 1 + ext |= signy + xbits += 1 + } + bs.putBits(uint32(code), uint(cbits)) + bs.putBits(uint32(ext), uint(xbits)) + } else { + idx = (uint64(x) * ylen) + uint64(y) + code = uint64(h.table[idx]) + cbits = int64(h.hLen[idx]) + if x != 0 { + code <<= 1 + code |= signx + cbits += 1 + } + if y != 0 { + code <<= 1 + code |= signy + cbits += 1 + } + bs.putBits(uint32(code), uint(cbits)) + } +} diff --git a/pkg/mp3/l3loop.go b/pkg/mp3/l3loop.go new file mode 100644 index 0000000..50a2244 --- /dev/null +++ b/pkg/mp3/l3loop.go @@ -0,0 +1,739 @@ +package mp3 + +import ( + "math" +) + +const ( + scaleFactorBand_LMax = 22 + enTotKrit = 10 + enDifKrit = 100 + enScfsiBandKrit = 10 + xmScfsiBandKrit = 10 +) + +// innerLoop selects the best quantizerStepSize for a particular set of scaleFactors. +func (enc *Encoder) innerLoop(ix *[GRANULE_SIZE]int64, max_bits int64, cod_info *GranuleInfo, gr int64, ch int64) int64 { + var ( + bits int64 + c1bits int64 + bvbits int64 + ) + if max_bits < 0 { + cod_info.QuantizerStepSize-- + } + for { + for enc.quantize(ix, func() int64 { + p := &cod_info.QuantizerStepSize + *p++ + return *p + }()) > 8192 { + } + calcRunLength(ix, cod_info) + bits = func() int64 { + c1bits = count1BitCount(ix, cod_info) + return c1bits + }() + enc.subDivide(cod_info) + bigValuesTableSelect(ix, cod_info) + bits += func() int64 { + bvbits = bigValuesBitCount(ix, cod_info) + return bvbits + }() + if bits <= max_bits { + break + } + } + return bits +} + +// outerLoop controls the masking conditions of all scaleFactorBands. It computes the best scaleFactor and +// global gain. This module calls the inner iteration loop. +// l3XMin: the allowed distortion of the scaleFactor. +// ix: vector of quantized values ix(0..575) +func (enc *Encoder) outerLoop(max_bits int64, l3_xmin *PsyXMin, ix *[GRANULE_SIZE]int64, gr int64, ch int64) int64 { + var ( + bits int64 + huff_bits int64 + side_info *SideInfo = &enc.sideInfo + cod_info *GranuleInfo = &side_info.Granules[gr].Channels[ch].Tt + ) + cod_info.QuantizerStepSize = enc.binSearchStepSize(max_bits, ix, cod_info) + cod_info.Part2Length = uint64(enc.calcPart2Length(gr, ch)) + huff_bits = int64(uint64(max_bits) - cod_info.Part2Length) + bits = enc.innerLoop(ix, huff_bits, cod_info, gr, ch) + cod_info.Part2_3Length = cod_info.Part2Length + uint64(bits) + return int64(cod_info.Part2_3Length) +} + +func (enc *Encoder) iterationLoop() { + var ( + l3_xmin PsyXMin + cod_info *GranuleInfo + max_bits int64 + ch int64 + gr int64 + i int64 + ix *[GRANULE_SIZE]int64 + ) + for ch = enc.Wave.Channels; func() int64 { + p := &ch + x := *p + *p-- + return x + }() != 0; { + for gr = 0; gr < enc.Mpeg.GranulesPerFrame; gr++ { + ix = &enc.l3Encoding[ch][gr] + enc.l3loop.Xr = enc.mdctFrequency[ch][gr][:] + for func() int32 { + i = GRANULE_SIZE + return func() int32 { + p := &enc.l3loop.Xrmax + enc.l3loop.Xrmax = 0 + return *p + }() + }(); func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + a := mulSR(enc.l3loop.Xr[i], enc.l3loop.Xr[i]) + enc.l3loop.Xrsq[i] = a + a = int32(math.Abs(float64(enc.l3loop.Xr[i]))) + enc.l3loop.Xrabs[i] = a + if int64(enc.l3loop.Xrabs[i]) > int64(enc.l3loop.Xrmax) { + enc.l3loop.Xrmax = enc.l3loop.Xrabs[i] + } + } + cod_info = &(enc.sideInfo.Granules[gr].Channels[ch]).Tt + cod_info.ScaleFactorBandMaxLen = scaleFactorBand_LMax - 1 + calcXMin(&enc.ratio, cod_info, &l3_xmin, gr, ch) + if enc.Mpeg.Version == MPEG_I { + enc.calcSCFSI(&l3_xmin, ch, gr) + } + max_bits = enc.maxReservoirBits(&enc.PerceptualEnergy[ch][gr]) + for i = 4; func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + cod_info.ScaleFactorLen[i] = 0 + } + cod_info.Part2_3Length = 0 + cod_info.BigValues = 0 + cod_info.Count1 = 0 + cod_info.ScaleFactorCompress = 0 + cod_info.TableSelect[0] = 0 + cod_info.TableSelect[1] = 0 + cod_info.TableSelect[2] = 0 + cod_info.Region0Count = 0 + cod_info.Region1Count = 0 + cod_info.Part2Length = 0 + cod_info.PreFlag = 0 + cod_info.ScaleFactorScale = 0 + cod_info.Count1TableSelect = 0 + if int64(enc.l3loop.Xrmax) != 0 { + cod_info.Part2_3Length = uint64(enc.outerLoop(max_bits, &l3_xmin, ix, gr, ch)) + } + enc.reservoirAdjust(cod_info) + cod_info.GlobalGain = uint64(cod_info.QuantizerStepSize + 210) + } + } + enc.reservoirFrameEnd() +} + +// calcSCFSI calculates the scalefactor select information ( scfsi ) +func (enc *Encoder) calcSCFSI(l3_xmin *PsyXMin, ch int64, gr int64) { + var ( + l3_side *SideInfo = &enc.sideInfo + scfsi_band_long [5]int64 = [5]int64{0, 6, 11, 16, 21} + scfsi_band int64 + sfb int64 + start int64 + end int64 + i int64 + condition int64 = 0 + temp int64 + scalefac_band_long *[23]int64 = &scaleFactorBandIndex[enc.Mpeg.SampleRateIndex] + ) + enc.l3loop.Xrmaxl[gr] = enc.l3loop.Xrmax + for func() int64 { + temp = 0 + return func() int64 { + i = GRANULE_SIZE + return i + }() + }(); func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + temp += int64(enc.l3loop.Xrsq[i]) >> 10 + } + if temp != 0 { + enc.l3loop.EnTot[gr] = int32(math.Log(float64(temp)*4.768371584e-07) / LN2) + } else { + enc.l3loop.EnTot[gr] = 0 + } + for sfb = 21; func() int64 { + p := &sfb + x := *p + *p-- + return x + }() != 0; { + start = scalefac_band_long[sfb] + end = scalefac_band_long[sfb+1] + for func() int64 { + temp = 0 + return func() int64 { + i = start + return i + }() + }(); i < end; i++ { + temp += int64(enc.l3loop.Xrsq[i]) >> 10 + } + if temp != 0 { + enc.l3loop.En[gr][sfb] = int32(math.Log(float64(temp)*4.768371584e-07) / LN2) + } else { + enc.l3loop.En[gr][sfb] = 0 + } + if l3_xmin.L[gr][ch][sfb] != 0 { + enc.l3loop.Xm[gr][sfb] = int32(math.Log(l3_xmin.L[gr][ch][sfb]) / LN2) + } else { + enc.l3loop.Xm[gr][sfb] = 0 + } + } + if gr == 1 { + var ( + gr2 int64 + tp int64 + ) + for gr2 = 2; func() int64 { + p := &gr2 + x := *p + *p-- + return x + }() != 0; { + if int64(enc.l3loop.Xrmaxl[gr2]) != 0 { + condition++ + } + condition++ + } + if math.Abs(float64(enc.l3loop.EnTot[0])-float64(enc.l3loop.EnTot[1])) < enTotKrit { + condition++ + } + for func() int64 { + tp = 0 + return func() int64 { + sfb = 21 + return sfb + }() + }(); func() int64 { + p := &sfb + x := *p + *p-- + return x + }() != 0; { + tp += int64(math.Abs(float64(enc.l3loop.En[0][sfb]) - float64(enc.l3loop.En[1][sfb]))) + } + if tp < enDifKrit { + condition++ + } + if condition == 6 { + for scfsi_band = 0; scfsi_band < 4; scfsi_band++ { + var ( + sum0 int64 = 0 + sum1 int64 = 0 + ) + l3_side.ScaleFactorSelectInfo[ch][scfsi_band] = 0 + start = scfsi_band_long[scfsi_band] + end = scfsi_band_long[scfsi_band+1] + for sfb = start; sfb < end; sfb++ { + sum0 += int64(math.Abs(float64(enc.l3loop.En[0][sfb]) - float64(enc.l3loop.En[1][sfb]))) + sum1 += int64(math.Abs(float64(enc.l3loop.Xm[0][sfb]) - float64(enc.l3loop.Xm[1][sfb]))) + } + if sum0 < enScfsiBandKrit && sum1 < xmScfsiBandKrit { + l3_side.ScaleFactorSelectInfo[ch][scfsi_band] = 1 + } else { + l3_side.ScaleFactorSelectInfo[ch][scfsi_band] = 0 + } + } + } else { + for scfsi_band = 0; scfsi_band < 4; scfsi_band++ { + l3_side.ScaleFactorSelectInfo[ch][scfsi_band] = 0 + } + } + } +} + +// calcPart2Length calculates the number of bits needed to encode the scaleFactor in the +// main data block. +func (enc *Encoder) calcPart2Length(gr int64, ch int64) int64 { + var ( + slen1 int64 + slen2 int64 + bits int64 + gi *GranuleInfo = &enc.sideInfo.Granules[gr].Channels[ch].Tt + ) + bits = 0 + { + slen1 = slen1Table[gi.ScaleFactorCompress] + slen2 = slen2Table[gi.ScaleFactorCompress] + if gr == 0 || (enc.sideInfo.ScaleFactorSelectInfo[ch][0]) == 0 { + bits += slen1 * 6 + } + if gr == 0 || (enc.sideInfo.ScaleFactorSelectInfo[ch][1]) == 0 { + bits += slen1 * 5 + } + if gr == 0 || (enc.sideInfo.ScaleFactorSelectInfo[ch][2]) == 0 { + bits += slen2 * 5 + } + if gr == 0 || (enc.sideInfo.ScaleFactorSelectInfo[ch][3]) == 0 { + bits += slen2 * 5 + } + } + return bits +} + +// calcXMin calculates the allowed distortion for each scalefactor band, +// as determined by the psychoacoustic model. xmin(sb) = ratio(sb) * en(sb) / bw(sb) +func calcXMin(ratio *PsyRatio, cod_info *GranuleInfo, l3_xmin *PsyXMin, gr int64, ch int64) { + var sfb int64 + for sfb = int64(cod_info.ScaleFactorBandMaxLen); func() int64 { + p := &sfb + x := *p + *p-- + return x + }() != 0; { + l3_xmin.L[gr][ch][sfb] = 0 + } +} + +// loopInitialize calculates the look up tables used by the iteration loop. +func (enc *Encoder) loopInitialize() { + var i int64 + for i = 128; func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + enc.l3loop.StepTable[i] = math.Pow(2.0, float64(127-i)/4) + if (enc.l3loop.StepTable[i] * 2) > math.MaxInt32 { + enc.l3loop.StepTableI[i] = math.MaxInt32 + } else { + enc.l3loop.StepTableI[i] = int32((enc.l3loop.StepTable[i] * 2) + 0.5) + } + } + for i = 10000; func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + enc.l3loop.Int2idx[i] = int64(math.Sqrt(math.Sqrt(float64(i))*float64(i)) - 0.0946 + 0.5) + } +} + +// quantize perform quantization of the vector xr ( -> ix). +// Returns maximum value of ix +func (enc *Encoder) quantize(ix *[GRANULE_SIZE]int64, stepsize int64) int64 { + var ( + i int64 + max int64 + ln int64 + scalei int32 + scale float64 + dbl float64 + ) + scalei = enc.l3loop.StepTableI[stepsize+127] + if int64(int32((((int64(enc.l3loop.Xrmax))*(int64(scalei)))+0x80000000)>>32)) > 165140 { + max = 16384 + } else { + for i = 0; i < GRANULE_SIZE; i++ { + ln = int64(mulR(int32(math.Abs(float64(enc.l3loop.Xr[i]))), scalei)) + if ln < 10000 { + ix[i] = enc.l3loop.Int2idx[ln] + } else { + scale = enc.l3loop.StepTable[stepsize+math.MaxInt8] + dbl = (float64(enc.l3loop.Xrabs[i])) * scale * 4.656612875e-10 + ix[i] = int64(math.Sqrt(math.Sqrt(dbl) * dbl)) + } + if max < ix[i] { + max = ix[i] + } + } + } + return max +} + +// ixMax calculates the maximum of ix from 0 to 575 +func ixMax(ix *[GRANULE_SIZE]int64, begin uint64, end uint64) int64 { + var ( + i int64 + max int64 = 0 + ) + for i = int64(begin); uint64(i) < end; i++ { + if max < ix[i] { + max = ix[i] + } + } + return max +} + +// calcRunLength calculates rZero, count1, big_values (Partitions ix into big values, quadruples and zeros) +func calcRunLength(ix *[GRANULE_SIZE]int64, cod_info *GranuleInfo) { + var ( + i int64 + rzero int64 = 0 + ) + for i = GRANULE_SIZE; i > 1; i -= 2 { + if ix[i-1] == 0 && ix[i-2] == 0 { + rzero++ + } else { + break + } + } + cod_info.Count1 = 0 + for ; i > 3; i -= 4 { + if ix[i-1] <= 1 && ix[i-2] <= 1 && ix[i-3] <= 1 && ix[i-4] <= 1 { + cod_info.Count1++ + } else { + break + } + } + cod_info.BigValues = uint64(i >> 1) +} + +// count1BitCount determines the number of bits to encode the quadruples. +func count1BitCount(ix *[GRANULE_SIZE]int64, cod_info *GranuleInfo) int64 { + var ( + p int64 + i int64 + k int64 + v int64 + w int64 + x int64 + y int64 + signbits int64 + sum0 int64 = 0 + sum1 int64 = 0 + ) + for func() int64 { + i = int64(cod_info.BigValues << 1) + return func() int64 { + k = 0 + return k + }() + }(); uint64(k) < cod_info.Count1; func() int64 { + i += 4 + return func() int64 { + p := &k + x := *p + *p++ + return x + }() + }() { + v = ix[i] + w = ix[i+1] + x = ix[i+2] + y = ix[i+3] + p = v + (w << 1) + (x << 2) + (y << 3) + signbits = 0 + if v != 0 { + signbits++ + } + if w != 0 { + signbits++ + } + if x != 0 { + signbits++ + } + if y != 0 { + signbits++ + } + sum0 += signbits + sum1 += signbits + sum0 += int64(huffmanCodeTable[32].hLen[p]) + sum1 += int64(huffmanCodeTable[33].hLen[p]) + } + if sum0 < sum1 { + cod_info.Count1TableSelect = 0 + return sum0 + } else { + cod_info.Count1TableSelect = 1 + return sum1 + } +} + +// subDivide subdivides the bigValue region which will use separate Huffman tables. +func (enc *Encoder) subDivide(cod_info *GranuleInfo) { + var subdv_table [23]struct { + Region0_count uint64 + Region1_count uint64 + } = [23]struct { + Region0_count uint64 + Region1_count uint64 + }{{}, {}, {}, {}, {}, {Region0_count: 0, Region1_count: 1}, {Region0_count: 1, Region1_count: 1}, {Region0_count: 1, Region1_count: 1}, {Region0_count: 1, Region1_count: 2}, {Region0_count: 2, Region1_count: 2}, {Region0_count: 2, Region1_count: 3}, {Region0_count: 2, Region1_count: 3}, {Region0_count: 3, Region1_count: 4}, {Region0_count: 3, Region1_count: 4}, {Region0_count: 3, Region1_count: 4}, {Region0_count: 4, Region1_count: 5}, {Region0_count: 4, Region1_count: 5}, {Region0_count: 4, Region1_count: 6}, {Region0_count: 5, Region1_count: 6}, {Region0_count: 5, Region1_count: 6}, {Region0_count: 5, Region1_count: 7}, {Region0_count: 6, Region1_count: 7}, {Region0_count: 6, Region1_count: 7}} + if cod_info.BigValues == 0 { + cod_info.Region0Count = 0 + cod_info.Region1Count = 0 + } else { + var ( + scalefac_band_long []int64 = scaleFactorBandIndex[enc.Mpeg.SampleRateIndex][:] + bigvalues_region int64 + scfb_anz int64 + thiscount int64 + ) + bigvalues_region = int64(cod_info.BigValues * 2) + scfb_anz = 0 + for scalefac_band_long[scfb_anz] < bigvalues_region { + scfb_anz++ + } + for thiscount = int64(subdv_table[scfb_anz].Region0_count); thiscount != 0; thiscount-- { + if scalefac_band_long[thiscount+1] <= bigvalues_region { + break + } + } + cod_info.Region0Count = uint64(thiscount) + cod_info.Address1 = uint64(scalefac_band_long[thiscount+1]) + scalefac_band_long = scalefac_band_long[cod_info.Region0Count+1:] + for thiscount = int64(subdv_table[scfb_anz].Region1_count); thiscount != 0; thiscount-- { + if scalefac_band_long[thiscount+1] <= bigvalues_region { + break + } + } + cod_info.Region1Count = uint64(thiscount) + cod_info.Address2 = uint64(scalefac_band_long[thiscount+1]) + cod_info.Address3 = uint64(bigvalues_region) + } +} + +// bigValuesTableSelect selects huffman code tables for the bigValues region +func bigValuesTableSelect(ix *[GRANULE_SIZE]int64, cod_info *GranuleInfo) { + cod_info.TableSelect[0] = 0 + cod_info.TableSelect[1] = 0 + cod_info.TableSelect[2] = 0 + { + if cod_info.Address1 > 0 { + cod_info.TableSelect[0] = uint64(newChooseTable(ix, 0, cod_info.Address1)) + } + if cod_info.Address2 > cod_info.Address1 { + cod_info.TableSelect[1] = uint64(newChooseTable(ix, cod_info.Address1, cod_info.Address2)) + } + if cod_info.BigValues<<1 > cod_info.Address2 { + cod_info.TableSelect[2] = uint64(newChooseTable(ix, cod_info.Address2, cod_info.BigValues<<1)) + } + } +} + +// newChooseTable chooses the Huffman table that will encode ix[begin..end] with the fewest bits. +// Note: This code contains knowledge about the sizes and characteristics of the Huffman tables as +// defined in the IS (Table B.7), and will not work with any arbitrary tables. +func newChooseTable(ix *[GRANULE_SIZE]int64, begin uint64, end uint64) int64 { + var ( + i int64 + max int64 + choice [2]int64 + sum [2]int64 + ) + max = ixMax(ix, begin, end) + if max == 0 { + return 0 + } + choice[0] = 0 + choice[1] = 0 + if max < 15 { + for i = 14; func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + if huffmanCodeTable[i].xLen > uint(max) { + choice[0] = i + break + } + } + sum[0] = countBit(ix, begin, end, uint64(choice[0])) + switch choice[0] { + case 2: + sum[1] = countBit(ix, begin, end, 3) + if sum[1] <= sum[0] { + choice[0] = 3 + } + case 5: + sum[1] = countBit(ix, begin, end, 6) + if sum[1] <= sum[0] { + choice[0] = 6 + } + case 7: + sum[1] = countBit(ix, begin, end, 8) + if sum[1] <= sum[0] { + choice[0] = 8 + sum[0] = sum[1] + } + sum[1] = countBit(ix, begin, end, 9) + if sum[1] <= sum[0] { + choice[0] = 9 + } + case 10: + sum[1] = countBit(ix, begin, end, 11) + if sum[1] <= sum[0] { + choice[0] = 11 + sum[0] = sum[1] + } + sum[1] = countBit(ix, begin, end, 12) + if sum[1] <= sum[0] { + choice[0] = 12 + } + case 13: + sum[1] = countBit(ix, begin, end, 15) + if sum[1] <= sum[0] { + choice[0] = 15 + } + } + } else { + max -= 15 + for i = 15; i < 24; i++ { + if huffmanCodeTable[i].linMax >= uint(max) { + choice[0] = i + break + } + } + for i = 24; i < 32; i++ { + if huffmanCodeTable[i].linMax >= uint(max) { + choice[1] = i + break + } + } + sum[0] = countBit(ix, begin, end, uint64(choice[0])) + sum[1] = countBit(ix, begin, end, uint64(choice[1])) + if sum[1] < sum[0] { + choice[0] = choice[1] + } + } + return choice[0] +} + +// bigValuesBitCount Count the number of bits necessary to code the bigValues region. +func bigValuesBitCount(ix *[GRANULE_SIZE]int64, gi *GranuleInfo) int64 { + var ( + bits int64 = 0 + table uint64 + ) + if (func() uint64 { + table = gi.TableSelect[0] + return table + }()) != 0 { + bits += countBit(ix, 0, gi.Address1, table) + } + if (func() uint64 { + table = gi.TableSelect[1] + return table + }()) != 0 { + bits += countBit(ix, gi.Address1, gi.Address2, table) + } + if (func() uint64 { + table = gi.TableSelect[2] + return table + }()) != 0 { + bits += countBit(ix, gi.Address2, gi.Address3, table) + } + return bits +} + +// countBit counts the number of bits necessary to code the subregion. +func countBit(ix *[GRANULE_SIZE]int64, start uint64, end uint64, table uint64) int64 { + var ( + linbits uint64 + ylen uint64 + i int64 + sum int64 + x int64 + y int64 + h *huffCodeTableInfo + ) + if table == 0 { + return 0 + } + h = &(huffmanCodeTable[table]) + sum = 0 + ylen = uint64(h.yLen) + linbits = uint64(h.linBits) + if table > 15 { + for i = int64(start); uint64(i) < end; i += 2 { + x = ix[i] + y = ix[i+1] + if x > 14 { + x = 15 + sum += int64(linbits) + } + if y > 14 { + y = 15 + sum += int64(linbits) + } + sum += int64(h.hLen[x*int64(ylen)+y]) + if x != 0 { + sum++ + } + if y != 0 { + sum++ + } + } + } else { + for i = int64(start); uint64(i) < end; i += 2 { + x = ix[i] + y = ix[i+1] + sum += int64(h.hLen[x*int64(ylen)+y]) + if x != 0 { + sum++ + } + if y != 0 { + sum++ + } + } + } + return sum +} + +// binSearchStepSize successively approximates an approach to obtaining a initial quantizer +// step size. The following optional code written by Seymour Shlien will speed up the shine_outer_loop code which is +// called by iteration_loop. When BIN_SEARCH is defined, the shine_outer_loop function precedes the call to the +// function shine_inner_loop with a call to bin_search gain defined below, which returns a good starting quantizerStepSize. +func (enc *Encoder) binSearchStepSize(desired_rate int64, ix *[GRANULE_SIZE]int64, cod_info *GranuleInfo) int64 { + var ( + bit int64 + next int64 + count int64 + ) + next = -120 + count = 120 + for { + { + var half int64 = count / 2 + if enc.quantize(ix, next+half) > 8192 { + bit = 100000 + } else { + calcRunLength(ix, cod_info) + bit = count1BitCount(ix, cod_info) + enc.subDivide(cod_info) + bigValuesTableSelect(ix, cod_info) + bit += bigValuesBitCount(ix, cod_info) + } + if bit < desired_rate { + count = half + } else { + next += half + count -= half + } + } + if count <= 1 { + break + } + } + return next +} diff --git a/pkg/mp3/l3mdct.go b/pkg/mp3/l3mdct.go new file mode 100644 index 0000000..85b0c05 --- /dev/null +++ b/pkg/mp3/l3mdct.go @@ -0,0 +1,159 @@ +package mp3 + +import ( + "math" +) + +// This is table B.9: coefficients for aliasing reduction +func MDCT_CA(coefficient float64) int32 { + return int32(coefficient / math.Sqrt(1.0+(coefficient*coefficient)) * float64(math.MaxInt32)) +} +func MDCT_CS(coefficient float64) int32 { + return int32(1.0 / math.Sqrt(1.0+(coefficient*coefficient)) * float64(math.MaxInt32)) +} + +var ( + MDCT_CA0 = MDCT_CA(-0.6) + MDCT_CA1 = MDCT_CA(-0.535) + MDCT_CA2 = MDCT_CA(-0.33) + MDCT_CA3 = MDCT_CA(-0.185) + MDCT_CA4 = MDCT_CA(-0.095) + MDCT_CA5 = MDCT_CA(-0.041) + MDCT_CA6 = MDCT_CA(-0.0142) + MDCT_CA7 = MDCT_CA(-0.0037) + + MDCT_CS0 = MDCT_CS(-0.6) + MDCT_CS1 = MDCT_CS(-0.535) + MDCT_CS2 = MDCT_CS(-0.33) + MDCT_CS3 = MDCT_CS(-0.185) + MDCT_CS4 = MDCT_CS(-0.095) + MDCT_CS5 = MDCT_CS(-0.041) + MDCT_CS6 = MDCT_CS(-0.0142) + MDCT_CS7 = MDCT_CS(-0.0037) +) + +func (enc *Encoder) mdctInitialize() { + var ( + m int64 + k int64 + ) + for m = 18; func() int64 { + p := &m + x := *p + *p-- + return x + }() != 0; { + for k = 36; func() int64 { + p := &k + x := *p + *p-- + return x + }() != 0; { + enc.mdct.CosL[m][k] = int32(math.Sin(PI36*(float64(k)+0.5)) * math.Cos((PI/72)*float64(k*2+19)*float64(m*2+1)) * math.MaxInt32) + } + } +} +func (enc *Encoder) mdctSub(stride int64) { + var ( + ch int64 + gr int64 + band int64 + j int64 + k int64 + mdct_in [36]int32 + ) + for ch = enc.Wave.Channels; func() int64 { + p := &ch + x := *p + *p-- + return x + }() != 0; { + for gr = 0; gr < enc.Mpeg.GranulesPerFrame; gr++ { + mdct_enc := &enc.mdctFrequency[ch][gr] + for k = 0; k < 18; k += 2 { + enc.windowFilterSubband(&enc.buffer[ch], &enc.l3SubbandSamples[ch][gr+1][k], ch, stride) + enc.windowFilterSubband(&enc.buffer[ch], &enc.l3SubbandSamples[ch][gr+1][k+1], ch, stride) + for band = 1; band < 32; band += 2 { + enc.l3SubbandSamples[ch][gr+1][k+1][band] *= -1 + } + } + for band = 0; band < 32; band++ { + for k = 18; func() int64 { + p := &k + x := *p + *p-- + return x + }() != 0; { + mdct_in[k] = enc.l3SubbandSamples[ch][gr][k][band] + mdct_in[k+18] = enc.l3SubbandSamples[ch][gr+1][k][band] + } + for k = 18; func() int64 { + p := &k + x := *p + *p-- + return x + }() != 0; { + var ( + vm int32 + vm_lo uint32 + ) + _ = vm_lo + vm = int32(((int64(mdct_in[35])) * (int64(enc.mdct.CosL[k][35]))) >> 32) + for j = 35; j != 0; j -= 7 { + vm += mul(mdct_in[j-1], enc.mdct.CosL[k][j-1]) + vm += mul(mdct_in[j-2], enc.mdct.CosL[k][j-2]) + vm += mul(mdct_in[j-3], enc.mdct.CosL[k][j-3]) + vm += mul(mdct_in[j-4], enc.mdct.CosL[k][j-4]) + vm += mul(mdct_in[j-5], enc.mdct.CosL[k][j-5]) + vm += mul(mdct_in[j-6], enc.mdct.CosL[k][j-6]) + vm += mul(mdct_in[j-7], enc.mdct.CosL[k][j-7]) + } + mdct_enc[band*18+k] = vm + } + // Perform aliasing reduction butterfly + if band != 0 { + mdct_enc[band*18+0], mdct_enc[(band-1)*18+17-0] = cmuls( + &mdct_enc[band*18+0], &mdct_enc[(band-1)*18+17-0], + &MDCT_CS0, &MDCT_CA0, + ) + + mdct_enc[band*18+1], mdct_enc[(band-1)*18+17-1] = cmuls( + &mdct_enc[band*18+1], &mdct_enc[(band-1)*18+17-1], + &MDCT_CS1, &MDCT_CA1, + ) + + mdct_enc[band*18+2], mdct_enc[(band-1)*18+17-2] = cmuls( + &mdct_enc[band*18+2], &mdct_enc[(band-1)*18+17-2], + &MDCT_CS2, &MDCT_CA2, + ) + + mdct_enc[band*18+3], mdct_enc[(band-1)*18+17-3] = cmuls( + &mdct_enc[band*18+3], &mdct_enc[(band-1)*18+17-3], + &MDCT_CS3, &MDCT_CA3, + ) + + mdct_enc[band*18+4], mdct_enc[(band-1)*18+17-4] = cmuls( + &mdct_enc[band*18+4], &mdct_enc[(band-1)*18+17-4], + &MDCT_CS4, &MDCT_CA4, + ) + + mdct_enc[band*18+5], mdct_enc[(band-1)*18+17-5] = cmuls( + &mdct_enc[band*18+5], &mdct_enc[(band-1)*18+17-5], + &MDCT_CS5, &MDCT_CA5, + ) + + mdct_enc[band*18+6], mdct_enc[(band-1)*18+17-6] = cmuls( + &mdct_enc[band*18+6], &mdct_enc[(band-1)*18+17-6], + &MDCT_CS6, &MDCT_CA6, + ) + + mdct_enc[band*18+7], mdct_enc[(band-1)*18+17-7] = cmuls( + &mdct_enc[band*18+7], &mdct_enc[(band-1)*18+17-7], + &MDCT_CS7, &MDCT_CA7, + ) + } + } + } + copy(enc.l3SubbandSamples[ch][0][:], enc.l3SubbandSamples[ch][enc.Mpeg.GranulesPerFrame][:]) + } +} diff --git a/pkg/mp3/l3subband.go b/pkg/mp3/l3subband.go new file mode 100644 index 0000000..415c942 --- /dev/null +++ b/pkg/mp3/l3subband.go @@ -0,0 +1,118 @@ +package mp3 + +import ( + "math" + "unsafe" +) + +// subbandInitialize calculates the analysis filterbank coefficients and rounds to the 9th decimal +// place accuracy of the filterbank tables in the ISO document. The coefficients are stored in #filter# +func (enc *Encoder) subbandInitialize() { + var ( + i int64 + j int64 + filter float64 + ) + for i = MAX_CHANNELS; func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + enc.subband.Off[i] = 0 + enc.subband.X[i] = [HAN_SIZE]int32{} + } + for i = SUBBAND_LIMIT; func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + for j = 64; func() int64 { + p := &j + x := *p + *p-- + return x + }() != 0; { + if (func() float64 { + filter = math.Cos(float64((i*2+1)*(16-j))*PI64) * 1e+09 + return filter + }()) >= 0 { + filter, _ = math.Modf(filter + 0.5) + } else { + filter, _ = math.Modf(filter - 0.5) + } + enc.subband.Fl[i][j] = int32(filter * (math.MaxInt32 * 1e-09)) + } + } +} + +// Overlapping window on PCM samples 32 16-bit pcm samples are scaled to fractional 2's complement and +// concatenated to the end of the window buffer #x#. The updated window buffer #x# is then windowed by +// the analysis window #shine_enwindow# to produce the windowed sample #z# Calculates the analysis filter bank +// coefficients The windowed samples #z# is filtered by the digital filter matrix #filter# to produce the subband +// samples #s#. This done by first selectively picking out values from the windowed samples, and then +// multiplying them by the filter matrix, producing 32 subband samples. +func (enc *Encoder) windowFilterSubband(buffer **int16, s *[32]int32, ch int64, stride int64) { + var ( + y [64]int32 + i int64 + j int64 + ptr *int16 = *buffer + ) + for i = 32; func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + enc.subband.X[ch][i+enc.subband.Off[ch]] = int32(int64(int32(*ptr)) << 16) + ptr = (*int16)(unsafe.Add(unsafe.Pointer(ptr), unsafe.Sizeof(int16(0))*uintptr(stride))) + } + *buffer = ptr + for i = 64; func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + var ( + s_value int32 + s_value_lo uint32 + ) + _ = s_value_lo + s_value = int32(((int64(enc.subband.X[ch][(enc.subband.Off[ch]+i+(0<<6))&(HAN_SIZE-1)])) * (int64(enWindow[i+(0<<6)]))) >> 32) + s_value += int32(((int64(enc.subband.X[ch][(enc.subband.Off[ch]+i+(1<<6))&(HAN_SIZE-1)])) * (int64(enWindow[i+(1<<6)]))) >> 32) + s_value += int32(((int64(enc.subband.X[ch][(enc.subband.Off[ch]+i+(2<<6))&(HAN_SIZE-1)])) * (int64(enWindow[i+(2<<6)]))) >> 32) + s_value += int32(((int64(enc.subband.X[ch][(enc.subband.Off[ch]+i+(3<<6))&(HAN_SIZE-1)])) * (int64(enWindow[i+(3<<6)]))) >> 32) + s_value += int32(((int64(enc.subband.X[ch][(enc.subband.Off[ch]+i+(4<<6))&(HAN_SIZE-1)])) * (int64(enWindow[i+(4<<6)]))) >> 32) + s_value += int32(((int64(enc.subband.X[ch][(enc.subband.Off[ch]+i+(5<<6))&(HAN_SIZE-1)])) * (int64(enWindow[i+(5<<6)]))) >> 32) + s_value += int32(((int64(enc.subband.X[ch][(enc.subband.Off[ch]+i+(6<<6))&(HAN_SIZE-1)])) * (int64(enWindow[i+(6<<6)]))) >> 32) + s_value += int32(((int64(enc.subband.X[ch][(enc.subband.Off[ch]+i+(7<<6))&(HAN_SIZE-1)])) * (int64(enWindow[i+(7<<6)]))) >> 32) + y[i] = s_value + } + enc.subband.Off[ch] = (enc.subband.Off[ch] + 480) & (HAN_SIZE - 1) + for i = SUBBAND_LIMIT; func() int64 { + p := &i + x := *p + *p-- + return x + }() != 0; { + var ( + s_value int32 + s_value_lo uint32 + ) + _ = s_value_lo + s_value = int32(((int64(enc.subband.Fl[i][63])) * (int64(y[63]))) >> 32) + for j = 63; j != 0; j -= 7 { + s_value += int32(((int64(enc.subband.Fl[i][j-1])) * (int64(y[j-1]))) >> 32) + s_value += int32(((int64(enc.subband.Fl[i][j-2])) * (int64(y[j-2]))) >> 32) + s_value += int32(((int64(enc.subband.Fl[i][j-3])) * (int64(y[j-3]))) >> 32) + s_value += int32(((int64(enc.subband.Fl[i][j-4])) * (int64(y[j-4]))) >> 32) + s_value += int32(((int64(enc.subband.Fl[i][j-5])) * (int64(y[j-5]))) >> 32) + s_value += int32(((int64(enc.subband.Fl[i][j-6])) * (int64(y[j-6]))) >> 32) + s_value += int32(((int64(enc.subband.Fl[i][j-7])) * (int64(y[j-7]))) >> 32) + } + s[i] = s_value + } +} diff --git a/pkg/mp3/layer3.go b/pkg/mp3/layer3.go new file mode 100644 index 0000000..7dcb34d --- /dev/null +++ b/pkg/mp3/layer3.go @@ -0,0 +1,201 @@ +package mp3 + +import ( + "encoding/binary" + "io" + "unsafe" +) + +const SHINE_MAX_SAMPLES = 1152 + +type channel int + +const ( + PCM_MONO channel = 1 + PCM_STEREO channel = 2 +) + +type mpegVersion int + +const ( + MPEG_25 mpegVersion = 0 + MPEG_II mpegVersion = 2 + MPEG_I mpegVersion = 3 +) + +type mpegLayer int + +// Only Layer III currently implemented +const LAYER_III mpegLayer = 1 + +var mpegGranulesPerFrame = [4]int{ + // MPEG 2.5 + 1, + // Reserved + -1, + // MPEG II + 1, + // MPEG I + 2, +} + +func getMpegVersion(sampleRateIndex int) mpegVersion { + if sampleRateIndex < 3 { + return MPEG_I + } else if sampleRateIndex < 6 { + return MPEG_II + } else { + return MPEG_25 + } +} + +// findSampleRateIndex checks if a given sampleRate is supported by the encoder +func findSampleRateIndex(freq int) int { + var i int + for i = 0; i < 9; i++ { + if freq == int(sampleRates[i]) { + return i + } + } + return -1 +} + +// findBitrateIndex checks if a given bitrate is supported by the encoder +func findBitrateIndex(bitr int, mpeg_version mpegVersion) int { + var i int + for i = 0; i < 16; i++ { + if bitr == int(bitRates[i][mpeg_version]) { + return i + } + } + return -1 +} + +// CheckConfig checks if a given bitrate and samplerate is supported by the encoder +func CheckConfig(freq int, bitr int) mpegVersion { + var ( + samplerate_index int + bitrate_index int + ) + samplerate_index = findSampleRateIndex(freq) + if samplerate_index < 0 { + return -1 + } + mpeg_version := getMpegVersion(samplerate_index) + bitrate_index = findBitrateIndex(bitr, mpeg_version) + if bitrate_index < 0 { + return -1 + } + return mpeg_version +} + +// samplesPerPass returns the audio samples expected in each frame. +func (enc *Encoder) samplesPerPass() int64 { + return enc.Mpeg.GranulesPerFrame * GRANULE_SIZE +} +func NewEncoder(sampleRate, channels int) *Encoder { + var ( + avg_slots_per_frame float64 + ) + + enc := new(Encoder) + + if channels > 1 { + enc.Mpeg.Mode = STEREO + } else { + enc.Mpeg.Mode = MONO + } + + enc.subbandInitialize() + enc.mdctInitialize() + enc.loopInitialize() + enc.Wave.Channels = int64(channels) + enc.Wave.SampleRate = int64(sampleRate) + enc.Mpeg.Bitrate = 128 + enc.Mpeg.Emph = NONE + enc.Mpeg.Copyright = 0 + enc.Mpeg.Original = 1 + enc.reservoirMaxSize = 0 + enc.reservoirSize = 0 + enc.Mpeg.Layer = int64(LAYER_III) + enc.Mpeg.Crc = 0 + enc.Mpeg.Ext = 0 + enc.Mpeg.ModeExt = 0 + enc.Mpeg.BitsPerSlot = 8 + enc.Mpeg.SampleRateIndex = int64(findSampleRateIndex(int(enc.Wave.SampleRate))) + enc.Mpeg.Version = getMpegVersion(int(enc.Mpeg.SampleRateIndex)) + enc.Mpeg.BitrateIndex = int64(findBitrateIndex(int(enc.Mpeg.Bitrate), enc.Mpeg.Version)) + enc.Mpeg.GranulesPerFrame = int64(mpegGranulesPerFrame[enc.Mpeg.Version]) + avg_slots_per_frame = (float64(enc.Mpeg.GranulesPerFrame) * GRANULE_SIZE / (float64(enc.Wave.SampleRate))) * (float64(enc.Mpeg.Bitrate) * 1000 / float64(enc.Mpeg.BitsPerSlot)) + enc.Mpeg.WholeSlotsPerFrame = int64(avg_slots_per_frame) + enc.Mpeg.FracSlotsPerFrame = avg_slots_per_frame - float64(enc.Mpeg.WholeSlotsPerFrame) + enc.Mpeg.Slot_lag = -enc.Mpeg.FracSlotsPerFrame + if enc.Mpeg.FracSlotsPerFrame == 0 { + enc.Mpeg.Padding = 0 + } + enc.bitstream.open(BUFFER_SIZE) + if enc.Mpeg.GranulesPerFrame == 2 { + enc.sideInfoLen = (func() int64 { + if enc.Wave.Channels == 1 { + return 4 + 17 + } + return 4 + 32 + }()) * 8 + } else { + enc.sideInfoLen = (func() int64 { + if enc.Wave.Channels == 1 { + return 4 + 9 + } + return 4 + 17 + }()) * 8 + } + return enc +} +func (enc *Encoder) encodeBufferInternal(stride int) ([]uint8, int) { + if enc.Mpeg.FracSlotsPerFrame != 0 { + if enc.Mpeg.Slot_lag <= (enc.Mpeg.FracSlotsPerFrame - 1.0) { + enc.Mpeg.Padding = 1 + } else { + enc.Mpeg.Padding = 0 + } + enc.Mpeg.Slot_lag += float64(enc.Mpeg.Padding) - enc.Mpeg.FracSlotsPerFrame + } + enc.Mpeg.BitsPerFrame = (enc.Mpeg.WholeSlotsPerFrame + enc.Mpeg.Padding) * 8 + enc.meanBits = (enc.Mpeg.BitsPerFrame - enc.sideInfoLen) / enc.Mpeg.GranulesPerFrame + enc.mdctSub(int64(stride)) + enc.iterationLoop() + enc.formatBitstream() + written := enc.bitstream.dataPosition + enc.bitstream.dataPosition = 0 + return enc.bitstream.data, written +} + +func (enc *Encoder) encodeBufferInterleaved(data *int16) ([]uint8, int) { + enc.buffer[0] = data + if enc.Wave.Channels == 2 { + enc.buffer[1] = (*int16)(unsafe.Add(unsafe.Pointer(data), unsafe.Sizeof(int16(0))*1)) + } + return enc.encodeBufferInternal(int(enc.Wave.Channels)) +} + +func (enc *Encoder) Write(out io.Writer, data []int16) error { + samples_per_pass := int(enc.samplesPerPass()) + + samplesRead := len(data) + for i := 0; i < samplesRead; i += samples_per_pass * 2 { + end := i + samples_per_pass + if end > samplesRead { + end = samplesRead + } + + chunk := data[i:end] + + // Encode and write the chunk to the output file. + data, written := enc.encodeBufferInterleaved(&chunk[0]) + err := binary.Write(out, binary.LittleEndian, data[:written]) + if err != nil { + return err + } + } + return nil +} diff --git a/pkg/mp3/multiply.go b/pkg/mp3/multiply.go new file mode 100644 index 0000000..2a8a753 --- /dev/null +++ b/pkg/mp3/multiply.go @@ -0,0 +1,28 @@ +package mp3 + +/* +Functions for efficient multiplication operations with 32-bit integers. They rely on bitwise manipulation and shifting to perform multiplication and rounding to achieve fixed-point arithmetic. +*/ + +// mul safely multiples a and b and returns the result. +// By casting to int64 first, overflow is avoided. +func mul(a, b int32) int32 { + return int32((int64(a) * int64(b)) >> 32) +} + +func mulR(a, b int32) int32 { + return int32(((int64(a) * int64(b)) + 0x80000000) >> 32) +} + +// mulSR is similar to mulS but with rounding. +func mulSR(a, b int32) int32 { + return int32(((int64(a) * int64(b)) + 0x40000000) >> 31) +} + +// cmuls multiples two complex numbers together. +func cmuls(aReal, aImag, bReal, bImag *int32) (int32, int32) { + resReal := int32(((int64(*aReal)*int64(*bReal) - int64(*aImag)*int64(*bImag)) >> 31)) + resImag := int32(((int64(*aReal)*int64(*bImag) + int64(*aImag)*int64(*bReal)) >> 31)) + + return resReal, resImag +} diff --git a/pkg/mp3/reservoir.go b/pkg/mp3/reservoir.go new file mode 100644 index 0000000..da8e053 --- /dev/null +++ b/pkg/mp3/reservoir.go @@ -0,0 +1,103 @@ +// Layer3 bit reservoir: Described in C.1.5.4.2.2 of the IS +package mp3 + +// maxReservoirBits is called at the beginning of each granule to get the max bit +// allowance for the current granule based on reservoir size and perceptual entropy. +func (enc *Encoder) maxReservoirBits(pe *float64) int64 { + var ( + more_bits int64 + max_bits int64 + add_bits int64 + over_bits int64 + mean_bits int64 = enc.meanBits + ) + mean_bits /= enc.Wave.Channels + max_bits = mean_bits + if max_bits > 4095 { + max_bits = 4095 + } + if enc.reservoirMaxSize == 0 { + return max_bits + } + more_bits = int64(*pe*3.1 - float64(mean_bits)) + add_bits = 0 + if more_bits > 100 { + var frac int64 = (enc.reservoirSize * 6) / 10 + if frac < more_bits { + add_bits = frac + } else { + add_bits = more_bits + } + } + over_bits = enc.reservoirSize - (enc.reservoirMaxSize<<3)/10 - add_bits + if over_bits > 0 { + add_bits += over_bits + } + max_bits += add_bits + if max_bits > 4095 { + max_bits = 4095 + } + return max_bits +} + +// reservoirAdjust is called after a granule's bit allocation. It readjusts the size of +// the reservoir to reflect the granule's usage. +func (enc *Encoder) reservoirAdjust(gi *GranuleInfo) { + enc.reservoirSize += int64(uint64(enc.meanBits/enc.Wave.Channels) - gi.Part2_3Length) +} +func (enc *Encoder) reservoirFrameEnd() { + var ( + gi *GranuleInfo + gr int64 + ch int64 + ancillary_pad int64 + stuffingBits int64 + over_bits int64 + l3_side *SideInfo = &enc.sideInfo + ) + ancillary_pad = 0 + if enc.Wave.Channels == 2 && (enc.meanBits&1) != 0 { + enc.reservoirSize += 1 + } + over_bits = enc.reservoirSize - enc.reservoirMaxSize + if over_bits < 0 { + over_bits = 0 + } + enc.reservoirSize -= over_bits + stuffingBits = over_bits + ancillary_pad + if (func() int64 { + over_bits = enc.reservoirSize % 8 + return over_bits + }()) != 0 { + stuffingBits += over_bits + enc.reservoirSize -= over_bits + } + if stuffingBits != 0 { + gi = &(l3_side.Granules[0].Channels[0]).Tt + if gi.Part2_3Length+uint64(stuffingBits) < 4095 { + gi.Part2_3Length += uint64(stuffingBits) + } else { + for gr = 0; gr < enc.Mpeg.GranulesPerFrame; gr++ { + for ch = 0; ch < enc.Wave.Channels; ch++ { + var ( + extraBits int64 + bitsThisGr int64 + gi *GranuleInfo = &(l3_side.Granules[gr].Channels[ch]).Tt + ) + if stuffingBits == 0 { + break + } + extraBits = int64(4095 - gi.Part2_3Length) + if extraBits < stuffingBits { + bitsThisGr = extraBits + } else { + bitsThisGr = stuffingBits + } + gi.Part2_3Length += uint64(bitsThisGr) + stuffingBits -= bitsThisGr + } + } + l3_side.ReservoirDrain = stuffingBits + } + } +} diff --git a/pkg/mp3/tables.go b/pkg/mp3/tables.go new file mode 100644 index 0000000..ac3a69a --- /dev/null +++ b/pkg/mp3/tables.go @@ -0,0 +1,187 @@ +/* + * Here are MPEG1 Table B.8 and MPEG2 Table B.1 -- Layer III scalefactor bands. + * Index into this using a method such as: + * idx = fr_ps->header->sampling_frequency + (fr_ps->header->version * 3) + */ +package mp3 + +var ( + slen1Table = [16]int64{ + 0, 0, 0, 0, 3, 1, 1, 1, + 2, 2, 2, 3, 3, 3, 4, 4, + } + slen2Table = [16]int64{ + 0, 1, 2, 3, 0, 1, 2, 3, + 1, 2, 3, 1, 2, 3, 2, 3, + } + + sampleRates = [9]int64{ + // MPEG-1 + 44100, 48000, 32000, + // MPEG-II + 22050, 24000, 16000, + // MPEG-2.5 + 11025, 12000, 8000, + } + + bitRates = [16][4]int64{ + // MPEG version: + // 2.5, reserved, II, I + {-1, -1, -1, -1}, {8, -1, 8, 32}, {16, -1, 16, 40}, {24, -1, 24, 48}, + {32, -1, 32, 56}, {40, -1, 40, 64}, {48, -1, 48, 80}, {56, -1, 56, 96}, + {64, -1, 64, 112}, {-1, -1, 80, 128}, {-1, -1, 96, 160}, {-1, -1, 112, 192}, + {-1, -1, 128, 224}, {-1, -1, 144, 256}, {-1, -1, 160, 320}, {-1, -1, -1, -1}, + } + + scaleFactorBandIndex = [9][23]int64{ + /* MPEG-I */ + /* Table B.8.b: 44.1 kHz */ + {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 52, 62, + 74, 90, 110, 134, 162, 196, 238, 288, 342, 418, 576}, + /* Table B.8.c: 48 kHz */ + {0, 4, 8, 12, 16, 20, 24, 30, 36, 42, 50, 60, + 72, 88, 106, 128, 156, 190, 230, 276, 330, 384, 576}, + /* Table B.8.a: 32 kHz */ + {0, 4, 8, 12, 16, 20, 24, 30, 36, 44, 54, 66, + 82, 102, 126, 156, 194, 240, 296, 364, 448, 550, 576}, + /* MPEG-II */ + /* Table B.2.b: 22.05 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, + 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576}, + /* Table B.2.c: 24 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, + 114, 136, 162, 194, 232, 278, 330, 394, 464, 540, 576}, + /* Table B.2.a: 16 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 45, 66, 80, 96, + 116, 140, 168, 200, 238, 248, 336, 396, 464, 522, 576}, + + /* MPEG-2.5 */ + /* 11.025 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, + 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576}, + /* 12 kHz */ + {0, 6, 12, 18, 24, 30, 36, 44, 54, 66, 80, 96, + 116, 140, 168, 200, 238, 284, 336, 396, 464, 522, 576}, + /* MPEG-2.5 8 kHz */ + {0, 12, 24, 36, 48, 60, 72, 88, 108, 132, 160, 192, + 232, 280, 336, 400, 476, 566, 568, 570, 572, 574, 576}, + } +) +var values = []float64{ + 0.000000, -0.000000, -0.000000, -0.000000, -0.000000, -0.000000, + -0.000000, -0.000001, -0.000001, -0.000001, + -0.000001, -0.000001, -0.000001, -0.000002, -0.000002, -0.000002, + -0.000002, -0.000003, -0.000003, -0.000003, + -0.000004, -0.000004, -0.000005, -0.000005, -0.000006, -0.000007, + -0.000008, -0.000008, -0.000009, -0.000010, + -0.000011, -0.000012, -0.000014, -0.000015, -0.000017, -0.000018, + -0.000020, -0.000021, -0.000023, -0.000025, + -0.000028, -0.000030, -0.000032, -0.000035, -0.000038, -0.000041, + -0.000043, -0.000046, -0.000050, -0.000053, + -0.000056, -0.000060, -0.000063, -0.000066, -0.000070, -0.000073, + -0.000077, -0.000081, -0.000084, -0.000087, + -0.000091, -0.000093, -0.000096, -0.000099, 0.000102, 0.000104, + 0.000106, 0.000107, 0.000108, 0.000109, + 0.000109, 0.000108, 0.000107, 0.000105, 0.000103, 0.000099, + 0.000095, 0.000090, 0.000084, 0.000078, + 0.000070, 0.000061, 0.000051, 0.000040, 0.000027, 0.000014, + -0.000001, -0.000017, -0.000034, -0.000053, + -0.000073, -0.000094, -0.000116, -0.000140, -0.000165, -0.000191, + -0.000219, -0.000247, -0.000277, -0.000308, + -0.000339, -0.000371, -0.000404, -0.000438, -0.000473, -0.000507, + -0.000542, -0.000577, -0.000612, -0.000647, + -0.000681, -0.000714, -0.000747, -0.000779, -0.000810, -0.000839, + -0.000866, -0.000892, -0.000915, -0.000936, + -0.000954, -0.000969, -0.000981, -0.000989, -0.000994, -0.000995, + -0.000992, -0.000984, 0.000971, 0.000954, + 0.000931, 0.000903, 0.000869, 0.000829, 0.000784, 0.000732, + 0.000674, 0.000610, 0.000539, 0.000463, + 0.000379, 0.000288, 0.000192, 0.000088, -0.000021, -0.000137, + -0.000260, -0.000388, -0.000522, -0.000662, + -0.000807, -0.000957, -0.001111, -0.001270, -0.001432, -0.001598, + -0.001767, -0.001937, -0.002110, -0.002283, + -0.002457, -0.002631, -0.002803, -0.002974, -0.003142, -0.003307, + -0.003467, -0.003623, -0.003772, -0.003914, + -0.004049, -0.004175, -0.004291, -0.004396, -0.004490, -0.004570, + -0.004638, -0.004691, -0.004728, -0.004749, + -0.004752, -0.004737, -0.004703, -0.004649, -0.004574, -0.004477, + -0.004358, -0.004215, -0.004049, -0.003859, + -0.003643, -0.003402, 0.003135, 0.002841, 0.002522, 0.002175, + 0.001801, 0.001400, 0.000971, 0.000516, + 0.000033, -0.000476, -0.001012, -0.001574, -0.002162, -0.002774, + -0.003411, -0.004072, -0.004756, -0.005462, + -0.006189, -0.006937, -0.007703, -0.008487, -0.009288, -0.010104, + -0.010933, -0.011775, -0.012628, -0.013489, + -0.014359, -0.015234, -0.016113, -0.016994, -0.017876, -0.018757, + -0.019634, -0.020507, -0.021372, -0.022229, + -0.023074, -0.023907, -0.024725, -0.025527, -0.026311, -0.027074, + -0.027815, -0.028533, -0.029225, -0.029890, + -0.030527, -0.031133, -0.031707, -0.032248, -0.032755, -0.033226, + -0.033660, -0.034056, -0.034413, -0.034730, + -0.035007, -0.035242, -0.035435, -0.035586, -0.035694, -0.035759, + 0.035781, 0.035759, 0.035694, 0.035586, + 0.035435, 0.035242, 0.035007, 0.034730, 0.034413, 0.034056, + 0.033660, 0.033226, 0.032755, 0.032248, + 0.031707, 0.031133, 0.030527, 0.029890, 0.029225, 0.028533, + 0.027815, 0.027074, 0.026311, 0.025527, + 0.024725, 0.023907, 0.023074, 0.022229, 0.021372, 0.020507, + 0.019634, 0.018757, 0.017876, 0.016994, + 0.016113, 0.015234, 0.014359, 0.013489, 0.012628, 0.011775, + 0.010933, 0.010104, 0.009288, 0.008487, + 0.007703, 0.006937, 0.006189, 0.005462, 0.004756, 0.004072, + 0.003411, 0.002774, 0.002162, 0.001574, + 0.001012, 0.000476, -0.000033, -0.000516, -0.000971, -0.001400, + -0.001801, -0.002175, -0.002522, -0.002841, + 0.003135, 0.003402, 0.003643, 0.003859, 0.004049, 0.004215, + 0.004358, 0.004477, 0.004574, 0.004649, + 0.004703, 0.004737, 0.004752, 0.004749, 0.004728, 0.004691, + 0.004638, 0.004570, 0.004490, 0.004396, + 0.004291, 0.004175, 0.004049, 0.003914, 0.003772, 0.003623, + 0.003467, 0.003307, 0.003142, 0.002974, + 0.002803, 0.002631, 0.002457, 0.002283, 0.002110, 0.001937, + 0.001767, 0.001598, 0.001432, 0.001270, + 0.001111, 0.000957, 0.000807, 0.000662, 0.000522, 0.000388, + 0.000260, 0.000137, 0.000021, -0.000088, + -0.000192, -0.000288, -0.000379, -0.000463, -0.000539, -0.000610, + -0.000674, -0.000732, -0.000784, -0.000829, + -0.000869, -0.000903, -0.000931, -0.000954, 0.000971, 0.000984, + 0.000992, 0.000995, 0.000994, 0.000989, + 0.000981, 0.000969, 0.000954, 0.000936, 0.000915, 0.000892, + 0.000866, 0.000839, 0.000810, 0.000779, + 0.000747, 0.000714, 0.000681, 0.000647, 0.000612, 0.000577, + 0.000542, 0.000507, 0.000473, 0.000438, + 0.000404, 0.000371, 0.000339, 0.000308, 0.000277, 0.000247, + 0.000219, 0.000191, 0.000165, 0.000140, + 0.000116, 0.000094, 0.000073, 0.000053, 0.000034, 0.000017, + 0.000001, -0.000014, -0.000027, -0.000040, + -0.000051, -0.000061, -0.000070, -0.000078, -0.000084, -0.000090, + -0.000095, -0.000099, -0.000103, -0.000105, + -0.000107, -0.000108, -0.000109, -0.000109, -0.000108, -0.000107, + -0.000106, -0.000104, 0.000102, 0.000099, + 0.000096, 0.000093, 0.000091, 0.000087, 0.000084, 0.000081, + 0.000077, 0.000073, 0.000070, 0.000066, + 0.000063, 0.000060, 0.000056, 0.000053, 0.000050, 0.000046, + 0.000043, 0.000041, 0.000038, 0.000035, + 0.000032, 0.000030, 0.000028, 0.000025, 0.000023, 0.000021, + 0.000020, 0.000018, 0.000017, 0.000015, + 0.000014, 0.000012, 0.000011, 0.000010, 0.000009, 0.000008, + 0.000008, 0.000007, 0.000006, 0.000005, + 0.000005, 0.000004, 0.000004, 0.000003, 0.000003, 0.000003, + 0.000002, 0.000002, 0.000002, 0.000002, + 0.000001, 0.000001, 0.000001, 0.000001, 0.000001, 0.000001, + 0.000000, 0.000000, 0.000000, 0.000000, + 0.000000, 0.000000, +} + +var enWindow []int32 = createEnWindow() + +func createEnWindow() []int32 { + result := make([]int32, 0) + for _, val := range values { + result = append(result, ew(val)) + } + return result +} +func ew(x float64) int32 { + return int32(x * float64(0x7fffffff)) +} diff --git a/pkg/mp3/types.go b/pkg/mp3/types.go new file mode 100644 index 0000000..18ad276 --- /dev/null +++ b/pkg/mp3/types.go @@ -0,0 +1,152 @@ +package mp3 + +const ( + PI = 3.14159265358979 + PI4 = 0.78539816339745 + PI12 = 0.26179938779915 + PI36 = 0.087266462599717 + PI64 = 0.049087385212 + SQRT2 = 1.41421356237 + LN2 = 0.69314718 + LN_TO_LOG10 = 0.2302585093 + BLKSIZE = 1024 + /* for loop unrolling, require that HAN_SIZE%8==0 */ + HAN_SIZE = 512 + SCALE_BLOCK = 12 + SCALE_RANGE = 64 + SCALE = 32768 + SUBBAND_LIMIT = 32 + MAX_CHANNELS = 2 + GRANULE_SIZE = 576 + MAX_GRANULES = 2 +) + +type mode int + +const ( + STEREO mode = iota + JOINT_STEREO + DUAL_CHANNEL + MONO +) + +type emphasis int + +const ( + NONE emphasis = 0 + MU50_15 emphasis = 1 + CITT emphasis = 3 +) + +type Wave struct { + Channels int64 + SampleRate int64 +} +type MPEG struct { + Version mpegVersion + Layer int64 + GranulesPerFrame int64 + Mode mode + Bitrate int64 + Emph emphasis + Padding int64 + BitsPerFrame int64 + BitsPerSlot int64 + FracSlotsPerFrame float64 + Slot_lag float64 + WholeSlotsPerFrame int64 + BitrateIndex int64 + SampleRateIndex int64 + Crc int64 + Ext int64 + ModeExt int64 + Copyright int64 + Original int64 +} +type L3Loop struct { + // Magnitudes of the spectral values + Xr []int32 + Xrsq [GRANULE_SIZE]int32 + Xrabs [GRANULE_SIZE]int32 + // Maximum of xrabs array + Xrmax int32 + // gr + EnTot [2]int32 + En [2][21]int32 + Xm [2][21]int32 + Xrmaxl [2]int32 + // 2**(-x/4) for x = -127..0 + StepTable [128]float64 + // 2**(-x/4) for x = -127..0 + StepTableI [128]int32 + // x**(3/4) for x = 0..9999 + Int2idx [10000]int64 +} +type MDCT struct { + CosL [18][36]int32 +} +type Subband struct { + Off [2]int64 + Fl [32][64]int32 + X [2][512]int32 +} +type GranuleInfo struct { + Part2_3Length uint64 + BigValues uint64 + Count1 uint64 + GlobalGain uint64 + ScaleFactorCompress uint64 + TableSelect [3]uint64 + Region0Count uint64 + Region1Count uint64 + PreFlag uint64 + ScaleFactorScale uint64 + Count1TableSelect uint64 + Part2Length uint64 + ScaleFactorBandMaxLen uint64 + Address1 uint64 + Address2 uint64 + Address3 uint64 + QuantizerStepSize int64 + ScaleFactorLen [4]uint64 +} +type SideInfo struct { + PrivateBits uint64 + ReservoirDrain int64 + ScaleFactorSelectInfo [MAX_CHANNELS][4]uint64 + Granules [MAX_GRANULES]struct { + Channels [MAX_CHANNELS]struct { + Tt GranuleInfo + } + } +} +type PsyRatio struct { + L [MAX_GRANULES][MAX_CHANNELS][21]float64 +} +type PsyXMin struct { + L [MAX_GRANULES][MAX_CHANNELS][21]float64 +} +type ScaleFactor struct { + L [2][2][22]int32 + S [2][2][13][3]int32 +} +type Encoder struct { + Wave Wave + Mpeg MPEG + bitstream bitstream + sideInfo SideInfo + sideInfoLen int64 + meanBits int64 + ratio PsyRatio + scaleFactor ScaleFactor + buffer [2]*int16 + PerceptualEnergy [2][2]float64 + l3Encoding [2][2][GRANULE_SIZE]int64 + l3SubbandSamples [2][3][18][32]int32 + mdctFrequency [2][2][GRANULE_SIZE]int32 + reservoirSize int64 + reservoirMaxSize int64 + l3loop L3Loop + mdct MDCT + subband Subband +}