IDF.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:40k
源码类别:

Windows编程

开发平台:

Visual C++

  1. //************************************************************************
  2. //**
  3. //**  THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  4. //**  ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
  5. //**  TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR
  6. //**  A PARTICULAR PURPOSE.
  7. //**
  8. //**  Copyright (C) 1993 - 1997 Microsoft Corporation. All Rights Reserved.
  9. //**
  10. //**  idf.c
  11. //**
  12. //**  DESCRIPTION:
  13. //**    main worker code for IDF editing
  14. //**
  15. //************************************************************************
  16. #include <windows.h>
  17. #include <windowsx.h>
  18. #include <mmsystem.h>
  19. #include "idfedit.h"
  20. #include <commdlg.h>
  21. #include "drawstr.h"
  22. VOID FreeIDFFile (LPIDFHEAD);
  23. /*+ PromptForIDFName();
  24.  *
  25.  *
  26.  *  DESCRIPTION:
  27.  *     This function is a wrapper for the Get[Open/Save]FileName commdlg
  28.  *     chooser dialogs. Based on the fuFlags argument, this function
  29.  *     will display the appropriate chooser dialog and return the result.
  30.  *
  31.  *  ARGUMENTS:
  32.  *     HWND    hwnd          - Handle to parent window.
  33.  *     LPSTR   lpszPath      - Pointer to the buffer to receive the
  34.  *                             the file path.
  35.  *     LPSTR   lpszTitle     - Pointer to the buffer to receive the
  36.  *                             file the file title, NULL if no title
  37.  *                             is wanted.
  38.  *     BOOL     fSave        - TRUE if we are to save a file,
  39.  *                             FALSE if we are to open the file.
  40.  *
  41.  *  RETURNS:
  42.  *     BOOL  -  TRUE if a file was chosen. FALSE if the user canceled
  43.  *              the operation.
  44.  *
  45.  *-=======================================================================*/
  46. BOOL WINAPI PromptForIDFName (
  47.     HWND    hwnd,
  48.     LPTSTR  lpszPath,
  49.     LPTSTR  lpszTitle,
  50.     BOOL    fSave)
  51. {
  52.    OPENFILENAME   ofn;
  53.    TCHAR          szExtDefault[4];
  54.    TCHAR          szExtFilter[256];
  55.    LPTSTR         pstr;
  56.    BOOL           bRet;
  57.    //  Get the extension filter and default extension.
  58.    //
  59.    LoadString (hInst, IDS_OFN_EXT_DEF, szExtDefault, NUMELMS(szExtDefault));
  60.    LoadString (hInst, IDS_OFN_EXT_FILTER, szExtFilter, NUMELMS(szExtFilter));
  61.    // Parse the bang out of the filter string, replace with a NULL.
  62.    //
  63.    for (pstr = szExtFilter; *pstr; pstr = AnsiNext(pstr))
  64.       if (TEXT('!') == *pstr)
  65.          *pstr = 0;
  66.    // set the default path to *.ext
  67.    //
  68.    lpszPath[0] = TEXT('*');
  69.    if (szExtDefault[0])
  70.       {
  71.       lpszPath[1] = TEXT('.');
  72.       lstrcpy (lpszPath+2, szExtDefault);
  73.       }
  74.    // If there is a title then reset it also.
  75.    //
  76.    if (lpszTitle)
  77.       lpszTitle[0] = 0;
  78.    //  Initialize the OPENFILENAME structure elements.
  79.    //
  80.    ZeroMemory(&ofn, sizeof(ofn));
  81.    ofn.lStructSize    = sizeof(OPENFILENAME);
  82.    ofn.hwndOwner      = hwnd;
  83.    ofn.lpstrFilter    = szExtFilter;
  84.    ofn.nFilterIndex   = 1;
  85.    ofn.lpstrFile      = lpszPath;
  86.    ofn.nMaxFile       = MAX_PATH;
  87.    ofn.lpstrFileTitle = lpszTitle;
  88.    ofn.nMaxFileTitle  = lpszTitle ? MAX_PATH : 0;
  89.    ofn.lpstrDefExt    = szExtDefault;
  90.    //  If the fSave is TRUE, then call GetSaveFileName()
  91.    //  otherwise call GetOpenFileName().
  92.    //
  93.    if (fSave)
  94.       {
  95.       // Set the OPENFILENAME flags to save and prompt if we
  96.       // will overwrite an existing file.
  97.       //
  98.       ofn.Flags = OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT;
  99.       bRet = GetSaveFileName(&ofn);
  100.       }
  101.    else
  102.       {
  103.       // Set the OPENFILENAME flags to open and the file 
  104.       // must exist if we are opening.
  105.       //
  106.       ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
  107.       bRet = GetOpenFileName(&ofn);
  108.       }
  109.    return bRet;
  110. }
  111. STATICFN UINT fnMapLabel (
  112.    LPTSTR    psz,
  113.    UINT      cch,
  114.    UINT      uDummy,
  115.    UINT      uIndex,
  116.    UINT      uMsgID)
  117. {
  118.    UINT   lRet = 0;
  119.    switch (uMsgID)
  120.    {
  121.       case WM_GETTEXT:
  122.          lstrcpy (psz, "  0   1   2   3   4   5   6   7   8   9");
  123.          lRet = lstrlen (psz);
  124.          break;
  125.    }
  126.    return lRet;
  127. }
  128. #define BLANK_LINE "", 0,0,AS_HEX,0,0
  129. // 0
  130. //
  131. #undef STDFLD
  132. #define STDFLD(fld) FLD(INSTRUMENT,fld)
  133. static DSFIELD aINSTRUMENTfields[] = {
  134.     "IDF Version", STDFLD(dwVersion),            AS_HEX | IS_EDIT, 0, 0,
  135.     "IDF Creator", STDFLD(dwCreator),            AS_HEX | IS_EDIT, 0, 0,
  136. //  "Instrument Identifier",  STDFLD(szInstID),             AS_SZ | IS_EDIT,  0, 0,
  137.     BLANK_LINE,
  138.     "Manufacturer ID",      STDFLD(dwManufactID),         AS_INT | IS_EDIT, 0, 0,
  139.     "Product ID",           STDFLD(dwProductID),          AS_INT | IS_EDIT, 0, 0,
  140.     "Product Rev.",         STDFLD(dwRevision),           AS_INT | IS_EDIT, 0, 0,
  141.     "Manufacturer",         STDFLD(szManufact),           AS_SZ | IS_EDIT, 0, 0,
  142.     "Product Name",         STDFLD(szProduct),            AS_SZ | IS_EDIT, 0, 0,
  143.     BLANK_LINE,
  144.     "Supports General MIDI",   STDFLD(dwFlags), AS_BITFIELD | IS_EDIT, 0, 0,
  145.     "Supports SysEx Messages", STDFLD(dwFlags), AS_BITFIELD | IS_EDIT, 1, 0,
  146.     "Basic Channel",           STDFLD(dwBasicChannel),       AS_INT | IS_EDIT, 0, 0,
  147.     "Number of Channels",      STDFLD(nChannels),            AS_INT | IS_EDIT, 0, 0,
  148.     "Instrument Polyphony",    STDFLD(nInstrumentPolyphony), AS_INT | IS_EDIT, 0, 0,
  149.     "Channel Polyphony",       STDFLD(nChannelPolyphony),    AS_INT | IS_EDIT, 0, 0,
  150.     // pmap fields
  151.     //
  152.     BLANK_LINE,
  153.     "Patch Map",       0, 0, AS_XMODE, (DWORD)fnMapLabel, 0,
  154.     " %02d",           FIELDOFF(INSTRUMENT,aPatch), 10, AS_BYTES | IS_EDIT | AS_ARRAY, 0, 12,
  155.     " 12",             FIELDOFF(INSTRUMENT,aPatch) + 120, 8, AS_BYTES | IS_EDIT, 0, 0,
  156.     // key fields
  157.     //
  158.     BLANK_LINE,
  159.     "General Key Map", 0, 0,  AS_XMODE, (DWORD)fnMapLabel, 0,
  160.     " %02d",           FIELDOFF(INSTRUMENT,aGenKeymap), 10, AS_BYTES | IS_EDIT | AS_ARRAY, 0, 12,
  161.     " 12",             FIELDOFF(INSTRUMENT,aGenKeymap) + 120, 8, AS_BYTES | IS_EDIT, 0, 0,
  162.     BLANK_LINE,
  163.     "Drum Key Map",    0, 0,  AS_XMODE, (DWORD)fnMapLabel, 0,
  164.     " %02d",           FIELDOFF(INSTRUMENT,aDrumKeymap), 10, AS_BYTES | IS_EDIT | AS_ARRAY, 0, 12,
  165.     " 12",             FIELDOFF(INSTRUMENT,aDrumKeymap) + 120, 8, AS_BYTES | IS_EDIT, 0, 0,
  166.     // chnl fields
  167.     //
  168.     BLANK_LINE,
  169.     "Channel %2d",     FIELDOFF(INSTRUMENT,aChannel), 0, AS_ARRAY | AS_STRUCT, 1, 16,
  170.     // CHANNEL aChannel[MAX_CHANNEL];
  171.     NULL, (UINT)-1, 0, AS_NONE, 0, 0,
  172.     };
  173. #include <stdlib.h>
  174. STATICFN UINT AsciiToBytes (
  175.    LPDWORD lpv,
  176.    UINT    cb,
  177.    LPTSTR  psz)
  178.    {
  179.    UINT   jj;
  180.    for (jj = 0; ; ++jj)
  181.       {
  182.       ULONG uu;
  183.       LPTSTR pszStop;
  184.       while (*psz == 't' || *psz == ' ')
  185.          ++psz;
  186.       pszStop = psz;
  187.       uu = strtoul (psz, &pszStop, 16);
  188.       if (pszStop == psz)
  189.          break;
  190.       if (jj < cb/sizeof(*lpv))
  191.          lpv[jj] = uu;
  192.       psz = pszStop;
  193.       }
  194.    return jj * sizeof(*lpv);
  195.    }
  196. STATICFN VOID BytesToAscii (
  197.    LPTSTR  psz,
  198.    UINT    cch,
  199.    LPDWORD lpv,
  200.    UINT    cbData)
  201. {
  202.    UINT jj;
  203.    UINT cb;
  204.    for (jj = 0; jj < (cbData+sizeof(*lpv)-1)/sizeof(*lpv); ++jj)
  205.       {
  206.       wsprintf (psz, "%08lX ", lpv[jj]);
  207.       cch -= (cb = lstrlen(psz));
  208.       psz += cb;
  209.       *psz = 0;
  210.       if (cch < cb + 4)
  211.          {
  212.          *psz++ = '.';
  213.          *psz++ = '.';
  214.          *psz++ = '.';
  215.          *psz++ = 0;
  216.          break;
  217.          } 
  218.       }
  219. }   
  220. const TCHAR cszNone[] = "<none>";
  221. STATICFN UINT fnChanData (
  222.    LPTSTR    psz,
  223.    UINT      cch,
  224.    LPCHANNEL pChan,
  225.    UINT      uIndex,
  226.    UINT      uMsgID)
  227. {
  228.    LPDWORD lpvData = pChan->lpInit;
  229.    UINT    cbData  = pChan->cbInit;
  230.    UINT    lRet = 0;
  231.    switch (uMsgID)
  232.    {
  233.       case WM_GETTEXT:
  234.          if (!lpvData || !cbData)
  235.             lstrcpy (psz, cszNone);
  236.          else
  237.             BytesToAscii (psz, cch, lpvData, cbData);
  238.          lRet = lstrlen (psz);
  239.          break;
  240.       case WM_SETTEXT:
  241.          {
  242.          UINT uu;
  243.          // if we dont have a writable pointer to sysex data,
  244.          // we must allocate an editable one before we go further.
  245.          //
  246.          if (IsBadWritePtr (lpvData,1))
  247.             cbData = 0;
  248.          // if the data is not the string <none>
  249.          // parse it as HEX data and use that to set the sysex
  250.          // data.  if it is <none> remove the sysex data.
  251.          //
  252.          if (!psz || ! lstrcmpi(psz, cszNone))
  253.             uu = 0;
  254.          else
  255.             uu = AsciiToBytes (lpvData, cbData, psz);
  256.          // if there was more data than would fit in the current
  257.          // sysex buffer. allocate a new buffer and try again
  258.          //
  259.          if (uu > cbData)
  260.             {
  261.             if (cbData && lpvData)
  262.                HeapFree (gs.idf.hEditHeap, 0, lpvData);
  263.             lpvData = HeapAlloc (gs.idf.hEditHeap, 0, uu);
  264.             AsciiToBytes (lpvData, uu, psz);
  265.             }
  266.          // update pChan pointers to reflect the new sysex data
  267.          //
  268.          pChan->lpInit = lpvData;
  269.          pChan->cbInit = uu;
  270.          }
  271.          break;
  272.       case WM_COPY:
  273.          {
  274.          HGLOBAL hMem = GlobalAlloc (GHND, 4 + cbData * 3);
  275.          if (!(psz = GlobalLock (hMem)))
  276.             break;
  277.          // put the sysex data on the clipboard as ASCII
  278.          //
  279.          BytesToAscii (psz, 4 + cbData * 3, lpvData, cbData);
  280.          GlobalUnlock (hMem);
  281.          if (!OpenClipboard (hWndMain))
  282.             GlobalFree (hMem);
  283.          else
  284.             {
  285.             EmptyClipboard ();
  286.             SetClipboardData (CF_TEXT, hMem);
  287.             CloseClipboard ();
  288.             lRet = 1;
  289.             }
  290.          }
  291.          break;
  292.       case WM_PASTE:
  293.          {
  294.          HGLOBAL hMem;
  295.          // grap text from the clipboard and use it as the sysex data
  296.          // however, ignore the data if it's not valid hex data
  297.          //
  298.          if (!OpenClipboard (hWndMain))
  299.             break;
  300.          if (hMem = GetClipboardData (CF_TEXT))
  301.             {
  302.             if (psz = GlobalLock (hMem))
  303.                {
  304.                fnChanData (psz, GlobalSize(hMem), pChan, uIndex, WM_SETTEXT);
  305.                GlobalUnlock (hMem);
  306.                lRet = 1;
  307.                }
  308.             }
  309.          CloseClipboard ();
  310.          }
  311.          break;
  312.    }
  313.    return lRet;
  314. }
  315. // 0
  316. //
  317. #undef STDFLD
  318. #define STDFLD(fld) #fld, FLD(CHANNEL,fld)
  319. static DSFIELD aCHANNELfields[] = {
  320.     "Mute This Channel", FLD(CHANNEL,iFlags), AS_BITFIELD | IS_EDIT, 1, 0,
  321.     "Is Drum Channel",   FLD(CHANNEL,iFlags), AS_BITFIELD | IS_EDIT, 0, 0,
  322.     //"Init Data",  0, sizeof(CHANNEL), AS_XMODE | IS_EDIT, (DWORD)fnChanData, 0,
  323.     NULL, (UINT)-1, 0, AS_NONE, 0, 0,
  324.     };
  325. static DSFIELDTBL aStructs[] = {
  326.     aINSTRUMENTfields,   "INSTRUMENT", sizeof(INSTRUMENT),
  327.     aCHANNELfields,      "CHANNEL",    sizeof(CHANNEL),
  328.     };
  329. /*+ FindListChunk
  330.  *
  331.  *-======================================================================*/
  332. LPRIFF FindListChunk (
  333.    LPRIFFLIST pList,
  334.    DWORD      fccToFind)
  335. {
  336.    UINT   cbRemain;
  337.    LPRIFF pRiff;
  338.    // in this code, we expect to have only MMAP lists
  339.    //
  340.    assert (pList);
  341.    assert (pList->cbList > sizeof(RIFF) + sizeof(DWORD));
  342.    assert (pList->fccType == FCC_MMAP);
  343.    cbRemain = pList->cbList - sizeof(DWORD);
  344.    assert (cbRemain < 0x10000); // reasonableness check
  345.    // scan for the requested chunk
  346.    //
  347.    pRiff = (LPRIFF)(pList+1);
  348.    for (;;)
  349.       {
  350.       UINT cbAdvance = pRiff->cb + (pRiff->cb & 1) + sizeof(RIFF);
  351.       if (pRiff->fcc == fccToFind)
  352.          return pRiff;
  353.       if (cbRemain <= cbAdvance)
  354.          break;
  355.       cbRemain -= cbAdvance;
  356.       pRiff = NEXTRIFF(pRiff);
  357.       }
  358.    return NULL;
  359. }
  360. /*+ 
  361.  *
  362.  *-======================================================================*/
  363. LPVOID CopyForEditing (
  364.    LPVOID pData, 
  365.    UINT   cbData)
  366. {
  367.    LPVOID pDataT;
  368.    pDataT = HeapAlloc (gs.idf.hEditHeap, 0, cbData);
  369.    if (pDataT)
  370.       CopyMemory (pDataT, pData, cbData);
  371.    return pDataT;
  372. }   
  373. /*+ 
  374.  *
  375.  *-======================================================================*/
  376. void FreeInstrumEdits (
  377.    LPINSTRUMENT pInstrum)
  378. {
  379.    UINT      ii;
  380.    // free anything that has been dynamically allocated for editing
  381.    // purposes.  (currently only sysex channel init data)
  382.    //
  383.    for (ii = 0; ii < NUMELMS(pInstrum->aChannel); ++ii)
  384.       {
  385.       LPCHANNEL pChan = &pInstrum->aChannel[ii];
  386.       // if the pointer is a valid writeable pointer, assume it
  387.       // cam from the edit heap.
  388.       //
  389.       if (pChan->lpInit && !IsBadWritePtr(pChan->lpInit, 1))
  390.          HeapFree (gs.idf.hEditHeap, 0, pChan->lpInit);
  391.       ZeroMemory (pChan, sizeof(*pChan));
  392.       }
  393. }
  394. /*+ IdentityMap
  395.  *
  396.  *-======================================================================*/
  397. STATICFN void _inline IdentityMap (
  398.    LPBYTE abData)
  399. {
  400.    BYTE ii;
  401.    assert (MAX_PATCH == MAX_KEYMAP);
  402.    for (ii = 0; ii < MAX_KEYMAP; ++ii)
  403.       abData[ii] = ii;
  404. }
  405. /*+ IsIdentityMap
  406.  *
  407.  *-======================================================================*/
  408. STATICFN BOOL IsIdentityMap (
  409.    LPBYTE abData)
  410. {
  411.    BYTE ii;
  412.    assert (MAX_PATCH == MAX_KEYMAP);
  413.    for (ii = 0; ii < MAX_KEYMAP; ++ii)
  414.       if (abData[ii] != ii)
  415.          return FALSE;
  416.    return TRUE;
  417. }
  418. /*+ 
  419.  *
  420.  *-======================================================================*/
  421. void CopyInstrumData (
  422.    LPINSTRUMENT pInstrum, 
  423.    LPRIFFLIST   pList)
  424. {
  425.    LPRIFF pRiff;
  426.    UINT   ii;
  427.    #pragma message (SQUAWK "free channel data first?")
  428.    // initialize to defaults for optional fields in the IDF file
  429.    //
  430.    FreeInstrumEdits (pInstrum);
  431.    ZeroMemory (pInstrum, sizeof(*pInstrum));
  432.    IdentityMap (pInstrum->aPatch);
  433.    IdentityMap (pInstrum->aGenKeymap);
  434.    IdentityMap (pInstrum->aDrumKeymap);
  435.    pInstrum->aChannel[9].iFlags = CHANNEL_IS_DRUM;
  436.    assert (pList);
  437.    if (!pList)
  438.       return;
  439.    // is there a header chunk? if so, then
  440.    // copy it's data into the instrum structure
  441.    //
  442.    pRiff = FindListChunk (pList, FCC_hdr);
  443.    if (pRiff && pRiff->cb >= sizeof(IDFHEADER))
  444.       {
  445.       LPIDFHEADER phdr = (LPVOID)(pRiff+1);
  446.       pInstrum->dwVersion = phdr->dwVersion;
  447.       pInstrum->dwCreator = phdr->dwCreator;
  448.       // copy instrument id, and force a NULL terminator
  449.       //
  450.       CopyMemory (pInstrum->szInstID, 
  451.                   phdr->abInstID,
  452.                   max(phdr->cbInstID, NUMELMS(pInstrum->szInstID)));
  453.       pInstrum->szInstID[NUMELMS(pInstrum->szInstID)-1] = 0;
  454.       }
  455.    // manufacturer info
  456.    //
  457.    pRiff = FindListChunk (pList, FCC_inst);
  458.    if (pRiff && pRiff->cb >= sizeof(IDFINSTINFO))
  459.       {
  460.       LPIDFINSTINFO pinst = (LPVOID)(pRiff+1);
  461.       #pragma message (SQUAWK "get tables of manufactures & products")
  462.       pInstrum->dwManufactID = pinst->dwManufactID;
  463.       pInstrum->dwProductID = pinst->dwProductID;
  464.       pInstrum->dwRevision = pinst->dwRevision;
  465.      #ifdef UNICODE
  466.       CopyMemory (pInstrum->szManufact, pinst->abData,
  467.                   max(pinst->cbManufactUNICODE, sizeof(pInstrum->szManufact)));
  468.      #else
  469.       CopyMemory (pInstrum->szManufact, pinst->abData,
  470.                   max(pinst->cbManufactASCII, sizeof(pInstrum->szManufact)));
  471.      #endif
  472.       pInstrum->szManufact[NUMELMS(pInstrum->szManufact)-1] = 0;
  473.      #ifdef UNICODE
  474.       CopyMemory (pInstrum->szProduct, 
  475.                   pinst->abData + pinst->cbManufactASCII + pinst->cbManufactUNICODE, 
  476.                   max(pinst->cbProductUNICODE, sizeof(pInstrum->szProduct)));
  477.      #else
  478.       CopyMemory (pInstrum->szProduct,
  479.                   pinst->abData + pinst->cbManufactASCII + pinst->cbManufactUNICODE, 
  480.                   max(pinst->cbProductASCII, sizeof(pInstrum->szProduct)));
  481.      #endif
  482.       pInstrum->szProduct[NUMELMS(pInstrum->szProduct)-1] = 0;
  483.       }
  484.    // capabilities
  485.    //
  486.    pRiff = FindListChunk (pList, FCC_caps);
  487.    if (pRiff && pRiff->cb >= sizeof(IDFINSTCAPS))
  488.       {
  489.       LPIDFINSTCAPS pcaps = (LPVOID)(pRiff+1);
  490.       pInstrum->dwFlags = pcaps->fdwFlags;
  491.       pInstrum->dwBasicChannel = pcaps->dwBasicChannel;
  492.       pInstrum->nChannels      = pcaps->cNumChannels;
  493.       pInstrum->nInstrumentPolyphony = pcaps->cInstrumentPolyphony;
  494.       pInstrum->nChannelPolyphony = pcaps->cChannelPolyphony;
  495.       }
  496.    // per channel init data
  497.    //
  498.    pRiff = FindListChunk (pList, FCC_chan);
  499.    if (pRiff && pRiff->cb >= sizeof(IDFCHANNELHDR))
  500.       {
  501.       LPIDFCHANNELHDR  pchan = (LPVOID)(pRiff+1);
  502.       LPIDFCHANNELINFO pinfo = (LPVOID)(pchan+1);
  503.       UINT cbRemain = pRiff->cb - sizeof(IDFCHANNELHDR);
  504.       for (ii = 0; ii < NUMELMS(pInstrum->aChannel); ++ii)
  505.       {
  506.          pInstrum->aChannel[ii].iFlags &= ~CHANNEL_IS_MUTE;
  507.          if (pchan->dwDrumMask & (1 << ii))
  508.             pInstrum->aChannel[ii].iFlags |= CHANNEL_IS_DRUM;
  509.          else
  510.          {
  511.             pInstrum->aChannel[ii].iFlags &= ~CHANNEL_IS_DRUM;
  512.             if (!(pchan->dwGeneralMask & (1 << ii)))
  513.                pInstrum->aChannel[ii].iFlags |= CHANNEL_IS_MUTE;
  514.          }
  515.       }
  516.       for (ii = 0; /*ii < pchan->cNumChannels*/ ;++ii)
  517.          {
  518.          if (cbRemain < sizeof(IDFCHANNELINFO) ||
  519.              cbRemain < pinfo->cbStruct)
  520.             break;
  521.          if (pinfo->dwChannel < NUMELMS(pInstrum->aChannel))
  522.             {
  523.             LPCHANNEL pChan = &pInstrum->aChannel[pinfo->dwChannel];
  524.             pChan->cbInit = pinfo->cbInitData;
  525.             pChan->lpInit = (LPVOID)pinfo->abData;
  526.             }
  527.          cbRemain -= pinfo->cbStruct;
  528.          if (cbRemain < sizeof(IDFCHANNELINFO))
  529.             break;
  530.          pinfo = (LPVOID)((LPBYTE)pinfo + pinfo->cbStruct);
  531.          }
  532.       }
  533.    else
  534.       {
  535.       pRiff = FindListChunk (pList, FCC_chnl);
  536.       if (pRiff && pRiff->cb >= sizeof(IDFCHNLHDR))
  537.          {
  538.          LPIDFCHNLHDR pchnl = (LPVOID)(pRiff+1);
  539.          LPIDFCHNLINFO pinfo = (LPVOID)(pchnl+1);
  540.          UINT cbRemain = pRiff->cb;
  541.          if (cbRemain >= sizeof(IDFCHNLHDR) + sizeof(IDFCHNLINFO))
  542.             {
  543.             cbRemain -= sizeof(IDFCHNLHDR);
  544.             for (ii = 0; ii < pchnl->cNumChannels; ++ii)
  545.                {
  546.                if (cbRemain < pinfo->cbStruct)
  547.                   break;
  548.                if (pinfo->dwChannel < NUMELMS(pInstrum->aChannel))
  549.                   {
  550.                   LPCHANNEL pChan = &pInstrum->aChannel[pinfo->dwChannel];
  551.                   // for now, just point channel data at riff data, we'll
  552.                   // copy it when they try to actually edit it.
  553.                   //
  554.                   if (pinfo->fdwChannel & IDFCHNLINFO_F_DRUM_CHANNEL)
  555.                      {
  556.                      pChan->iFlags |= CHANNEL_IS_DRUM;
  557.                      pChan->cbInit = pinfo->cbDrumInitData;
  558.                      pChan->lpInit = (LPVOID)(pinfo->abData + pinfo->cbGeneralInitData);
  559.                      }
  560.                   else
  561.                      {
  562.                      pChan->iFlags &= ~CHANNEL_IS_DRUM;
  563.                      pChan->cbInit = pinfo->cbGeneralInitData;
  564.                      pChan->lpInit = (LPVOID)pinfo->abData;
  565.                      }
  566.                   }
  567.                cbRemain -= pinfo->cbStruct;
  568.                if (cbRemain < sizeof(IDFCHNLINFO))
  569.                   break;
  570.                pinfo = (LPVOID)((LPBYTE)pinfo + pinfo->cbStruct);
  571.                }
  572.             }
  573.          }
  574.       }
  575.    // patch map
  576.    //
  577.    pRiff = FindListChunk (pList, FCC_pmap);
  578.    if (pRiff && pRiff->cb >= sizeof(IDFPATCHMAPHDR))
  579.       {
  580.       LPIDFPATCHMAPHDR ppmap = (LPVOID)(pRiff+1);
  581.       CopyMemory (pInstrum->aPatch, ppmap->abPatchMap, sizeof(pInstrum->aPatch));
  582.       }
  583.    //
  584.    // key map.  we support old style 'key' chunk.  but will override
  585.    // it with the data from a new style 'gkey' & 'dkey' chunk if both
  586.    // are found
  587.    //
  588.    // old style 'key ' chunk
  589.    //
  590.    pRiff = FindListChunk (pList, FCC_key);
  591.    if (pRiff && pRiff->cb >= sizeof(IDFKEYHDR))
  592.       {
  593.       LPIDFKEYHDR pkey = (LPVOID)(pRiff+1);
  594.       LPIDFKEY    pmap = (LPVOID)(pkey+1);
  595.       UINT        nMaps = pkey->cNumKeyMaps;
  596.       UINT        cbRemain = pRiff->cb - sizeof(IDFKEYHDR);
  597.       // copy keymaps as we find them, we only recognize 2 differnent
  598.       // keymap types however.  and we only honor the last instance
  599.       // each type that we find
  600.       //
  601.       while (nMaps > 0 && cbRemain >= sizeof(IDFKEY))
  602.          {
  603.          if (IDFKEY_F_GENERAL_CHANNEL == pmap->fdwKeyMap)
  604.              CopyMemory (pInstrum->aGenKeymap, pmap->abKeyMap, sizeof(pInstrum->aGenKeymap));
  605.          else if (IDFKEY_F_DRUM_CHANNEL == pmap->fdwKeyMap)
  606.              CopyMemory (pInstrum->aDrumKeymap, pmap->abKeyMap, sizeof(pInstrum->aDrumKeymap));
  607.          --nMaps;
  608.          ++pmap;
  609.          cbRemain -= sizeof(IDFKEY);
  610.          }
  611.       }
  612.    // 'gkey' chunk
  613.    //
  614.    pRiff = FindListChunk (pList, FCC_gkey);
  615.    if (pRiff && pRiff->cb >= sizeof(IDFKEYMAP))
  616.       {
  617.       LPIDFKEYMAP pgkey = (LPVOID)(pRiff+1);
  618.       assert (sizeof(pgkey->abKeyMap) == sizeof(pInstrum->aGenKeymap));
  619.       CopyMemory (pInstrum->aGenKeymap, pgkey->abKeyMap, sizeof(pInstrum->aGenKeymap));
  620.       }
  621.    // 'dkey' chunk
  622.    //
  623.    pRiff = FindListChunk (pList, FCC_dkey);
  624.    if (pRiff && pRiff->cb >= sizeof(IDFKEYMAP))
  625.       {
  626.       LPIDFKEYMAP pdkey = (LPVOID)(pRiff+1);
  627.       assert (sizeof(pdkey->abKeyMap) == sizeof(pInstrum->aDrumKeymap));
  628.       CopyMemory (pInstrum->aDrumKeymap, pdkey->abKeyMap, sizeof(pInstrum->aDrumKeymap));
  629.       }
  630. }
  631. /*+ SaveInstrumToRiff
  632.  *
  633.  *-======================================================================*/
  634. VOID SaveInstrumToRiff(
  635.     LPRIFFLIST   pList, 
  636.     LPINSTRUMENT pInstrum)
  637. {
  638.     LPRIFF pRiff = (LPVOID)(pList+1);
  639.     // hdr
  640.     {
  641.     LPIDFHEADER phdr = (LPVOID)(pRiff+1);
  642.     UINT        cb = lstrlen(pInstrum->szInstID) + 1;
  643.     phdr->cbStruct = sizeof(*phdr) + cb;
  644.     phdr->dwVersion = pInstrum->dwVersion;
  645.     phdr->dwCreator = pInstrum->dwCreator;
  646.     phdr->cbInstID = cb;
  647.     lstrcpy (phdr->abInstID, pInstrum->szInstID);
  648.     phdr->abInstID[cb-1] = 0;
  649.     pRiff->fcc = FCC_hdr;
  650.     pRiff->cb = phdr->cbStruct;
  651.     pRiff = NEXTRIFF(pRiff);
  652.     }
  653.     // inst
  654.     //
  655.     {
  656.     LPIDFINSTINFO pinst = (LPVOID)(pRiff+1);
  657.     UINT          cb1 = lstrlen(pInstrum->szManufact)+1;
  658.     UINT          cb2 = lstrlen(pInstrum->szProduct)+1;
  659.     cb1 += (cb1 & 1);
  660.     cb2 += (cb2 & 2);
  661.     pinst->cbStruct = sizeof(*pinst) + (cb1 + cb2) * 3;
  662.     pinst->dwManufactID = pInstrum->dwManufactID;
  663.     pinst->dwProductID = pInstrum->dwProductID;
  664.     pinst->dwRevision = pInstrum->dwRevision;
  665.     pinst->cbManufactASCII = cb1;
  666.     pinst->cbManufactUNICODE = cb1 * 2;
  667.     pinst->cbProductASCII = cb2;
  668.     pinst->cbProductUNICODE = cb2 * 2;
  669.     ZeroMemory (pinst->abData, (cb1 + cb2) * 3);
  670.    #ifdef UNICODE
  671.     #error not yet implemented
  672.    #else
  673.     lstrcpy (pinst->abData, pInstrum->szManufact);
  674.     MultiByteToWideChar(CP_ACP, 0, pInstrum->szManufact, 
  675.                         cb1, (LPWSTR)(pinst->abData + cb1),  cb1);
  676.     lstrcpy (pinst->abData + (cb1 * 3), pInstrum->szProduct);
  677.     MultiByteToWideChar(CP_ACP, 0, pInstrum->szProduct, 
  678.                         cb2, (LPWSTR)(pinst->abData + (cb1 * 3) + cb2), cb2);
  679.    #endif
  680.     pRiff->fcc = FCC_inst;
  681.     pRiff->cb = pinst->cbStruct;
  682.     pRiff = NEXTRIFF(pRiff);
  683.     }
  684.     // caps
  685.     //
  686.     {
  687.     LPIDFINSTCAPS pcaps = (LPVOID)(pRiff+1);
  688.     pcaps->cbStruct = sizeof(*pcaps);
  689.     pcaps->fdwFlags = pInstrum->dwFlags;
  690.     pcaps->dwBasicChannel = pInstrum->dwBasicChannel;
  691.     pcaps->cNumChannels = pInstrum->nChannels;
  692.     pcaps->cInstrumentPolyphony = pInstrum->nInstrumentPolyphony;
  693.     pcaps->cChannelPolyphony = pInstrum->nChannelPolyphony;
  694.     pRiff->fcc = FCC_caps;
  695.     pRiff->cb = pcaps->cbStruct;
  696.     pRiff = NEXTRIFF(pRiff);
  697.     }
  698.     //
  699.     // chan chunk
  700.     //
  701.     {
  702.     LPIDFCHANNELHDR  pchan = (LPVOID)(pRiff+1);
  703.     LPIDFCHANNELINFO pinfo = (LPVOID)(pchan+1);
  704.     UINT cbTotal = 0;
  705.     UINT ii;
  706.     pchan->cbStruct = sizeof(*pchan);
  707.     pchan->dwDrumMask = 0;
  708.     pchan->dwGeneralMask = 0x0000FFFF;
  709.     for (ii = 0; ii < NUMELMS(pInstrum->aChannel); ++ii)
  710.         if (pInstrum->aChannel[ii].iFlags & CHANNEL_IS_MUTE)
  711.             pchan->dwGeneralMask &= ~(1 << ii);
  712.         else if (pInstrum->aChannel[ii].iFlags & CHANNEL_IS_DRUM)
  713.             pchan->dwDrumMask |= (1 << ii);
  714.     pchan->dwGeneralMask &= ~(pchan->dwDrumMask);
  715.     pchan->fdwFlags = 0;
  716.     cbTotal = pchan->cbStruct;
  717.     for (ii = 0; ii < NUMELMS(pInstrum->aChannel); ++ii)
  718.        {
  719.        LPCHANNEL pChan = &pInstrum->aChannel[ii];
  720.        // if we have non-default channel info. append
  721.        // channel info data
  722.        //
  723.        if (pChan->cbInit)
  724.           {
  725.           UINT cbData = (pChan->cbInit + 3) & ~3;
  726.           pinfo->dwChannel = ii;
  727.           pinfo->cbInitData = cbData;
  728.           ZeroMemory (pinfo->abData, cbData);
  729.           CopyMemory (pinfo->abData, pChan->lpInit, pChan->cbInit);
  730.           // advance pinfo to the next channel header
  731.           //
  732.           //++pchan->cNumChannels;
  733.           pinfo->cbStruct = sizeof(*pinfo) + cbData;
  734.           cbTotal += pinfo->cbStruct;
  735.           pinfo = (LPVOID)(((LPBYTE)pinfo) + pinfo->cbStruct);
  736.           }
  737.        }
  738.     // save the chan chunk
  739.     //
  740.     pRiff->fcc = FCC_chan;
  741.     pRiff->cb = cbTotal;
  742.     pRiff = NEXTRIFF(pRiff);
  743.     }
  744.     // pmap
  745.     //
  746.     {
  747.     if (!IsIdentityMap(pInstrum->aPatch))
  748.        {
  749.        LPIDFPATCHMAPHDR ppmap = (LPVOID)(pRiff+1);
  750.        ppmap->cbStruct = sizeof(*ppmap);
  751.        CopyMemory (ppmap->abPatchMap, pInstrum->aPatch, sizeof(ppmap->abPatchMap));
  752.        pRiff->fcc = FCC_pmap;
  753.        pRiff->cb = ppmap->cbStruct;  
  754.        pRiff = NEXTRIFF(pRiff);
  755.        }
  756.     //
  757.     // gkey chunk (general keymap)
  758.     //
  759.     if (!IsIdentityMap(pInstrum->aGenKeymap))
  760.        {
  761.        LPIDFKEYMAP pgkey = (LPVOID)(pRiff+1);
  762.        pgkey->cbStruct = sizeof(*pgkey);
  763.        CopyMemory (pgkey->abKeyMap, pInstrum->aGenKeymap, sizeof(pgkey->abKeyMap));
  764.        pRiff->fcc = FCC_gkey;
  765.        pRiff->cb = sizeof(*pgkey);
  766.        pRiff = NEXTRIFF(pRiff);
  767.        }
  768.     // dkey chunk (drum keymap)
  769.     //
  770.     if (!IsIdentityMap(pInstrum->aDrumKeymap))
  771.        {
  772.        LPIDFKEYMAP pdkey = (LPVOID)(pRiff+1);
  773.        pdkey->cbStruct = sizeof(*pdkey);
  774.        CopyMemory (pdkey->abKeyMap, pInstrum->aDrumKeymap, sizeof(pdkey->abKeyMap));
  775.        pRiff->fcc = FCC_dkey;
  776.        pRiff->cb = sizeof(*pdkey);
  777.        pRiff = NEXTRIFF(pRiff);
  778.        }
  779.     }
  780.     pList->fccList = FCC_LIST;
  781.     pList->cbList = (DWORD)pRiff - (DWORD)pList - sizeof(RIFF);
  782.     pList->fccType = FCC_MMAP;
  783. }
  784. /*+ GetBackupName
  785.  *
  786.  *-======================================================================*/
  787. BOOL GetBackupName (
  788.    LPTSTR pszBak,
  789.    LPTSTR pszName)
  790. {
  791.    LPTSTR psz;
  792.    lstrcpy (pszBak, pszName);
  793.    psz = pszBak + lstrlen(pszBak);
  794.    while (psz > pszBak)
  795.       {
  796.       if (*psz == TEXT(':'))
  797.          break;
  798.       if (*psz == TEXT('\'))
  799.          break;
  800.       if (*psz == TEXT('.'))
  801.          *psz = 0;
  802.       --psz;
  803.       }
  804.    lstrcat (pszBak, TEXT(".id-"));
  805.    return TRUE;
  806. }
  807. /*+ InstrumMaxRiffDataSize
  808.  *
  809.  *-======================================================================*/
  810. STATICFN UINT InstrumMaxRiffDataSize (
  811.    LPINSTRUMENT pInstrum)
  812. {
  813.    UINT cbData;
  814.    UINT ii;
  815.    cbData = (sizeof(RIFF) * 6)
  816.             + sizeof(IDFHEADER) + MAX_NAME 
  817.             + sizeof(IDFINSTINFO) + (MAX_NAME * 6)
  818.             + sizeof(IDFINSTCAPS)
  819.             + sizeof(IDFCHNLHDR)
  820.             + sizeof(IDFPATCHMAPHDR)
  821.             + sizeof(IDFKEYHDR) + (sizeof(IDFKEY) * 2);
  822.    for (ii = 0; ii < NUMELMS(pInstrum->aChannel); ++ii)
  823.        {
  824.        LPCHANNEL pChan = &pInstrum->aChannel[ii];
  825.        cbData += pChan->cbInit + sizeof(IDFCHNLINFO);
  826.        }
  827.    return cbData;
  828. }
  829. /*+ SaveIDFToFile 
  830.  *
  831.  *-======================================================================*/
  832. BOOL SaveIDFToFile (
  833.    LPIDFHEAD pIDF,
  834.    LPTSTR    pszFileIn)
  835. {
  836.    HANDLE hFile = NULL;
  837.    HANDLE hSection = NULL;
  838.    LPBYTE pBase = NULL;
  839.    TCHAR  szBakName[MAX_PATH];
  840.    LPTSTR pszFile = pszFileIn;
  841.    DWORD  cbFile;
  842.    UINT   ii;
  843.    LPRIFFLIST pList;
  844.    // are we saving to the same name? if so
  845.    // rename the old file to a backup name
  846.    //
  847.    szBakName[0] = 0;
  848.    if (!lstrcmpi(pszFile, pIDF->szFile))
  849.    {
  850.       if (pIDF->bReadOnly)
  851.          return FALSE;
  852.       GetBackupName (szBakName, pszFile);
  853.       pszFile = szBakName;
  854.    }
  855.    // determine necessary file size
  856.    //
  857.    cbFile = sizeof(RIFFLIST) * 2;
  858.    for (ii = 0; ii < pIDF->nInstrum; ++ii)
  859.       {
  860.       cbFile += sizeof(RIFFLIST);
  861.       if (pIDF->ai[ii].pInstrum)
  862.          {
  863.          cbFile += InstrumMaxRiffDataSize (pIDF->ai[ii].pInstrum);
  864.          }
  865.       else if (pIDF->ai[ii].pList)
  866.          {
  867.          cbFile += pIDF->ai[ii].pList->cbList;
  868.          }
  869.       else
  870.          {
  871.          assert (0); // should never get here
  872.          }
  873.       }
  874.    // open a writable mapped file of the size
  875.    // necessary to write the IDF data
  876.    //
  877.    hFile = CreateFile (pszFile,
  878.                        GENERIC_READ | GENERIC_WRITE,
  879.                        FILE_SHARE_READ,
  880.                        NULL, // security
  881.                        OPEN_ALWAYS,
  882.                        FILE_ATTRIBUTE_NORMAL,
  883.                        NULL);
  884.    if (INVALID_HANDLE_VALUE == hFile)
  885.       goto error_exit;
  886.    SetFilePointer (hFile, cbFile, NULL, FILE_BEGIN);
  887.    SetEndOfFile (hFile);
  888.    hSection = CreateFileMapping (hFile, NULL,
  889.                                  PAGE_READWRITE, 0, 0, NULL);
  890.    if (INVALID_HANDLE_VALUE == hSection)
  891.       goto error_exit;
  892.    pBase = MapViewOfFile (hSection, FILE_MAP_ALL_ACCESS, 0, 0, 0);
  893.    if (NULL == pBase)
  894.       goto error_exit;
  895.    // Create RIFF data into the memory mapped file
  896.    //   
  897.    pList = (LPVOID)pBase;
  898.    pList->fccList = FCC_RIFF;
  899.    pList->cbList = 0;
  900.    pList->fccType = FCC_IDF;
  901.    ++pList;
  902.    for (ii = 0; ii < pIDF->nInstrum; ++ii)
  903.       {
  904.       struct _instrum_info * pi = &pIDF->ai[ii];
  905.       pList->cbList = 0;
  906.       if (pi->pInstrum)
  907.          {
  908.          SaveInstrumToRiff(pList, pi->pInstrum);
  909.          }
  910.       else if (pi->pList)
  911.          {   
  912.          CopyMemory (pList, pi->pList, 
  913.                      pi->pList->cbList + sizeof(RIFF));
  914.          }
  915.       else
  916.          {
  917.          assert(0);
  918.          }
  919.       if (pList->cbList > 0)
  920.          pList = (LPVOID) NEXTRIFF(pList);
  921.       }
  922.    cbFile = (DWORD)pList - (DWORD)pBase;
  923.    ((LPRIFF)pBase)->cb = cbFile - sizeof(RIFF);
  924.    UnmapViewOfFile (pBase);
  925.    CloseHandle (hSection);
  926.    SetFilePointer (hFile, cbFile, NULL, FILE_BEGIN);
  927.    SetEndOfFile (hFile);
  928.    CloseHandle (hFile);
  929.    // close the existing file, delete the old file, 
  930.    // rename the new file to the previous filename
  931.    // and open the new file & display contents
  932.    //
  933.    FreeIDFFile (pIDF);
  934.    if (pszFile == szBakName)
  935.       {
  936.       pszFile = pszFileIn;
  937.       DeleteFile (pszFile);
  938.       if ( ! MoveFile (szBakName, pszFile))
  939.          {
  940.          // inexplicable failure copy the back over the origonal,
  941.          // int this case we delete the backup and return failure
  942.          //
  943.          DeleteFile (szBakName);
  944.          return FALSE;
  945.          }
  946.       }
  947.    // return success
  948.    //
  949.    return TRUE;
  950. error_exit:
  951.    if (pBase)
  952.       UnmapViewOfFile (pBase);
  953.    if (hSection && INVALID_HANDLE_VALUE != hSection)
  954.       CloseHandle (hSection);
  955.    if (hFile && INVALID_HANDLE_VALUE != hFile)
  956.       CloseHandle (hFile);
  957.    return FALSE;
  958. }
  959. /*+
  960.  *
  961.  *-======================================================================*/
  962. VOID FreeIDFFile (
  963.    LPIDFHEAD pIDF)
  964. {
  965.    if (pIDF->pFileBase)
  966.       UnmapViewOfFile (pIDF->pFileBase), pIDF->pFileBase = NULL;
  967.    if (pIDF->hSection && INVALID_HANDLE_VALUE != pIDF->hSection)
  968.       CloseHandle (pIDF->hSection), pIDF->hSection = NULL;
  969.    if (pIDF->hFile && INVALID_HANDLE_VALUE != pIDF->hFile)
  970.       CloseHandle (pIDF->hFile), pIDF->hFile = NULL;
  971.    if (gs.idf.hEditHeap)
  972.       HeapDestroy (gs.idf.hEditHeap);
  973.    gs.idf.hEditHeap = HeapCreate (0, 0x1000, 0x100000);
  974.    gs.idf.vi.pTable = aStructs;
  975.    gs.idf.vi.lpData = &gs.idf.instrum;
  976.    pIDF->bChanged = FALSE;
  977.    pIDF->nInstrum = 0;
  978.    pIDF->piSelect = NULL;
  979.    pIDF->pInstrumSelect = NULL;
  980.    ZeroMemory (pIDF->ai, sizeof(pIDF->ai));
  981.    ZeroMemory (&pIDF->instrum, sizeof(pIDF->instrum));
  982.    pIDF->szFile[0] = 0;
  983. }
  984. typedef struct _idffile {
  985.     DWORD fccRIFF;
  986.     DWORD cbRIFF;
  987.     DWORD fccIDF;
  988.     } IDFFILE, * LPIDFFILE;
  989. /*+
  990.  *
  991.  *-======================================================================*/
  992. BOOL LoadIDFFromFile (
  993.    LPIDFHEAD pIDF,
  994.    LPTSTR    pszFile)
  995. {
  996.    LPIDFFILE  pIdfFile;
  997.    LPRIFFLIST pList;
  998.    DWORD      cbRemain;
  999.    UINT       ii;
  1000.    if (!pszFile)
  1001.       pszFile = pIDF->szFile;
  1002.    pIDF->bReadOnly = FALSE;
  1003.    pIDF->hFile = CreateFile (pszFile,
  1004.                              GENERIC_READ | GENERIC_WRITE,
  1005.                              FILE_SHARE_READ,
  1006.                              NULL, // security
  1007.                              OPEN_EXISTING,
  1008.                              FILE_ATTRIBUTE_NORMAL,
  1009.                              NULL);
  1010.    if (INVALID_HANDLE_VALUE == pIDF->hFile)
  1011.    {
  1012.       pIDF->bReadOnly = TRUE;
  1013.       pIDF->hFile = CreateFile (pszFile,
  1014.                                 GENERIC_READ,
  1015.                                 FILE_SHARE_READ,
  1016.                                 NULL, // security
  1017.                                 OPEN_EXISTING,
  1018.                                 FILE_ATTRIBUTE_NORMAL,
  1019.                                 NULL);
  1020.       if (INVALID_HANDLE_VALUE == pIDF->hFile)
  1021.          goto error_exit;
  1022.    }
  1023.    pIDF->hSection = CreateFileMapping (pIDF->hFile, NULL,
  1024.                                        PAGE_READONLY, //PAGE_READWRITE,
  1025.                                        0, 0, NULL);
  1026.    if (INVALID_HANDLE_VALUE == pIDF->hSection)
  1027.       goto error_exit;
  1028.    pIDF->pFileBase = MapViewOfFile (pIDF->hSection, FILE_MAP_READ, 0, 0, 0);
  1029.    if (NULL == pIDF->pFileBase)
  1030.       goto error_exit;
  1031.    pIDF->cbFile = GetFileSize (pIDF->hFile, NULL);
  1032.    // verify that this is indeed a valid IDF file
  1033.    //
  1034.    pIdfFile = (LPVOID)pIDF->pFileBase;
  1035.    if (pIdfFile->fccRIFF != FCC_RIFF ||
  1036.        pIdfFile->cbRIFF + sizeof(RIFF) > pIDF->cbFile ||
  1037.        pIdfFile->fccIDF != FCC_IDF)
  1038.        goto error_exit;
  1039.    lstrcpy (pIDF->szFile, pszFile);
  1040.    // now parse the IDF file and find the instruments therein
  1041.    //
  1042.    pList = (LPVOID)(pIdfFile + 1);
  1043.    cbRemain = pIdfFile->cbRIFF;
  1044.    for (ii = 0;
  1045.         pList->fccList == FCC_LIST && (ii < NUMELMS(pIDF->ai));
  1046.         ++ii, pList = (LPVOID) NEXTRIFF(pList))
  1047.       {
  1048.       UINT cbAdvance = pList->cbList + (pList->cbList & 1) + sizeof(RIFF); 
  1049.       pIDF->ai[ii].pList = pList;
  1050.       pIDF->nInstrum = ii+1;
  1051.       if (cbAdvance > cbRemain)
  1052.          break;
  1053.       cbRemain -= cbAdvance;
  1054.       }
  1055.    if (pIDF->nInstrum)
  1056.       pIDF->piSelect = &pIDF->ai[0];
  1057.    pIDF->bChanged = FALSE;
  1058.    return TRUE;
  1059. error_exit:
  1060.   #if defined DEBUG || defined _DEBUG
  1061.    {
  1062.    TCHAR sz[512];
  1063.    lstrcpy (sz, "LoadIDFFromFile failed: ");
  1064.    FormatMessage (FORMAT_MESSAGE_IGNORE_INSERTS
  1065.                   | FORMAT_MESSAGE_FROM_SYSTEM,
  1066.                   0,
  1067.                   GetLastError(),
  1068.                   0,
  1069.                   sz + lstrlen(sz),
  1070.                   NUMELMS(sz) - lstrlen(sz),
  1071.                   NULL);
  1072.    lstrcat (sz, "rn");
  1073.    OutputDebugString (sz);
  1074.    }
  1075.   #endif
  1076.    FreeIDFFile (pIDF);
  1077.    return FALSE;
  1078. }
  1079. /*+ NewIDFInstrum
  1080.  *
  1081.  *-======================================================================*/
  1082. LPINSTRUMENT WINAPI NewIDFInstrum (
  1083.    LPIDFHEAD  pIDF,
  1084.    LPRIFFLIST pList, // optional RIFF init data for instrument
  1085.    LPSTR      pszInstrument)
  1086. {
  1087.    static VIEWINIT vi;
  1088.    LPINSTRUMENT    lpi;
  1089.    if (pIDF->nInstrum >= NUMELMS(pIDF->ai))
  1090.       return NULL;
  1091.    lpi = HeapAlloc (gs.idf.hEditHeap, HEAP_ZERO_MEMORY, sizeof(INSTRUMENT));
  1092.    if (lpi)
  1093.       {
  1094.       static struct {
  1095.           RIFFLIST    list;
  1096.           RIFF        rhdr;
  1097.           IDFHEADER   hdr;
  1098.           RIFF        rcaps;
  1099.           IDFINSTCAPS caps;
  1100.           }  gmMMAP = { 
  1101.               FCC_LIST, sizeof(gmMMAP) - sizeof(RIFF), FCC_MMAP, //list
  1102.               FCC_hdr, sizeof(IDFHEADER),           // rhdr
  1103.               sizeof(IDFHEADER), 0x100, 1, 1, 0,    // hdr
  1104.               FCC_caps, sizeof(IDFINSTCAPS), 
  1105.               sizeof(IDFINSTCAPS),          // caps size
  1106.               IDFINSTCAPS_F_GENERAL_MIDI,   // caps flags
  1107.               1,                            // caps basic channel 
  1108.               16,                           // caps num channels 
  1109.               16,                           // instrument polyphony
  1110.               16,                           // channel polyphony
  1111.           };
  1112.       // set default instrument data
  1113.       //
  1114.       if (!pList)
  1115.          pList = &gmMMAP.list;
  1116.       CopyInstrumData (lpi, pList);
  1117.       if (pszInstrument)
  1118.          lstrcpyA (lpi->szInstID, pszInstrument);
  1119.       pIDF->ai[pIDF->nInstrum].pList = pList;
  1120.       pIDF->ai[pIDF->nInstrum].pInstrum = lpi;
  1121.       pIDF->piSelect = &pIDF->ai[pIDF->nInstrum];
  1122.       ++pIDF->nInstrum;
  1123.       pIDF->bChanged = TRUE;
  1124.       }
  1125.    return lpi;
  1126. }
  1127. /*+ DeleteInstrum
  1128.  *
  1129.  *-======================================================================*/
  1130. VOID DeleteInstrum (
  1131.    LPIDFHEAD pIDF)
  1132. {
  1133.    UINT ii;
  1134.    // figure out which slot in the instrument array
  1135.    // is the selected one.
  1136.    //
  1137.    for (ii = 0; ii < pIDF->nInstrum; ++ii)
  1138.       {
  1139.       if (pIDF->piSelect == &pIDF->ai[ii])
  1140.          {
  1141.          struct _instrum_info info;
  1142.          assert (pIDF->nInstrum > 0);
  1143.          // exchange the selected instrument with the one
  1144.          // at the end of the list. then decrement the
  1145.          // count of valid instruments.
  1146.          //
  1147.          info = pIDF->ai[ii];
  1148.          pIDF->ai[ii] = pIDF->ai[pIDF->nInstrum-1];
  1149.          pIDF->ai[pIDF->nInstrum-1] = info;
  1150.          --pIDF->nInstrum;
  1151.          pIDF->bChanged = TRUE;
  1152.          Head_RefreshTree (pIDF->hWndHead);
  1153.          break;
  1154.          }
  1155.       }               
  1156. }
  1157. /*+ CopyInstrumToClip
  1158.  *
  1159.  *-======================================================================*/
  1160. VOID CopyInstrumToClip (
  1161.    LPIDFHEAD pIDF)
  1162. {
  1163.    UINT ii;
  1164.    for (ii = 0; ii < pIDF->nInstrum; ++ii)
  1165.       {
  1166.       if (pIDF->piSelect == &pIDF->ai[ii])
  1167.          {
  1168.          HGLOBAL hMem;
  1169.          if (pIDF->piSelect->pInstrum)
  1170.             {
  1171.             LPRIFFLIST pList;
  1172.             UINT   cb = InstrumMaxRiffDataSize (pIDF->piSelect->pInstrum);
  1173.             hMem = GlobalAlloc (GHND | GMEM_ZEROINIT, cb);
  1174.             if (!(pList = GlobalLock (hMem)))
  1175.                return;
  1176.             SaveInstrumToRiff (pList, pIDF->piSelect->pInstrum);
  1177.             GlobalUnlock (hMem);
  1178.             GlobalReAlloc (hMem, pList->cbList + sizeof(RIFF), 0);
  1179.             }
  1180.          else if (pIDF->piSelect->pList)
  1181.             {
  1182.             LPBYTE lpv;
  1183.             UINT   cb = pIDF->piSelect->pList->cbList + sizeof(RIFF);
  1184.             hMem = GlobalAlloc (GHND, cb);
  1185.             if (!(lpv = GlobalLock (hMem)))
  1186.                return;
  1187.             CopyMemory (lpv, pIDF->piSelect->pList, cb);
  1188.             GlobalUnlock (hMem);
  1189.             }
  1190.          if (!OpenClipboard (hWndMain))
  1191.             GlobalFree (hMem);
  1192.          else
  1193.             {
  1194.             EmptyClipboard ();
  1195.             SetClipboardData (CF_RIFF, hMem);
  1196.             CloseClipboard ();
  1197.             }
  1198.          }
  1199.       }               
  1200. }
  1201. /*+ PasteInstrum
  1202.  *
  1203.  *-======================================================================*/
  1204. VOID PasteInstrum (
  1205.    LPIDFHEAD pIDF)
  1206. {
  1207.    HGLOBAL      hMem;
  1208.    LPRIFFLIST   pList;
  1209.    if (!OpenClipboard(hWndMain))
  1210.       return;
  1211.    if (hMem = GetClipboardData(CF_RIFF))
  1212.       {
  1213.       if (pList = GlobalLock (hMem))
  1214.          {
  1215.          if (pList->fccList == FCC_LIST && pList->fccType == FCC_MMAP)
  1216.             {
  1217.             NewIDFInstrum (pIDF, pList, NULL);
  1218.             Head_RefreshTree (pIDF->hWndHead);
  1219.             }
  1220.          GlobalUnlock (hMem);
  1221.          }
  1222.       }
  1223.    CloseClipboard ();
  1224.    return;
  1225. }