Mercurial > repos > blastem
comparison vgmplay.c @ 511:2c1679058727
Add support for VGM 1.50 PCM data blocks
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Thu, 06 Feb 2014 22:18:19 -0800 |
parents | b7b7a1cab44a |
children | 6800d30437c9 |
comparison
equal
deleted
inserted
replaced
510:a277de8c1a18 | 511:2c1679058727 |
---|---|
63 CMD_WAIT_50, | 63 CMD_WAIT_50, |
64 CMD_END = 0x66, | 64 CMD_END = 0x66, |
65 CMD_DATA, | 65 CMD_DATA, |
66 CMD_PCM_WRITE, | 66 CMD_PCM_WRITE, |
67 CMD_WAIT_SHORT = 0x70, | 67 CMD_WAIT_SHORT = 0x70, |
68 CMD_YM2612_DAC = 0x80 | 68 CMD_YM2612_DAC = 0x80, |
69 CMD_DAC_STREAM_SETUP = 0x90, | |
70 CMD_DAC_STREAM_DATA, | |
71 CMD_DAC_STREAM_FREQ, | |
72 CMD_DAC_STREAM_START, | |
73 CMD_DAC_STREAM_STOP, | |
74 CMD_DAC_STREAM_STARTFAST, | |
75 CMD_DATA_SEEK = 0xE0 | |
69 }; | 76 }; |
70 | 77 |
78 enum { | |
79 DATA_YM2612_PCM = 0 | |
80 }; | |
81 | |
71 #pragma pack(pop) | 82 #pragma pack(pop) |
72 | 83 |
73 void handle_keydown(int keycode) | 84 void handle_keydown(int keycode) |
74 { | 85 { |
75 } | 86 } |
91 } | 102 } |
92 | 103 |
93 uint8_t headless = 0; | 104 uint8_t headless = 0; |
94 | 105 |
95 #define CYCLE_LIMIT MCLKS_NTSC/60 | 106 #define CYCLE_LIMIT MCLKS_NTSC/60 |
107 #define MAX_SOUND_CYCLES 100000 | |
96 tern_node * config; | 108 tern_node * config; |
97 | 109 |
98 void wait(ym2612_context * y_context, psg_context * p_context, uint32_t * current_cycle, uint32_t cycles) | 110 void wait(ym2612_context * y_context, psg_context * p_context, uint32_t * current_cycle, uint32_t cycles) |
99 { | 111 { |
112 while (cycles > MAX_SOUND_CYCLES) | |
113 { | |
114 wait(y_context, p_context, current_cycle, MAX_SOUND_CYCLES); | |
115 cycles -= MAX_SOUND_CYCLES; | |
116 } | |
100 *current_cycle += cycles; | 117 *current_cycle += cycles; |
101 psg_run(p_context, *current_cycle); | 118 psg_run(p_context, *current_cycle); |
102 ym_run(y_context, *current_cycle); | 119 ym_run(y_context, *current_cycle); |
103 | 120 |
104 if (*current_cycle > CYCLE_LIMIT) { | 121 if (*current_cycle > CYCLE_LIMIT) { |
107 y_context->current_cycle -= CYCLE_LIMIT; | 124 y_context->current_cycle -= CYCLE_LIMIT; |
108 process_events(); | 125 process_events(); |
109 } | 126 } |
110 } | 127 } |
111 | 128 |
129 typedef struct { | |
130 struct data_block *next; | |
131 uint8_t *data; | |
132 uint32_t size; | |
133 uint8_t type; | |
134 } data_block; | |
135 | |
112 int main(int argc, char ** argv) | 136 int main(int argc, char ** argv) |
113 { | 137 { |
138 data_block *blocks = NULL; | |
139 data_block *seek_block = NULL; | |
140 uint32_t seek_offset; | |
141 uint32_t block_offset; | |
142 | |
114 uint32_t fps = 60; | 143 uint32_t fps = 60; |
115 config = load_config(argv[0]); | 144 config = load_config(argv[0]); |
116 render_init(320, 240, "vgm play", 60, 0, 0); | 145 render_init(320, 240, "vgm play", 60, 0, 0); |
117 | 146 |
118 | 147 |
171 case CMD_WAIT_50: | 200 case CMD_WAIT_50: |
172 wait(&y_context, &p_context, ¤t_cycle, 882 * mclks_sample); | 201 wait(&y_context, &p_context, ¤t_cycle, 882 * mclks_sample); |
173 break; | 202 break; |
174 case CMD_END: | 203 case CMD_END: |
175 return 0; | 204 return 0; |
205 case CMD_DATA: { | |
206 cur++; //skip compat command | |
207 uint8_t data_type = *(cur++); | |
208 uint32_t data_size = *(cur++); | |
209 data_size |= *(cur++) << 8; | |
210 data_size |= *(cur++) << 16; | |
211 data_size |= *(cur++) << 24; | |
212 if (data_type == DATA_YM2612_PCM) { | |
213 data_block ** curblock = &blocks; | |
214 while(*curblock) | |
215 { | |
216 curblock = &((*curblock)->next); | |
217 } | |
218 *curblock = malloc(sizeof(data_block)); | |
219 (*curblock)->size = data_size; | |
220 (*curblock)->type = data_type; | |
221 (*curblock)->data = cur; | |
222 (*curblock)->next = NULL; | |
223 } else { | |
224 fprintf(stderr, "Skipping data block with unrecognized type %X\n", data_type); | |
225 } | |
226 cur += data_size; | |
227 break; | |
228 } | |
229 case CMD_DATA_SEEK: { | |
230 uint32_t new_offset = *(cur++); | |
231 new_offset |= *(cur++) << 8; | |
232 new_offset |= *(cur++) << 16; | |
233 new_offset |= *(cur++) << 24; | |
234 if (!seek_block || new_offset < seek_offset) { | |
235 seek_block = blocks; | |
236 seek_offset = 0; | |
237 block_offset = 0; | |
238 } | |
239 while (seek_block && (seek_offset - block_offset + seek_block->size) < new_offset) | |
240 { | |
241 seek_offset += seek_block->size - block_offset; | |
242 seek_block = seek_block->next; | |
243 block_offset = 0; | |
244 } | |
245 block_offset += new_offset-seek_offset; | |
246 seek_offset = new_offset; | |
247 break; | |
248 } | |
249 | |
176 default: | 250 default: |
177 if (cmd >= CMD_WAIT_SHORT && cmd < (CMD_WAIT_SHORT + 0x10)) { | 251 if (cmd >= CMD_WAIT_SHORT && cmd < (CMD_WAIT_SHORT + 0x10)) { |
178 uint32_t wait_time = (cmd & 0xF) + 1; | 252 uint32_t wait_time = (cmd & 0xF) + 1; |
179 wait_time *= mclks_sample; | 253 wait_time *= mclks_sample; |
180 wait(&y_context, &p_context, ¤t_cycle, wait_time); | 254 wait(&y_context, &p_context, ¤t_cycle, wait_time); |
255 } else if (cmd >= CMD_YM2612_DAC && cmd < CMD_DAC_STREAM_SETUP) { | |
256 if (seek_block) { | |
257 ym_address_write_part1(&y_context, 0x2A); | |
258 ym_data_write(&y_context, seek_block->data[block_offset]); | |
259 } else { | |
260 fputs("Encountered DAC write command but data seek pointer is invalid!\n", stderr); | |
261 } | |
262 uint32_t wait_time = (cmd & 0xF); | |
263 if (wait_time) | |
264 { | |
265 wait_time *= mclks_sample; | |
266 wait(&y_context, &p_context, ¤t_cycle, wait_time); | |
267 } | |
181 } else { | 268 } else { |
182 printf("unimplemented command: %X at offset %X\n", cmd, cur - data - 1); | 269 printf("unimplemented command: %X at offset %X\n", cmd, (unsigned int)(cur - data - 1)); |
183 exit(1); | 270 exit(1); |
184 } | 271 } |
185 } | 272 } |
186 } | 273 } |
187 return 0; | 274 return 0; |