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, &current_cycle, 882 * mclks_sample); 201 wait(&y_context, &p_context, &current_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, &current_cycle, wait_time); 254 wait(&y_context, &p_context, &current_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, &current_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;