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

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. ******************************************************************************
  11. *
  12. * SMFRead.C
  13. *
  14. * MIDI File access routines.
  15. *
  16. *****************************************************************************/
  17. #include <windows.h>
  18. #include <windowsx.h>
  19. #include <mmsystem.h>
  20. #include <memory.h>
  21. #include "muldiv32.h" 
  22. #include "smf.h"
  23. #include "smfi.h"
  24. #include "debug.h"
  25. PRIVATE UINT grbChanMsgLen[] =
  26.     0,                      /* 0x   not a status byte   */
  27.     0,                      /* 1x   not a status byte   */
  28.     0,                      /* 2x   not a status byte   */
  29.     0,                      /* 3x   not a status byte   */
  30.     0,                      /* 4x   not a status byte   */
  31.     0,                      /* 5x   not a status byte   */
  32.     0,                      /* 6x   not a status byte   */
  33.     0,                      /* 7x   not a status byte   */
  34.     3,                      /* 8x   Note off            */
  35.     3,                      /* 9x   Note on             */
  36.     3,                      /* Ax   Poly pressure       */
  37.     3,                      /* Bx   Control change      */
  38.     2,                      /* Cx   Program change      */
  39.     2,                      /* Dx   Chan pressure       */
  40.     3,                      /* Ex   Pitch bend change   */
  41.     0,                      /* Fx   SysEx (see below)   */             
  42. } ;
  43. /******************************************************************************
  44. *
  45. * smfBuildFileIndex
  46. *
  47. * Preliminary parsing of a MIDI file.
  48. *
  49. * ppSmf                     - Pointer to a returned SMF structure if the
  50. *                             file is successfully parsed.
  51. *
  52. * Returns
  53. *   SMF_SUCCESS The events were successfully read.
  54. *   SMF_NO_MEMORY Out of memory to build key frames.
  55. *   SMF_INVALID_FILE A disk or parse error occured on the file.
  56. * This function validates the format of and existing MIDI or RMI file
  57. * and builds the handle structure which will refer to it for the
  58. * lifetime of the instance.
  59. *  
  60. * The file header information will be read and verified, and
  61. * smfBuildTrackIndices will be called on every existing track
  62. * to build keyframes and validate the track format.
  63. *
  64. *****************************************************************************/
  65. SMFRESULT FNLOCAL smfBuildFileIndex(
  66.     PSMF BSTACK *           ppSmf)
  67. {
  68.     SMFRESULT               smfrc;
  69.     UNALIGNED CHUNKHDR *    pCh;
  70.     FILEHDR FAR *           pFh;
  71.     DWORD                   idx;
  72.     PSMF                    pSmf,
  73.                             pSmfTemp;
  74.     PTRACK                  pTrk;
  75.     WORD                    wMemory;
  76.     DWORD                   dwLeft;
  77.     HPBYTE                  hpbImage;
  78.     
  79.     DWORD                   idxTrack;
  80.     EVENT                   event;
  81.     BOOL                    fFirst;
  82.     DWORD                   dwLength;
  83.     HLOCAL                  hLocal;
  84.     PTEMPOMAPENTRY          pTempo;
  85.     assert(ppSmf != NULL);
  86.     pSmf = *ppSmf;
  87.     assert(pSmf != NULL);
  88.     /* MIDI data image is already in hpbImage (already extracted from
  89.     ** RIFF header if necessary).
  90.     */
  91.     /* Validate MIDI header
  92.     */
  93.     dwLeft   = pSmf->cbImage;
  94.     hpbImage = pSmf->hpbImage;
  95.     
  96.     if (dwLeft < sizeof(CHUNKHDR))
  97.         return SMF_INVALID_FILE;
  98.     pCh = (CHUNKHDR FAR *)hpbImage;
  99.     dwLeft   -= sizeof(CHUNKHDR);
  100.     hpbImage += sizeof(CHUNKHDR);
  101.     
  102.     if (pCh->fourccType != FOURCC_MThd)
  103.         return SMF_INVALID_FILE;
  104.     dwLength = DWORDSWAP(pCh->dwLength);
  105.     if (dwLength < sizeof(FILEHDR) || dwLength > dwLeft)
  106.         return SMF_INVALID_FILE;
  107.     pFh = (FILEHDR FAR *)hpbImage;
  108.     dwLeft   -= dwLength;
  109.     hpbImage += dwLength;
  110.     
  111.     pSmf->dwFormat       = (DWORD)(WORDSWAP(pFh->wFormat));
  112.     pSmf->dwTracks       = (DWORD)(WORDSWAP(pFh->wTracks));
  113.     pSmf->dwTimeDivision = (DWORD)(WORDSWAP(pFh->wDivision));
  114.     /*
  115.     ** We've successfully parsed the header. Now try to build the track
  116.     ** index.
  117.     ** 
  118.     ** We only check out the track header chunk here; the track will be
  119.     ** preparsed after we do a quick integretiy check.
  120.     */
  121.     wMemory = sizeof(SMF) + (WORD)(pSmf->dwTracks*sizeof(TRACK));
  122.     pSmfTemp = (PSMF)LocalReAlloc((HLOCAL)pSmf, wMemory, LMEM_MOVEABLE|LMEM_ZEROINIT);
  123.     if (NULL == pSmfTemp)
  124.     {
  125.         DPF(1, "No memory for extended pSmf");
  126.         return SMF_NO_MEMORY;
  127.     }
  128.     pSmf = *ppSmf = pSmfTemp;
  129.     pTrk = pSmf->rTracks;
  130.     
  131.     for (idx=0; idx<pSmf->dwTracks; idx++)
  132.     {
  133.         if (dwLeft < sizeof(CHUNKHDR))
  134.             return SMF_INVALID_FILE;
  135.         pCh = (CHUNKHDR FAR *)hpbImage;
  136.         dwLeft   -= sizeof(CHUNKHDR);
  137.         hpbImage += sizeof(CHUNKHDR);
  138.         if (pCh->fourccType != FOURCC_MTrk)
  139.             return SMF_INVALID_FILE;
  140.         
  141.         pTrk->idxTrack      = (DWORD)(hpbImage - pSmf->hpbImage);
  142.         pTrk->smti.cbLength = DWORDSWAP(pCh->dwLength);
  143.         if (pTrk->smti.cbLength > dwLeft)
  144.         {
  145.             DPF(1, "Track longer than file!");
  146.             return SMF_INVALID_FILE;
  147.         }
  148.         dwLeft   -= pTrk->smti.cbLength;
  149.         hpbImage += pTrk->smti.cbLength;
  150.         pTrk++;
  151.     }
  152.     /* File looks OK. Now preparse, doing the following:
  153.     ** (1) Build tempo map so we can convert to/from ticks quickly
  154.     ** (2) Determine actual tick length of file
  155.     ** (3) Validate all events in all tracks
  156.     */ 
  157.     pSmf->tkPosition = 0;
  158.     pSmf->fdwSMF &= ~SMF_F_EOF;
  159.     
  160.     for (pTrk = pSmf->rTracks, idxTrack = pSmf->dwTracks; idxTrack--; pTrk++)
  161.     {
  162.         pTrk->pSmf              = pSmf;
  163.         pTrk->tkPosition        = 0;
  164.         pTrk->cbLeft            = pTrk->smti.cbLength;
  165.         pTrk->hpbImage          = pSmf->hpbImage + pTrk->idxTrack;
  166.         pTrk->bRunningStatus    = 0;
  167.         pTrk->fdwTrack          = 0;
  168.     }
  169.     while (SMF_SUCCESS == (smfrc = smfGetNextEvent(pSmf, (EVENT BSTACK *)&event, MAX_TICKS)))
  170.     {
  171.         if (MIDI_META == event.abEvent[0] && 
  172.             MIDI_META_TEMPO == event.abEvent[1])
  173.         {
  174.             if (3 != event.cbParm)
  175.             {
  176.                 return SMF_INVALID_FILE;
  177.             }
  178.             if (pSmf->cTempoMap == pSmf->cTempoMapAlloc)
  179.             {
  180.                 if (NULL != pSmf->hTempoMap)
  181.                 {
  182.                     LocalUnlock(pSmf->hTempoMap);
  183.                 }
  184.                 
  185.                 pSmf->cTempoMapAlloc += C_TEMPO_MAP_CHK;
  186.                 fFirst = FALSE;
  187.                 if (0 == pSmf->cTempoMap)
  188.                 {
  189.                     hLocal = LocalAlloc(LHND, (UINT)(pSmf->cTempoMapAlloc*sizeof(TEMPOMAPENTRY)));
  190.                     fFirst = TRUE;
  191.                 }
  192.                 else
  193.                 {
  194.                     hLocal = LocalReAlloc(pSmf->hTempoMap, (UINT)(pSmf->cTempoMapAlloc*sizeof(TEMPOMAPENTRY)), LHND);
  195.                 }
  196.                 if (NULL == hLocal)
  197.                 {
  198.                     return SMF_NO_MEMORY;
  199.                 }
  200.                 pSmf->pTempoMap = (PTEMPOMAPENTRY)LocalLock(pSmf->hTempoMap = hLocal);
  201.             }
  202.             if (fFirst && pSmf->tkPosition != 0)
  203.             {
  204.                 /* Inserting first event and the absolute time is zero.
  205.                 ** Use defaults of 500,000 uSec/qn from MIDI spec
  206.                 */
  207.                 
  208.                 pTempo = &pSmf->pTempoMap[pSmf->cTempoMap++];
  209.                 pTempo->tkTempo = 0;
  210.                 pTempo->msBase  = 0;
  211.                 pTempo->dwTempo = MIDI_DEFAULT_TEMPO;
  212.                 fFirst = FALSE;
  213.             }
  214.             pTempo = &pSmf->pTempoMap[pSmf->cTempoMap++];
  215.             pTempo->tkTempo = pSmf->tkPosition;
  216.             if (fFirst)
  217.                 pTempo->msBase = 0;
  218.             else
  219.             {
  220.                 /* NOTE: Better not be here unless we're q/n format!
  221.                 */
  222.                 pTempo->msBase = (pTempo-1)->msBase +
  223.                                  muldiv32(pTempo->tkTempo-((pTempo-1)->tkTempo),
  224.                                           (pTempo-1)->dwTempo,
  225.                                           1000L*pSmf->dwTimeDivision);
  226.             }
  227.             pTempo->dwTempo = (((DWORD)event.hpbParm[0])<<16)|
  228.                               (((DWORD)event.hpbParm[1])<<8)|
  229.                               ((DWORD)event.hpbParm[2]);
  230.         }
  231.     }
  232. if (0 == pSmf->cTempoMap)
  233. {
  234. DPF(1, "File contains no tempo map! Insert default tempo.");
  235. hLocal = LocalAlloc(LHND, sizeof(TEMPOMAPENTRY));
  236. if (!hLocal)
  237. return SMF_NO_MEMORY;
  238.         pSmf->pTempoMap = (PTEMPOMAPENTRY)LocalLock(pSmf->hTempoMap = hLocal);
  239. pSmf->cTempoMap = 1;
  240. pSmf->cTempoMapAlloc = 1;
  241. pSmf->pTempoMap->tkTempo = 0;
  242.         pSmf->pTempoMap->msBase  = 0;
  243.         pSmf->pTempoMap->dwTempo = MIDI_DEFAULT_TEMPO;
  244. }
  245.     if (SMF_END_OF_FILE == smfrc || SMF_SUCCESS == smfrc)
  246.     {
  247.         pSmf->tkLength = pSmf->tkPosition;
  248.         smfrc = SMF_SUCCESS;
  249.     }
  250.         
  251.     return smfrc;
  252. }
  253. /******************************************************************************
  254. *
  255. * smfGetNextEvent
  256. *
  257. * Read the next event from the given file.
  258. *
  259. * pSmf                      - File to read the event from.
  260. *
  261. * pEvent                    - Pointer to an event structure which will receive
  262. *                             basic information about the event.
  263. *
  264. * tkMax                     - Tick destination. An attempt to read past this
  265. *                             position in the file will fail.
  266. *
  267. * Returns
  268. *   SMF_SUCCESS The events were successfully read.
  269. *   SMF_END_OF_FILE There are no more events to read in this track.
  270. *   SMF_REACHED_TKMAX No event was read because <p tkMax> was reached.
  271. *   SMF_INVALID_FILE A disk or parse error occured on the file.
  272. *
  273. * This is the lowest level of parsing for a raw MIDI stream. The basic
  274. * information about one event in the file will be returned in pEvent.
  275. *
  276. * Merging data from all tracks into one stream is performed here.
  277. * pEvent->tkDelta will contain the tick delta for the event.
  278. *
  279. * pEvent->abEvent will contain a description of the event.
  280. *  pevent->abEvent[0] will contain
  281. *    F0 or F7 for a System Exclusive message.
  282. *    FF for a MIDI file meta event.
  283. *    The status byte of any other MIDI message. (Running status will
  284. *    be tracked and expanded).
  285. *
  286. * pEvent->cbParm will contain the number of bytes of paramter data
  287. *   which is still in the file behind the event header already read.
  288. *   This data may be read with <f smfGetTrackEventData>. Any unread
  289. *   data will be skipped on the next call to <f smfGetNextTrackEvent>.
  290. *
  291. * Channel messages (0x8? - 0xE?) will always be returned fully in
  292. *   pevent->abEvent.
  293. *
  294. *  Meta events will contain the meta type in pevent->abEvent[1].
  295. *
  296. *  System exclusive events will contain only an 0xF0 or 0xF7 in
  297. *    pevent->abEvent[0].
  298. *
  299. *  The following fields in pTrk are used to maintain state and must
  300. *  be updated if a seek-in-track is performed:
  301. *
  302. *  bRunningStatus contains the last running status message or 0 if
  303. *   there is no valid running status.
  304. *
  305. *  hpbImage is a pointer into the file image of the first byte of
  306. *   the event to follow the event just read.
  307. *
  308. *  dwLeft contains the number of bytes from hpbImage to the end
  309. *   of the track.
  310. *
  311. *
  312. * Get the next due event from all (in-use?) tracks
  313. *
  314. * For all tracks
  315. *  If not end-of-track
  316. *   decode event delta time without advancing through buffer
  317. *   event_absolute_time = track_tick_time + track_event_delta_time
  318. *   relative_time = event_absolute_time - last_stream_time
  319. *   if relative_time is lowest so far
  320. *    save this track as the next to pull from, along with times
  321. *
  322. * If we found a track with a due event
  323. *  Advance track pointer past event, saving ptr to parm data if needed
  324. *  track_tick_time += track_event_delta_time
  325. *  last_stream_time = track_tick_time
  326. * Else
  327. *  Mark and return end_of_file
  328. *
  329. *****************************************************************************/
  330. SMFRESULT FNLOCAL smfGetNextEvent(
  331.     PSMF                    pSmf,
  332.     EVENT BSTACK *          pEvent,
  333.     TICKS                   tkMax)
  334. {
  335.     PTRACK                  pTrk;
  336.     PTRACK                  pTrkFound;
  337.     DWORD                   idxTrack;
  338.     TICKS                   tkEventDelta;
  339.     TICKS                   tkRelTime;
  340.     TICKS                   tkMinRelTime;
  341.     BYTE                    bEvent;
  342.     DWORD                   dwGotTotal;
  343.     DWORD                   dwGot;
  344.     DWORD                   cbEvent;
  345.     assert(pSmf != NULL);
  346.     assert(pEvent != NULL);
  347.     if (pSmf->fdwSMF & SMF_F_EOF)
  348.     {
  349.         return SMF_END_OF_FILE;
  350.     }
  351.     pTrkFound       = NULL;
  352.     tkMinRelTime    = MAX_TICKS;
  353.     
  354.     for (pTrk = pSmf->rTracks, idxTrack = pSmf->dwTracks; idxTrack--; pTrk++)
  355.     {
  356.         if (pTrk->fdwTrack & SMF_TF_EOT)
  357.             continue;
  358.         
  359.         if (!smfGetVDword(pTrk->hpbImage, pTrk->cbLeft, (DWORD BSTACK *)&tkEventDelta))
  360.         {
  361.             DPF(1, "Hit end of track w/o end marker!");
  362.             return SMF_INVALID_FILE;
  363.         }
  364.         tkRelTime = pTrk->tkPosition + tkEventDelta - pSmf->tkPosition;
  365.         if (tkRelTime < tkMinRelTime)
  366.         {
  367.             tkMinRelTime = tkRelTime;
  368.             pTrkFound = pTrk;
  369.         }
  370.     }
  371.     if (!pTrkFound)
  372.     {
  373.         pSmf->fdwSMF |= SMF_F_EOF;
  374.         return SMF_END_OF_FILE;
  375.     }
  376.     pTrk = pTrkFound;
  377.     if (pSmf->tkPosition + tkMinRelTime >= tkMax)
  378.     {
  379.         return SMF_REACHED_TKMAX;
  380.     }
  381.         
  382.     pTrk->hpbImage += (dwGot = smfGetVDword(pTrk->hpbImage, pTrk->cbLeft, (DWORD BSTACK *)&tkEventDelta));
  383.     pTrk->cbLeft   -= dwGot;
  384.     /* We MUST have at least three bytes here (cause we haven't hit
  385.     ** the end-of-track meta yet, which is three bytes long). Checking
  386.     ** against three means we don't have to check how much is left
  387.     ** in the track again for any short event, which is most cases.
  388.     */
  389.     if (pTrk->cbLeft < 3)
  390.     {
  391.         return SMF_INVALID_FILE;
  392.     }
  393.     pTrk->tkPosition += tkEventDelta;
  394.     pEvent->tkDelta = pTrk->tkPosition - pSmf->tkPosition;
  395.     pSmf->tkPosition = pTrk->tkPosition;
  396.     bEvent = *pTrk->hpbImage++;
  397.     
  398.     if (MIDI_MSG > bEvent)
  399.     {
  400.         if (0 == pTrk->bRunningStatus)
  401.         {
  402.             return SMF_INVALID_FILE;
  403.         }
  404.         dwGotTotal = 1;
  405.         pEvent->abEvent[0] = pTrk->bRunningStatus;
  406.         pEvent->abEvent[1] = bEvent;
  407.         if (3 == grbChanMsgLen[(pTrk->bRunningStatus >> 4) & 0x0F])
  408.         {
  409.             pEvent->abEvent[2] = *pTrk->hpbImage++;
  410.             dwGotTotal++;
  411.         }
  412.     }
  413.     else if (MIDI_SYSEX > bEvent)
  414.     {
  415.         pTrk->bRunningStatus = bEvent;
  416.         
  417.         dwGotTotal = 2;
  418.         pEvent->abEvent[0] = bEvent;
  419.         pEvent->abEvent[1] = *pTrk->hpbImage++;
  420.         if (3 == grbChanMsgLen[(bEvent >> 4) & 0x0F])
  421.         {
  422.             pEvent->abEvent[2] = *pTrk->hpbImage++;
  423.             dwGotTotal++;
  424.         }
  425.     }
  426.     else
  427.     {
  428.         pTrk->bRunningStatus = 0;
  429.         if (MIDI_META == bEvent)
  430.         {
  431.             pEvent->abEvent[0] = MIDI_META;
  432.             if (MIDI_META_EOT == (pEvent->abEvent[1] = *pTrk->hpbImage++))
  433.             {
  434.                 pTrk->fdwTrack |= SMF_TF_EOT;
  435.             }
  436.             dwGotTotal = 2;
  437.         }
  438.         else if (MIDI_SYSEX == bEvent || MIDI_SYSEXEND == bEvent)
  439.         {
  440.             pEvent->abEvent[0] = bEvent;
  441.             dwGotTotal = 1;
  442.         }
  443.         else
  444.         {
  445.             return SMF_INVALID_FILE;
  446.         }
  447.         
  448.         if (0 == (dwGot = smfGetVDword(pTrk->hpbImage, pTrk->cbLeft - 2, (DWORD BSTACK *)&cbEvent)))
  449.         {
  450.             return SMF_INVALID_FILE;
  451.         }
  452.         pTrk->hpbImage  += dwGot;
  453.         dwGotTotal      += dwGot;
  454.         if (dwGotTotal + cbEvent > pTrk->cbLeft)
  455.         {
  456.             return SMF_INVALID_FILE;
  457.         }
  458.         pEvent->cbParm  = cbEvent;
  459.         pEvent->hpbParm = pTrk->hpbImage;
  460.         pTrk->hpbImage += cbEvent;
  461.         dwGotTotal     += cbEvent;
  462.     }
  463.     assert(pTrk->cbLeft >= dwGotTotal);
  464.     pTrk->cbLeft -= dwGotTotal;
  465.     return SMF_SUCCESS;
  466. }
  467. /******************************************************************************
  468. *
  469. * smfGetVDword
  470. *
  471. * Reads a variable length DWORD from the given file.
  472. *
  473. * hpbImage                  - Pointer to the first byte of the VDWORD.
  474. *
  475. * dwLeft                    - Bytes left in image
  476. *
  477. * pDw                       - Pointer to a DWORD to store the result in.
  478. *                             track.
  479. *
  480. * Returns the number of bytes consumed from the stream.
  481. *
  482. * A variable length DWORD stored in a MIDI file contains one or more
  483. * bytes. Each byte except the last has the high bit set; only the
  484. * low 7 bits are significant.
  485. *  
  486. *****************************************************************************/
  487. DWORD FNLOCAL smfGetVDword(
  488.     HPBYTE                  hpbImage,                                
  489.     DWORD                   dwLeft,                               
  490.     DWORD BSTACK *          pDw)
  491. {
  492.     BYTE                    b;
  493.     DWORD                   dwUsed  = 0;
  494.     assert(hpbImage != NULL);
  495.     assert(pDw != NULL);
  496.     
  497.     *pDw = 0;
  498.     do
  499.     {
  500.         if (!dwLeft)
  501.         {
  502.             return 0;
  503.         }
  504.         b = *hpbImage++;
  505.         dwLeft--;
  506.         dwUsed++;
  507.         
  508.         *pDw = (*pDw << 7) | (b & 0x7F);
  509.     } while (b&0x80);
  510.     return dwUsed;
  511. }