static XGMCommand* XGMCommand_createYMPort1Command(LList** pcommands) { LList* curCom = *pcommands; const int size = min(16, getSizeLList(curCom)); unsigned char* data = malloc((size * 2) + 1); int i, off; data[0] = XGM_YM2612_PORT1 | (size - 1); off = 1; for (i = 0; i < size; i++) { VGMCommand* command = curCom->element; data[off++] = VGMCommand_getYM2612Register(command); data[off++] = VGMCommand_getYM2612Value(command); curCom = curCom->next; } // update list pointer to remove elements we have done *pcommands = curCom; return XGMCommand_create(data, (size * 2) + 1); }
XGMCommand* XGMCommand_createYMKeyCommand(List* commands, int* offset, int max) { const int size = min(max, commands->size - *offset); unsigned char* data = malloc(size + 1); int i, off; data[0] = XGM_YM2612_REGKEY | (size - 1); off = 1; for (i = 0; i < size; i++) data[off++] = VGMCommand_getYM2612Value(getFromList(commands, i + *offset)); // remove elements we have done *offset += size; return XGMCommand_create(data, size + 1); }
XGMCommand* XGMCommand_createYMKeyCommand(LList** pcommands, int max) { LList* curCom = *pcommands; const int size = min(max, getSizeLList(curCom)); unsigned char* data = malloc(size + 1); int i, off; data[0] = XGM_YM2612_REGKEY | (size - 1); off = 1; for (i = 0; i < size; i++) { data[off++] = VGMCommand_getYM2612Value(curCom->element); curCom = curCom->next; } // update list pointer to remove elements we have done *pcommands = curCom; return XGMCommand_create(data, size + 1); }
static XGMCommand* XGMCommand_createYMPort1Command(List* commands, int* offset) { const int size = min(16, commands->size - *offset); unsigned char* data = malloc((size * 2) + 1); int i, off; data[0] = XGM_YM2612_PORT1 | (size - 1); off = 1; for (i = 0; i < size; i++) { VGMCommand* command = getFromList(commands, i + *offset); data[off++] = VGMCommand_getYM2612Register(command); data[off++] = VGMCommand_getYM2612Value(command); } // remove elements we have done *offset += size; return XGMCommand_create(data, (size * 2) + 1); }
static void XGC_extractMusic(XGM* xgc, XGM* xgm) { LList* vgmCommands; LList* frameCommands = NULL; LList* ymCommands = NULL; LList* ymKeyCommands = NULL; LList* psgCommands = NULL; LList* otherCommands = NULL; LList* newCommands = NULL; LList* stateChange = NULL; LList* xgcCommands; LList* com; LList* tmpCom; XGMCommand* sizeCommand; YM2612* ymOldState; YM2612* ymState; int j, size; ymOldState = YM2612_create(); ymState = YM2612_create(); // reset frame xgcCommands = createElement(XGCCommand_createFrameSizeCommand(0)); // TL / D1L / RR set to max vgmCommands = NULL; vgmCommands = insertAllAfterLList(vgmCommands, VGMCommand_createYMCommands(0, 0x40, 0x7F)); vgmCommands = insertAllAfterLList(vgmCommands, VGMCommand_createYMCommands(0, 0x80, 0xFF)); vgmCommands = getHeadLList(vgmCommands); xgcCommands = insertAllAfterLList(xgcCommands, XGCCommand_convert(XGMCommand_createYMPort0Commands(vgmCommands))); // set ym state com = vgmCommands; while(com != NULL) { VGMCommand* command = com->element; YM2612_set(ymState, VGMCommand_getYM2612Port(command), VGMCommand_getYM2612Register(command), VGMCommand_getYM2612Value(command)); com = com->next; } deleteLList(vgmCommands); vgmCommands = NULL; vgmCommands = insertAllAfterLList(vgmCommands, VGMCommand_createYMCommands(1, 0x40, 0x7F)); vgmCommands = insertAllAfterLList(vgmCommands, VGMCommand_createYMCommands(1, 0x80, 0xFF)); vgmCommands = getHeadLList(vgmCommands); xgcCommands = insertAllAfterLList(xgcCommands, XGCCommand_convert(XGMCommand_createYMPort1Commands(vgmCommands))); // set ym state com = vgmCommands; while(com != NULL) { VGMCommand* command = com->element; YM2612_set(ymState, VGMCommand_getYM2612Port(command), VGMCommand_getYM2612Register(command), VGMCommand_getYM2612Value(command)); com = com->next; } // key off for all channels deleteLList(vgmCommands); vgmCommands = NULL; vgmCommands = insertAfterLList(vgmCommands, VGMCommand_createYMCommand(0, 0x28, 0x00)); vgmCommands = insertAfterLList(vgmCommands, VGMCommand_createYMCommand(0, 0x28, 0x01)); vgmCommands = insertAfterLList(vgmCommands, VGMCommand_createYMCommand(0, 0x28, 0x02)); vgmCommands = insertAfterLList(vgmCommands, VGMCommand_createYMCommand(0, 0x28, 0x04)); vgmCommands = insertAfterLList(vgmCommands, VGMCommand_createYMCommand(0, 0x28, 0x05)); vgmCommands = insertAfterLList(vgmCommands, VGMCommand_createYMCommand(0, 0x28, 0x06)); vgmCommands = getHeadLList(vgmCommands); xgcCommands = insertAllAfterLList(xgcCommands, XGCCommand_convert(XGMCommand_createYMKeyCommands(vgmCommands))); // set ym state com = vgmCommands; while(com != NULL) { VGMCommand* command = com->element; YM2612_set(ymState, VGMCommand_getYM2612Port(command), VGMCommand_getYM2612Register(command), VGMCommand_getYM2612Value(command)); com = com->next; } stateChange = XGC_getStateChange(ymState, ymOldState); // add the state commands if no empty if (stateChange != NULL) xgcCommands = insertAllAfterLList(xgcCommands, XGCCommand_createStateCommands(stateChange)); // add 3 dummy frames (reserve frame space for PCM shift) xgcCommands = insertAfterLList(xgcCommands, XGCCommand_createFrameSizeCommand(0)); xgcCommands = insertAfterLList(xgcCommands, XGCCommand_createFrameSizeCommand(0)); xgcCommands = insertAfterLList(xgcCommands, XGCCommand_createFrameSizeCommand(0)); XGMCommand* loopCommand = XGM_getLoopPointedCommand(xgm); int loopOffset = -1; com = xgm->commands; while(com != NULL) { // build frame commands deleteLList(frameCommands); frameCommands = NULL; while(com != NULL) { // get command and pass to next one XGMCommand* command = com->element; com = com->next; // this is the command where we loop if (command == loopCommand) { if (loopOffset == -1) loopOffset = XGM_getMusicDataSizeOf(getHeadLList(xgcCommands)); } // loop information --> ignore if (XGMCommand_isLoop(command) || XGMCommand_isEnd(command)) continue; // stop here if (XGMCommand_isFrame(command)) break; // add command frameCommands = insertAfterLList(frameCommands, command); } // get back to head frameCommands = getHeadLList(frameCommands); // update state ymOldState = ymState; ymState = YM2612_copy(ymOldState); // prepare new commands for this frame deleteLList(newCommands); // add size command sizeCommand = XGCCommand_createFrameSizeCommand(0); newCommands = createElement(sizeCommand); // group commands deleteLList(ymCommands); deleteLList(ymKeyCommands); deleteLList(psgCommands); deleteLList(otherCommands); ymCommands = NULL; ymKeyCommands = NULL; psgCommands = NULL; otherCommands = NULL; tmpCom = frameCommands; while(tmpCom != NULL) { XGMCommand* command = tmpCom->element; if (XGMCommand_isPSGWrite(command)) psgCommands = insertAfterLList(psgCommands, command); else if (XGMCommand_isYM2612RegKeyWrite(command)) ymKeyCommands = insertAfterLList(ymKeyCommands, command); else if (XGMCommand_isYM2612Write(command)) { // update YM state for (j = 0; j < XGMCommand_getYM2612WriteCount(command); j++) { if (XGMCommand_isYM2612Port0Write(command)) YM2612_set(ymState, 0, command->data[(j * 2) + 1] & 0xFF, command->data[(j * 2) + 2] & 0xFF); else YM2612_set(ymState, 1, command->data[(j * 2) + 1] & 0xFF, command->data[(j * 2) + 2] & 0xFF); } // remove all $2B register writes (DAC enable is done automatically) if (XGMCommand_removeYM2612RegWrite(command, 0, 0x2B)) ymCommands = insertAfterLList(ymCommands, command); } else otherCommands = insertAfterLList(otherCommands, command); tmpCom = tmpCom->next; } XGMCommand* pcmComCH[4]; pcmComCH[0] = NULL; pcmComCH[1] = NULL; pcmComCH[2] = NULL; pcmComCH[3] = NULL; // discard multi PCM command in a single frame tmpCom = otherCommands; while(tmpCom != NULL) { XGMCommand* command = tmpCom->element; if (XGMCommand_isPCM(command)) { // get channel int ch = XGMCommand_getPCMChannel(command); // already have a PCM command for this channel ? if (pcmComCH[ch] != NULL) { // remove current PCM command removeFromLList(tmpCom); // we removed the last command --> update pointer if (tmpCom == otherCommands) otherCommands = tmpCom->prev; if (!silent) { int frameInd = XGC_computeLenInFrameOf(getHeadLList(xgcCommands)); int id = XGMCommand_getPCMId(command); // we are ignoring a real play command --> display it if (id != 0) printf("Warning: multiple PCM command on %d --> play %2X removed\n", frameInd, id); } } else pcmComCH[ch] = command; } tmpCom = tmpCom->prev; } psgCommands = getHeadLList(psgCommands); ymCommands = getHeadLList(ymCommands); ymKeyCommands = getHeadLList(ymKeyCommands); otherCommands = getHeadLList(otherCommands); // PSG commands first as PSG require main BUS access (DMA contention) if (psgCommands != NULL) newCommands = insertAllAfterLList(newCommands, XGCCommand_convert(psgCommands)); // then general YM commands if (ymCommands != NULL) newCommands = insertAllAfterLList(newCommands, XGCCommand_convert(ymCommands)); // then key commands if (ymKeyCommands != NULL) newCommands = insertAllAfterLList(newCommands, XGCCommand_convert(ymKeyCommands)); // and finally others commands if (otherCommands != NULL) newCommands = insertAllAfterLList(newCommands, XGCCommand_convert(otherCommands)); // state change stateChange = XGC_getStateChange(ymState, ymOldState); // add the state command if no empty if (stateChange != NULL) newCommands = insertAllAfterLList(newCommands, XGCCommand_createStateCommands(stateChange)); // is it the last frame ? if (com == NULL) { // loop point ? if (loopOffset != -1) newCommands = insertAfterLList(newCommands, XGMCommand_createLoopCommand(loopOffset)); else // add end command newCommands = insertAfterLList(newCommands, XGMCommand_createEndCommand()); } // get back to head newCommands = getHeadLList(newCommands); // limit frame commands to 255 bytes max size = 0; tmpCom = newCommands; while(tmpCom != NULL) { XGMCommand* command = tmpCom->element; // limit reached ? if ((size + command->size) >= 256) { // if ((frameInd > 10) && (!silent)) if (!silent) { int frameInd = XGC_computeLenInFrameOf(getHeadLList(xgcCommands)) + (XGC_computeLenInFrameOf(newCommands) - 1); printf("Warning: frame > 256 at frame %4X (need to split frame)\n", frameInd); } // end previous frame XGCCommand_setFrameSizeSize(sizeCommand, size); // insert new frame size info sizeCommand = XGCCommand_createFrameSizeCommand(0); insertBeforeLList(tmpCom, sizeCommand); // reset size and pass to next element size = 1; } size += command->size; tmpCom = tmpCom->next; } // set frame size XGCCommand_setFrameSizeSize(sizeCommand, size); // finally add the new commands xgcCommands = insertAllAfterLList(xgcCommands, newCommands); } xgc->commands = getHeadLList(xgcCommands); // compute offset & frame size XGC_computeAllOffset(xgc); XGC_computeAllFrameSize(xgc); if (!silent) printf("Number of command: %d\n", getSizeLList(xgc->commands)); }