home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / graphics / audio / idfedit / idf.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  41KB  |  1,433 lines

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