Mercurial > pmdwin
comparison pmd_play.c @ 0:c55ea9478c80
Hello Gensokyo!
author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
---|---|
date | Tue, 21 May 2013 10:29:21 +0200 |
parents | |
children | c8875256b767 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:c55ea9478c80 |
---|---|
1 #include <stdint.h> | |
2 #include <string.h> | |
3 #include <fcntl.h> | |
4 #include <unistd.h> | |
5 #include <sys/stat.h> | |
6 #include <math.h> | |
7 #include <getopt.h> | |
8 #if defined(WIN32) || defined(WIN64) | |
9 #include <windows.h> | |
10 #include <mmsystem.h> | |
11 int wave_out_open(HWAVEOUT *hWaveOut, uint32_t rate, uint8_t channels); | |
12 void wave_out_close(HWAVEOUT hWaveOut); | |
13 void writeAudio(HWAVEOUT hWaveOut, void *data, uint32_t size); | |
14 #else | |
15 int oss_audio_open(uint32_t oss_audio_rate, uint8_t nchannels); | |
16 int alsa_audio_open(uint32_t *rate, uint8_t channels, uint32_t *_ver, int mode); | |
17 int alsa_audio_close(int snd_fd); | |
18 long snd_pcm_writei(int snd_fd, const void *buffer, unsigned long size); | |
19 int snd_pcm_prepare(int snd_fd); | |
20 #ifdef USE_ALSA | |
21 #include <errno.h> | |
22 #endif | |
23 #endif | |
24 #include "pmdwin.h" | |
25 | |
26 #ifndef O_BINARY | |
27 #define O_BINARY 0 | |
28 #endif | |
29 | |
30 static uint32_t atoui(const uint8_t *str) { | |
31 uint32_t c, num = 0; | |
32 while(1) { | |
33 c = *str++ - 0x30; | |
34 if(c > 9) break; | |
35 num = (num << 1) + (num << 3) + c; | |
36 } | |
37 return num; | |
38 } | |
39 | |
40 static const unsigned char static_hdr_portion[20] = { | |
41 0x52, 0x49, 0x46, 0x46, 0xFF, 0xFF, 0xFF, 0x7F, | |
42 0x57, 0x41, 0x56, 0x45, 0x66, 0x6D, 0x74, 0x20, | |
43 0x10, 0x00, 0x00, 0x00 | |
44 }; | |
45 | |
46 typedef struct _WAVHeader { | |
47 uint16_t wav_id; | |
48 uint16_t channels; | |
49 uint32_t samplerate; | |
50 uint32_t bitrate; | |
51 uint32_t block_align; | |
52 uint32_t pad0; | |
53 uint32_t pad1; | |
54 } __attribute__((packed)) WAVHeader; | |
55 | |
56 static void write_wav_header(int fd, uint32_t rate) | |
57 { | |
58 WAVHeader w; | |
59 write(fd, &static_hdr_portion, 20); | |
60 | |
61 w.wav_id = 1; | |
62 w.channels = 1; | |
63 w.samplerate = rate; | |
64 w.bitrate = rate*2; | |
65 w.block_align = 0x00100010; | |
66 w.pad0 = 0x61746164; | |
67 w.pad1 = 0x7fffffff; | |
68 write(fd, &w, sizeof(WAVHeader)); | |
69 } | |
70 | |
71 //============================================================================= | |
72 // Load PMD data from file into memory. Uses mmap() on both Windows and *nix. | |
73 // Originally in pmdwin.cpp, moved here to minimize platform-specific code | |
74 // in pmdwin.cpp | |
75 //============================================================================= | |
76 #if defined(WIN32) || defined(WIN64) | |
77 static int music_load(char *filename) | |
78 { | |
79 HANDLE mapped_file, h; | |
80 int result; | |
81 size_t size; | |
82 uchar *musbuf; | |
83 struct stat st; | |
84 | |
85 mapped_file = CreateFile(filename, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); | |
86 h = CreateFileMapping(mapped_file, NULL, PAGE_READWRITE, 0, 0, NULL); | |
87 if(!h) { | |
88 return ERR_OPEN_MUSIC_FILE; | |
89 } | |
90 stat(filename, &st); | |
91 musbuf = (uchar*)MapViewOfFile(h, FILE_MAP_READ, 0, 0, 0); | |
92 CloseHandle(h); | |
93 CloseHandle(mapped_file); | |
94 size = st.st_size; | |
95 result = music_load3(musbuf, size); | |
96 return result; | |
97 } | |
98 #else | |
99 static int music_load(char *filename) | |
100 { | |
101 int fd = -1; | |
102 int result; | |
103 size_t size; | |
104 uchar musbuf[mdata_def*1024]; | |
105 | |
106 if((fd = open(filename, O_RDONLY)) < 0) { | |
107 return ERR_OPEN_MUSIC_FILE; | |
108 } | |
109 | |
110 size = read(fd, musbuf, sizeof(musbuf)); | |
111 close(fd); | |
112 result = music_load3(musbuf, size); | |
113 return result; | |
114 } | |
115 #endif | |
116 | |
117 #if defined(WIN32) || defined(WIN64) | |
118 #define WriteToConsole(str, len) WriteFile(errh, (str), (len), &done, NULL) | |
119 #else | |
120 #define WriteToConsole(str, len) write(2, (str), (len)) | |
121 #endif | |
122 | |
123 static void usage(void) { | |
124 #if defined(WIN32) || defined(WIN64) | |
125 DWORD done; | |
126 HANDLE errh = GetStdHandle(STD_ERROR_HANDLE); | |
127 #endif | |
128 const char *usage_str = | |
129 "pmdwin -f <output file> -l <loop count> -m <device mask> -c <channel mask> -t <time> [PMD File]\n\ | |
130 -f - Write output to wavfile\n\ | |
131 -l - Loop n times (default is once - use 0 for infinite loop)\n\ | |
132 -m - Device mask: 1 - OPNA, 2 - PSG, 4 - Rhythm (or them together)\n\ | |
133 -c - Channel mask: 1,2,4,8,16,32 are OPNA channels 1-6, 64,128,256 are PSG channels 1-3. Once again, or them together\n\ | |
134 -t - Play song for n seconds\n\n"; | |
135 WriteToConsole(usage_str, strlen(usage_str)); | |
136 } | |
137 | |
138 int main(int argc, char **argv) { | |
139 uint32_t i, frameno, samplerate_out = SOUND_44K, infloop = 0; | |
140 uint32_t pmd_length = 0, pmd_loopcount = 2; | |
141 int opt, j, out_fd = -1; | |
142 uint8_t tofile = 0; | |
143 int16_t pcmbuf[8192]; | |
144 char pmd_title[1024]; | |
145 char pmd_compo[1024]; | |
146 #if defined(WIN32) || defined(WIN64) | |
147 DWORD done; | |
148 HANDLE errh = GetStdHandle(STD_ERROR_HANDLE); | |
149 HWAVEOUT hWaveOut; | |
150 #endif | |
151 char buf[1024]; | |
152 pmdwininit(); | |
153 | |
154 while((opt = getopt(argc, argv, "f:l:m:c:t:r:")) != -1) { | |
155 switch(opt) { | |
156 case 'f': | |
157 tofile = 1; | |
158 out_fd = open(optarg, O_WRONLY|O_CREAT|O_APPEND|O_BINARY, 0644); | |
159 break; | |
160 case 'l': | |
161 pmd_loopcount = atoui((uint8_t*)optarg); | |
162 if(!pmd_loopcount) infloop = 1; | |
163 break; | |
164 case 'c': | |
165 setchanmask(atoui((uint8_t*)optarg)); | |
166 break; | |
167 case 'm': | |
168 setdevmask(atoui((uint8_t*)optarg)); | |
169 break; | |
170 case 't': | |
171 pmd_length = atoui((uint8_t*)optarg)*1000; | |
172 break; | |
173 case 'r': | |
174 samplerate_out = atoui((uint8_t*)optarg); | |
175 break; | |
176 default: | |
177 usage(); | |
178 break; | |
179 } | |
180 } | |
181 | |
182 if(!tofile) { | |
183 #if defined(WIN32) || defined(WIN64) | |
184 if(!wave_out_open(&hWaveOut, samplerate_out, 1)) { | |
185 #else | |
186 #ifdef USE_ALSA | |
187 if((out_fd = alsa_audio_open(&samplerate_out, 1, NULL, 0)) < 0) { | |
188 #else | |
189 if((out_fd = oss_audio_open(samplerate_out, 1)) < 0) { | |
190 #endif | |
191 #endif | |
192 WriteToConsole("Cannot open sound device, exiting.\n", 35); | |
193 return -1; | |
194 } | |
195 } else { | |
196 write_wav_header(out_fd, samplerate_out); | |
197 } | |
198 music_load(argv[optind]); | |
199 memcpy(pmd_title, "Title = ", 8); | |
200 getmemo3(pmd_title+8, NULL, 0, 1); | |
201 i = strlen(pmd_title); pmd_title[i++] = '\n'; | |
202 #if defined(WIN32) || defined(WIN64) | |
203 SetConsoleOutputCP(65001); // UTF-8 | |
204 #endif | |
205 WriteToConsole(pmd_title, i); | |
206 memcpy(pmd_compo, "Composer = ", 11); | |
207 getmemo3(pmd_compo+11, NULL, 0, 2); | |
208 i = strlen(pmd_compo); pmd_compo[i++] = '\n'; | |
209 WriteToConsole(pmd_compo, i); | |
210 setpcmrate(samplerate_out); | |
211 music_start(); | |
212 i = 0; | |
213 if(pmd_length != 0) { | |
214 frameno = lrintf(((float)pmd_length*(float)samplerate_out)/(4096.0f*1000.0f)); | |
215 } else { | |
216 frameno = 0; | |
217 } | |
218 buf[0] = '\r'; | |
219 while(getloopcount() < pmd_loopcount || infloop || i < frameno) { | |
220 int ret = getstatus(buf+1, 1022); | |
221 WriteToConsole(buf, ret+1); | |
222 getpcmdata(pcmbuf, 4096); | |
223 #if defined(WIN32) || defined(WIN64) | |
224 if(!tofile) { | |
225 writeAudio(hWaveOut, pcmbuf, 8192); | |
226 } else | |
227 #endif | |
228 #ifdef USE_ALSA | |
229 if(!tofile) { | |
230 j = snd_pcm_writei(out_fd, pcmbuf, 2048); | |
231 if(j == -EPIPE) { | |
232 snd_pcm_prepare(out_fd); | |
233 } | |
234 } else | |
235 #endif | |
236 write(out_fd, pcmbuf, 8192); | |
237 i++; | |
238 } | |
239 WriteToConsole("\n", 1); | |
240 #if defined(WIN32) || defined(WIN64) | |
241 if(!tofile) { | |
242 wave_out_close(hWaveOut); | |
243 } else | |
244 #endif | |
245 #ifdef USE_ALSA | |
246 alsa_audio_close(out_fd); | |
247 #else | |
248 close(out_fd); | |
249 #endif | |
250 return 0; | |
251 } | |
252 |