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
|
package main
import (
"flag"
"log"
"unsafe"
)
// #cgo LDFLAGS: -lADLMIDI -Lbin
// #cgo CFLAGS:
// #include <stdio.h>
// #include <stdlib.h>
// #include <adlmidi.h>
// typedef struct wav_header {
// // RIFF Header
// char riff_header[4]; // Contains "RIFF"
// int wav_size; // Size of the wav portion of the file, which follows the first 8 bytes. File size - 8
// char wave_header[4]; // Contains "WAVE"
// // Format Header
// char fmt_header[4]; // Contains "fmt " (includes trailing space)
// int fmt_chunk_size; // Should be 16 for PCM
// short audio_format; // Should be 1 for PCM. 3 for IEEE Float
// short num_channels;
// int sample_rate;
// int byte_rate; // Number of bytes per second. sample_rate * num_channels * Bytes Per Sample
// short sample_alignment; // num_channels * Bytes Per Sample
// short bit_depth; // Number of bits per sample
// // Data
// char data_header[4]; // Contains "data"
// int data_bytes; // Number of bytes in data. Number of samples * num_channels * sample byte size
// // uint8_t bytes[]; // Remainder of wave file is bytes
// } wav_header;
import "C"
func main() {
inputPtr := flag.String("i", "", "input midi file")
outputPtr := flag.String("o", "", "output wave file")
bank := flag.Int("b", 59, "bank")
chips := flag.Int("c", 2, "chips")
flag.Parse()
if *inputPtr == "" {
log.Fatal("no input midi file")
}
if *outputPtr == "" {
log.Fatal("no output file")
}
// Convert into raw C-String
cInputFile := C.CString(*inputPtr)
// Initializing the instance of libADLMIDI
cAdlMidiPlayer := C.adl_init(48000)
// Set number of parallel chips
C.adl_setNumChips(cAdlMidiPlayer, C.int(*chips))
// Disable looping (it's not needed for WAV output)
C.adl_setLoopEnabled(cAdlMidiPlayer, 0)
// Setting one of embedded banks
C.adl_setBank(cAdlMidiPlayer, C.int(*bank))
// Open an external MIDI file to play it
C.adl_openFile(cAdlMidiPlayer, cInputFile)
// Remove the file path buffer
C.free(unsafe.Pointer(cInputFile))
// Create the audio buffer that will be used to store taken audio chunks and write them into WAV file
cBuffer := C.malloc(2048 * 2)
cOutputFileName := C.CString(*outputPtr)
cFileMode := C.CString("wb")
cFILE := C.fopen(cOutputFileName, cFileMode)
C.free(unsafe.Pointer(cOutputFileName))
C.free(unsafe.Pointer(cFileMode))
var cWavHeader C.wav_header
cWavHeader.riff_header[0] = 'R'
cWavHeader.riff_header[1] = 'I'
cWavHeader.riff_header[2] = 'F'
cWavHeader.riff_header[3] = 'F'
cWavHeader.wav_size = 0
cWavHeader.wave_header[0] = 'W'
cWavHeader.wave_header[1] = 'A'
cWavHeader.wave_header[2] = 'V'
cWavHeader.wave_header[3] = 'E'
cWavHeader.fmt_header[0] = 'f'
cWavHeader.fmt_header[1] = 'm'
cWavHeader.fmt_header[2] = 't'
cWavHeader.fmt_header[3] = ' '
cWavHeader.fmt_chunk_size = 16
cWavHeader.audio_format = 1
cWavHeader.num_channels = 2
cWavHeader.sample_rate = 48000
cWavHeader.byte_rate = 192000
cWavHeader.sample_alignment = 4
cWavHeader.bit_depth = 16
cWavHeader.data_header[0] = 'd'
cWavHeader.data_header[1] = 'a'
cWavHeader.data_header[2] = 't'
cWavHeader.data_header[3] = 'a'
cWavHeader.data_bytes = 0
C.fwrite(unsafe.Pointer(&cWavHeader), 44, 1, cFILE)
finished := false
dataBytes := 0
for !finished {
count := C.adl_play(cAdlMidiPlayer, 2048, (*C.int16_t)(cBuffer))
if C.adl_atEnd(cAdlMidiPlayer) == 1 {
finished = true
}
if count > 0 {
dataBytes += int(count) * 4
C.fwrite(cBuffer, 1, C.size_t(count * 2), cFILE)
}
}
C.adl_close(cAdlMidiPlayer)
cWavHeader.wav_size = C.int(36 + dataBytes)
cWavHeader.data_bytes = C.int(dataBytes)
C.fseek(cFILE, 0, C.SEEK_SET)
C.fwrite(unsafe.Pointer(&cWavHeader), 44, 1, cFILE)
C.fclose(cFILE)
C.free(cBuffer)
}
|