home *** CD-ROM | disk | FTP | other *** search
/ DP Tool Club 19 / CD_ASCQ_19_010295.iso / dos / prg / midas / mod.asm < prev    next >
Assembly Source File  |  1994-08-06  |  66KB  |  3,024 lines

  1. ;*    MOD.ASM
  2. ;*
  3. ;* Protracker Module Player, v1.13
  4. ;*
  5. ;* Copyright 1994 Petteri Kangaslampi and Jarno Paananen
  6. ;*
  7. ;* This file is part of the MIDAS Sound System, and may only be
  8. ;* used, modified and distributed under the terms of the MIDAS
  9. ;* Sound System license, LICENSE.TXT. By continuing to use,
  10. ;* modify or distribute this file you indicate that you have
  11. ;* read the license and understand and accept it fully.
  12. ;*
  13.  
  14.  
  15. IDEAL
  16. P386
  17. JUMPS
  18.  
  19. INCLUDE "lang.inc"
  20. INCLUDE "errors.inc"
  21. INCLUDE "mglobals.inc"
  22. INCLUDE "mod.inc"
  23. INCLUDE "mplayer.inc"
  24. INCLUDE "sdevice.inc"
  25. INCLUDE "ems.inc"
  26. INCLUDE "timer.inc"
  27.  
  28.  
  29. DATASEG
  30.  
  31.  
  32. ;*
  33. ;* MOD player data structures
  34. ;*
  35.  
  36. module        DD    ?        ; pointer to module structure
  37. sdevice     DD    ?        ; current Sound Device
  38.  
  39. playCount    DB    ?        ; player speed counter
  40. speed        DB    ?        ; playing speed, default is 6
  41. tempo        DB    ?        ; playing BPM tempo
  42. masterVolume    DB    ?        ; master volume (0-64)
  43. pbFlag        DB    ?        ; pattern break flag
  44. loopCnt     DB    ?        ; song loop counter
  45.  
  46. position    DW    ?        ; position in song
  47. row        DW    ?        ; row in pattern
  48. songLength    DW    ?        ; song length (number of positions)
  49. numChans    DW    ?        ; number of channels
  50. firstSDChan    DW    ?        ; first Sound Device channel number
  51. chan        DW    ?        ; current channel number
  52. loopRow     DW    ?        ; pattern loop row number
  53. loopFlag    DB    ?        ; pattern loop flag
  54. loopCount    DB    ?        ; pattern loop counter
  55. delayCount    DB    ?        ; pattern delay count
  56. delayFlag    DB    ?        ; pattern delay flag
  57. skipFlag    DW    ?        ; 1 if some rows should be skipped
  58.                     ; next time song is played. Set by
  59.                     ; pattern loop and break commands.
  60.  
  61. setFrame    DW    ?        ; 1 if "set frame" (song is played),
  62.                     ; 0 if not
  63. rows        DW    ?        ; saved row number for GetInformation
  64. poss        DW    ?        ; saved position
  65. pats        DW    ?        ; saved pattern number
  66.  
  67. modMemPtr    DD    ?        ; temporary pointer used by some
  68.                     ; functions
  69.  
  70.  
  71. channels    modChannel  MPCHANNELS DUP (?)        ; channel structures
  72.  
  73.  
  74.  
  75. IDATASEG
  76.  
  77.  
  78.  
  79. ;/***************************************************************************\
  80. ;*     Protracker Module Player structure:
  81. ;\***************************************************************************/
  82.  
  83. mpMOD ModulePlayer    < \
  84.     mpUnInitialized, \
  85.     5000, \
  86.     far ptr modIdentify, \
  87.     far ptr modInit, \
  88.     far ptr modClose, \
  89.     far ptr modLoadModule, \
  90.     far ptr modFreeModule, \
  91.     far ptr modPlayModule, \
  92.     far ptr modStopModule, \
  93.     far ptr modSetInterrupt, \
  94.     far ptr modRemoveInterrupt, \
  95.     far ptr modPlay, \
  96.     far ptr modSetPosition, \
  97.     far ptr modGetInformation,\
  98.     far ptr modSetMasterVolume >
  99.  
  100.  
  101.  
  102.     ; sine table for vibrato:
  103. vibratoTable    DB    0,24,49,74,97,120,141,161
  104.         DB    180,197,212,224,235,244,250,253
  105.         DB    255,253,250,244,235,224,212,197
  106.         DB    180,161,141,120,97,74,49,24
  107.  
  108.     ; 100% Protracker compatible period table:
  109. LABEL    Periods     WORD
  110. ; Tuning 0, Normal
  111.     DW    856,808,762,720,678,640,604,570,538,508,480,453
  112.     DW    428,404,381,360,339,320,302,285,269,254,240,226
  113.     DW    214,202,190,180,170,160,151,143,135,127,120,113
  114.  
  115. ; Tuning 1
  116.     DW    850,802,757,715,674,637,601,567,535,505,477,450
  117.     DW    425,401,379,357,337,318,300,284,268,253,239,225
  118.     DW    213,201,189,179,169,159,150,142,134,126,119,113
  119.  
  120. ; Tuning 2
  121.     DW    844,796,752,709,670,632,597,563,532,502,474,447
  122.     DW    422,398,376,355,335,316,298,282,266,251,237,224
  123.     DW    211,199,188,177,167,158,149,141,133,125,118,112
  124.  
  125. ; Tuning 3
  126.     DW    838,791,746,704,665,628,592,559,528,498,470,444
  127.     DW    419,395,373,352,332,314,296,280,264,249,235,222
  128.     DW    209,198,187,176,166,157,148,140,132,125,118,111
  129.  
  130. ; Tuning 4
  131.     DW    832,785,741,699,660,623,588,555,524,495,467,441
  132.     DW    416,392,370,350,330,312,294,278,262,247,233,220
  133.     DW    208,196,185,175,165,156,147,139,131,124,117,110
  134.  
  135. ; Tuning 5
  136.     DW    826,779,736,694,655,619,584,551,520,491,463,437
  137.     DW    413,390,368,347,328,309,292,276,260,245,232,219
  138.     DW    206,195,184,174,164,155,146,138,130,123,116,109
  139.  
  140. ; Tuning 6
  141.     DW    820,774,730,689,651,614,580,547,516,487,460,434
  142.     DW    410,387,365,345,325,307,290,274,258,244,230,217
  143.     DW    205,193,183,172,163,154,145,137,129,122,115,109
  144.  
  145. ; Tuning 7
  146.     DW    814,768,725,684,646,610,575,543,513,484,457,431
  147.     DW    407,384,363,342,323,305,288,272,256,242,228,216
  148.     DW    204,192,181,171,161,152,144,136,128,121,114,108
  149.  
  150. ; Tuning -8
  151.     DW    907,856,808,762,720,678,640,604,570,538,508,480
  152.     DW    453,428,404,381,360,339,320,302,285,269,254,240
  153.     DW    226,214,202,190,180,170,160,151,143,135,127,120
  154.  
  155. ; Tuning -7
  156.     DW    900,850,802,757,715,675,636,601,567,535,505,477
  157.     DW    450,425,401,379,357,337,318,300,284,268,253,238
  158.     DW    225,212,200,189,179,169,159,150,142,134,126,119
  159.  
  160. ; Tuning -6
  161.     DW    894,844,796,752,709,670,632,597,563,532,502,474
  162.     DW    447,422,398,376,355,335,316,298,282,266,251,237
  163.     DW    223,211,199,188,177,167,158,149,141,133,125,118
  164.  
  165. ; Tuning -5
  166.     DW    887,838,791,746,704,665,628,592,559,528,498,470
  167.     DW    444,419,395,373,352,332,314,296,280,264,249,235
  168.     DW    222,209,198,187,176,166,157,148,140,132,125,118
  169.  
  170. ; Tuning -4
  171.     DW    881,832,785,741,699,660,623,588,555,524,494,467
  172.     DW    441,416,392,370,350,330,312,294,278,262,247,233
  173.     DW    220,208,196,185,175,165,156,147,139,131,123,117
  174.  
  175. ; Tuning -3
  176.     DW    875,826,779,736,694,655,619,584,551,520,491,463
  177.     DW    437,413,390,368,347,328,309,292,276,260,245,232
  178.     DW    219,206,195,184,174,164,155,146,138,130,123,116
  179.  
  180. ; Tuning -2
  181.     DW    868,820,774,730,689,651,614,580,547,516,487,460
  182.     DW    434,410,387,365,345,325,307,290,274,258,244,230
  183.     DW    217,205,193,183,172,163,154,145,137,129,122,115
  184.  
  185. ; Tuning -1
  186.     DW    862,814,768,725,684,646,610,575,543,513,484,457
  187.     DW    431,407,384,363,342,323,305,288,272,256,242,228
  188.     DW    216,203,192,181,171,161,152,144,136,128,121,114
  189.  
  190.  
  191.  
  192.     ; command name pointers:
  193. LABEL    cmdNames    DWORD
  194.     DD    far ptr strArpeggio
  195.     DD    far ptr strSlideUp
  196.     DD    far ptr strSlideDown
  197.     DD    far ptr strTonePortamento
  198.     DD    far ptr strVibrato
  199.     DD    far ptr strTPortVSlide
  200.     DD    far ptr strVibVSlide
  201.     DD    far ptr strTremolo
  202.     DD    far ptr strSetPanning
  203.     DD    far ptr strSampleOffs
  204.     DD    far ptr strVolSlide
  205.     DD    far ptr strPosJump
  206.     DD    far ptr strSetVol
  207.     DD    far ptr strPattBreak
  208.     DD    far ptr strNoCmd
  209.     DD    far ptr strSetSpeed
  210.  
  211.     ; E-command name pointers:
  212. LABEL    ecmdNames    DWORD
  213.     DD    far ptr strSetFilter
  214.     DD    far ptr strFineSldUp
  215.     DD    far ptr strFineSldDown
  216.     DD    far ptr strGlissCtrl
  217.     DD    far ptr strSetVibWform
  218.     DD    far ptr strSetFinetune
  219.     DD    far ptr strPatternLoop
  220.     DD    far ptr strSetTremWform
  221.     DD    far ptr strSetPanning
  222.     DD    far ptr strRetrig
  223.     DD    far ptr strFineVSldUp
  224.     DD    far ptr strFineVSldDown
  225.     DD    far ptr strNoteCut
  226.     DD    far ptr strNoteDelay
  227.     DD    far ptr strPattDelay
  228.     DD    far ptr strInvLoop
  229.  
  230.  
  231. strNoCmd    DB    0
  232. strSlideUp    DB    "Slide Up",0
  233. strSlideDown    DB    "Slide Down",0
  234. strTonePortamento DB    "Tone Porta",0
  235. strVibrato    DB    "Vibrato",0
  236. strTPortVSlide    DB    "TPrt+VolSld",0
  237. strVibVSlide    DB    "Vib+VolSld",0
  238. strTremolo    DB    "Tremolo",0
  239. strSetPanning    DB    "Set Panning",0
  240. strSampleOffs    DB    "Sample Offs",0
  241. strArpeggio    DB    "Arpeggio",0
  242. strVolSlide    DB    "VolumeSlide",0
  243. strPosJump    DB    "Pos. Jump",0
  244. strPattBreak    DB    "Patt. Break",0
  245. strSetSpeed    DB    "Set Speed",0
  246. strSetVol    DB    "Set Volume",0
  247.  
  248. strSetFilter    DB    "Set Filter",0
  249. strFineSldUp    DB    "FineSld Up",0
  250. strFineSldDown    DB    "FineSld Dwn",0
  251. strGlissCtrl    DB    "Gliss. Ctrl",0
  252. strSetVibWform    DB    "Vib.Wavefrm",0
  253. strSetFinetune    DB    "SetFinetune",0
  254. strPatternLoop    DB    "Patt.Loop",0
  255. strSetTremWform DB    "Tre.Wavefrm",0
  256. strRetrig    DB    "Retrig Note",0
  257. strFineVSldUp    DB    "FineVSld Up",0
  258. strFineVSldDown DB    "FineVSldDwn",0
  259. strNoteCut    DB    "Note Cut",0
  260. strNoteDelay    DB    "Note Delay",0
  261. strPattDelay    DB    "Patt.Delay",0
  262. strInvLoop    DB    "Invert Loop",0
  263.  
  264.  
  265.  
  266.  
  267. CODESEG
  268.  
  269. ;/***************************************************************************\
  270. ;*
  271. ;* Function:    int modIdentify(uchar *header, int *recognized);
  272. ;*
  273. ;* Description: Checks if the header is a Protracker module header
  274. ;*
  275. ;* Input:    uchar *headeer        pointer to header, length MPHDRSIZE
  276. ;*        int *recognized     pointer to result variable
  277. ;*
  278. ;* Returns:    MIDAS error code.
  279. ;*        *recognized set to 1 if header is a Protracker module header,
  280. ;*        0 if not
  281. ;*
  282. ;\***************************************************************************/
  283.  
  284. PROC    modIdentify    FAR    header : dword, recognized : dword
  285.  
  286.     les    bx,[header]
  287.  
  288.     mov    eax,[dword es:bx+modHeader.sign]     ; eax = header signature
  289.  
  290.     ; check if the signature is valid:
  291.     cmp    eax,".K.M"
  292.     je    @@1
  293.     cmp    eax,"!K!M"
  294.     je    @@1
  295.     cmp    eax,"4TLF"
  296.     je    @@1
  297.     cmp    eax,"ATCO"
  298.     je    @@1
  299.  
  300.     mov    ebx,eax
  301.         shr     ebx,8                           ; xCHN - signature
  302.         cmp     ebx,"NHC"
  303.     je    @@1
  304.  
  305.     mov    ebx,eax
  306.         shr     ebx,16
  307.         cmp     ebx,"HC"                        ; xxCH-sign
  308.     je    @@1
  309.  
  310.         and     eax,0FFFFFFh
  311.     cmp    eax,"ZDT"                       ; TDZx-sign
  312.     je    @@1
  313.  
  314.  
  315. ; MTM-SUPPORT IS GONE FOR NOW!
  316.  
  317. ;     mov     eax,[es:si]
  318. ;     and     eax,0ffffffh
  319. ;     cmp     eax,"MTM"
  320. ;     je     @@1
  321.  
  322.     ; not a Protracker module
  323.     xor    ax,ax
  324.     jmp    @@iddone
  325.  
  326. @@1:    mov    ax,1
  327.  
  328. @@iddone:
  329.     les    bx,[recognized]     ; store result in *recognized
  330.     mov    [es:bx],ax
  331.  
  332.     xor    ax,ax            ; always successful
  333.     ret
  334. ENDP
  335.  
  336.  
  337.  
  338.  
  339. ;/***************************************************************************\
  340. ;*
  341. ;* Function:    int modInit(SoundDevice *SD);
  342. ;*
  343. ;* Description: Initializes Protracker Module Player
  344. ;*
  345. ;* Input:    SoundDevice *SD     pointer to Sound Device to be used
  346. ;*                    for playing
  347. ;*
  348. ;* Returns:    MIDAS error code
  349. ;*
  350. ;\***************************************************************************/
  351.  
  352. PROC    modInit     FAR    SDev : dword
  353.  
  354.     mov    eax,[SDev]        ; store Sound Device pointer in
  355.     mov    [sdevice],eax        ; sdevice
  356.  
  357.     mov    [mpMOD.status],mpInitialized    ; Module Player is initialized
  358.  
  359.     xor    ax,ax            ; success
  360.  
  361.     ret
  362. ENDP
  363.  
  364.  
  365.  
  366. ;/***************************************************************************\
  367. ;*
  368. ;* Function:    int modClose(void);
  369. ;*
  370. ;* Description: Uninitializes the Protracker Module Player
  371. ;*
  372. ;* Returns:    MIDAS error code
  373. ;*
  374. ;\***************************************************************************/
  375.  
  376. PROC    modClose FAR
  377.  
  378.     mov    [mpMOD.status],mpUnInitialized
  379.  
  380.     xor    ax,ax            ; success
  381.     ret
  382. ENDP
  383.  
  384.  
  385.  
  386. ;/***************************************************************************\
  387. ;*
  388. ;* Function:    int modPlayModule(mpModule *module, ushort firstSDChannel,
  389. ;*            ushort numChannels, ushort loopStart, ushort loopEnd);
  390. ;*
  391. ;*
  392. ;* Description: Starts playing a module
  393. ;*
  394. ;* Input:    mpModule *module    pointer to the module to be played
  395. ;*        ushort firstSDChannel    first Sound Device channel to use
  396. ;*        ushort numChannels    number of channels
  397. ;*        ushort loopStart    song loop start (0 = beginning)
  398. ;*        ushort loopEnd        song loop end (use 65535 for whole
  399. ;*                    song if length is unknown)
  400. ;*
  401. ;* Returns:    MIDAS error code
  402. ;*
  403. ;\***************************************************************************/
  404.  
  405. PROC    modPlayModule    FAR    mmod : dword, firstSDChannel : word, \
  406.                 numChannels : word, loopStart : word, \
  407.                 loopEnd : word
  408. USES    si,di
  409.  
  410.     mov    eax,[mmod]        ; store module pointer in module
  411.     mov    [module],eax
  412.     les    si,[module]        ; point es:si to module structure
  413.  
  414.     mov    ax,[es:si+mpModule.songLength]    ; get song length from module
  415.     mov    [songLength],ax         ; and store it
  416.  
  417.     mov    ax,[firstSDChannel]    ; store first SD channel number
  418.     mov    [firstSDChan],ax
  419.     mov    ax,[numChannels]    ; store number of channels
  420.     mov    [numChans],ax
  421.  
  422.     ; initialize player internal variables:
  423.     mov    [position],0
  424.     mov    [row],0
  425.     mov    [masterVolume],64
  426.     mov    [playCount],0
  427.     mov    [speed],6        ; initial speed is 6
  428.     mov    [tempo],125        ; initial BPM tempo is 125
  429.     mov    [pbFlag],0
  430.     mov    [loopRow],0
  431.     mov    [loopFlag],0
  432.     mov    [delayCount],0
  433.     mov    [delayFlag],0
  434.     mov    [skipFlag],0
  435.     mov    [loopCnt],0
  436.  
  437.     mov    [mpMOD.updRate],5000    ; set update rate to 50Hz
  438.     lgs    di,[sdevice]
  439.     call    [gs:di+SoundDevice.SetUpdRate] LANG, 5000
  440.     test    ax,ax
  441.     jnz    @@err
  442.  
  443.  
  444.     ; Set default panning values for all channels:
  445.  
  446.     mov    [chan],0
  447.  
  448.     ; set initial panning values to channels:
  449. @@panloop:
  450.     mov    bx,[chan]
  451.     movsx    ax,[es:si+bx+mpModule.chanSettings]
  452.     add    bx,[firstSDChan]        ; bx = Sound Device channel
  453.                         ; number
  454.  
  455.     ; set Sound Device panning:
  456.     push    es gs
  457.     call    [gs:di+SoundDevice.SetPanning] LANG, bx, ax
  458.     pop    gs es
  459.     test    ax,ax
  460.     jnz    @@err
  461.  
  462.     inc    [chan]                ; next channel
  463.     mov    ax,[chan]
  464.     cmp    ax,[numChans]
  465.     jb    @@panloop
  466.  
  467.     ; clear player channel structures:
  468.     mov    ax,ds
  469.     mov    es,ax
  470.     mov    di,offset channels
  471.     mov    cx,MPCHANNELS * SIZE modChannel
  472.     xor    al,al
  473.     cld
  474.     rep    stosb
  475.  
  476.     mov    [mpMOD.status],mpPlaying
  477.  
  478.     xor    ax,ax            ; success
  479.     jmp    @@done
  480.  
  481. @@err:
  482.     ERROR    ID_modPlayModule
  483.  
  484. @@done:
  485.     ret
  486. ENDP
  487.  
  488.  
  489.  
  490.  
  491. ;/***************************************************************************\
  492. ;*
  493. ;* Function:    int modStopModule(void);
  494. ;*
  495. ;* Description: Stops playing a module
  496. ;*
  497. ;* Returns:    MIDAS error code
  498. ;*
  499. ;\***************************************************************************/
  500.  
  501. PROC    modStopModule    FAR
  502.  
  503.     mov    [module],0        ; point module to NULL for safety
  504.     mov    [mpMOD.status],mpStopped
  505.  
  506.     xor    ax,ax            ; success
  507.     ret
  508. ENDP
  509.  
  510.  
  511.  
  512.  
  513. ;/***************************************************************************\
  514. ;*
  515. ;* Function:    int modSetInterrupt(void);
  516. ;*
  517. ;* Description: Starts playing the module using TempoTimer
  518. ;*
  519. ;* Returns:    MIDAS error code
  520. ;*
  521. ;\***************************************************************************/
  522.  
  523. PROC    modSetInterrupt     FAR
  524.  
  525.     ; start playing with the TempoTimer:
  526.     call    tmrPlay LANG, seg modPlay offset modPlay, [sdevice]
  527.     test    ax,ax
  528.     jnz    @@err
  529.  
  530.     movzx    ax,[tempo]
  531.     mov    bx,40            ; BPM * 40 = playing rate in 100*Hz
  532.     mul    bx
  533.     call    tmrSetUpdRate LANG, ax    ; set timer update rate
  534.     test    ax,ax
  535.     jnz    @@err
  536.  
  537.     xor    ax,ax            ; success
  538.     jmp    @@done
  539.  
  540. @@err:
  541.     ERROR    ID_modSetInterrupt
  542.  
  543. @@done:
  544.     ret
  545. ENDP
  546.  
  547.  
  548.  
  549.  
  550. ;/***************************************************************************\
  551. ;*
  552. ;* Function:    int modRemoveInterrupt(void);
  553. ;*
  554. ;* Description: Stops playing with the TempoTimer
  555. ;*
  556. ;* Returns:    MIDAS error code
  557. ;*
  558. ;\***************************************************************************/
  559.  
  560. PROC    modRemoveInterrupt    FAR
  561.  
  562.     call    tmrStop LANG        ; stop playing the module with timer
  563.     test    ax,ax
  564.     jnz    @@err
  565.  
  566.     xor    ax,ax            ; success
  567.     jmp    @@done
  568.  
  569. @@err:
  570.     ERROR    ID_modRemoveInterrupt
  571.  
  572. @@done:
  573.     ret
  574. ENDP
  575.  
  576.  
  577.  
  578.  
  579.  
  580.  
  581. ;/***************************************************************************\
  582. ;*
  583. ;* Function:    int modPlay(void);
  584. ;*
  585. ;* Description: Plays one "frame" of the module. Usually called from
  586. ;*        the timer.
  587. ;*
  588. ;* Returns:    MIDAS error code
  589. ;*
  590. ;\***************************************************************************/
  591.  
  592. PROC    modPlay     FAR
  593. USES    di, si
  594.  
  595.     inc    [playCount]        ; increment player counter
  596.     mov    al,[speed]        ; if player counter is equal to the
  597.     cmp    [playCount],al        ; speed, it's time to play the song
  598.     jne    @@noplay        ; data.
  599.  
  600.     call    modPlaySong        ; play one row of the song data
  601.     test    ax,ax
  602.     jnz    @@err
  603.     jmp    @@ok
  604.  
  605. @@noplay:
  606.     ; Song data is not played - just process the continuous commands
  607.     call    modRunCommands
  608.     test    ax,ax
  609.     jnz    @@err
  610.  
  611. @@ok:    xor    ax,ax            ; success
  612.     jmp    @@done
  613.  
  614. @@err:
  615.     ERROR    ID_modPlay
  616.  
  617. @@done:
  618.     ret
  619. ENDP
  620.  
  621.  
  622.  
  623. ;/***************************************************************************\
  624. ;*
  625. ;* Function:    modRunCommands
  626. ;*
  627. ;* Description: Processes the continuous commands
  628. ;*
  629. ;* Returns:    MIDAS error code in ax
  630. ;*
  631. ;\***************************************************************************/
  632.  
  633. PROC NOLANGUAGE modRunCommands    NEAR
  634.  
  635.     mov    [chan],0        ; set channel number to 0
  636.     mov    di,offset channels    ; point ds:di to channel structures
  637.     lgs    si,[sdevice]        ; point gs:si to Sound Device
  638.  
  639. @@chanloop:
  640.     movzx    bx,[di+modChannel.cmd]    ; bx = command for this channel
  641.     shl    bx,1
  642.     movzx    ax,[di+modChannel.info] ; ax = command infobyte
  643.     call    [contCmd+bx]        ; process the command
  644.     test    ax,ax            ; error?
  645.     jnz    @@done            ; if yes, pass it on
  646.  
  647.     add    di,size modChannel    ; point ds:di to next channel
  648.  
  649.     mov    ax,[chan]
  650.     inc    ax            ; next channel number
  651.     cmp    ax,[numChans]
  652.     jae    @@no
  653.     mov    [chan],ax
  654.     jmp    @@chanloop
  655.  
  656. @@no:
  657.     call    modUpdBars        ; update "fake" volume bars
  658.  
  659.     ; pass possible error code on
  660. @@done:
  661.     ret
  662. ENDP
  663.  
  664.  
  665.  
  666.  
  667. ;/***************************************************************************\
  668. ;*
  669. ;* Function:    modPlaySong
  670. ;*
  671. ;* Description: Plays one row of song data
  672. ;*
  673. ;* Returns:    MIDAS error code in ax
  674. ;*
  675. ;\***************************************************************************/
  676.  
  677.  
  678. PROC    modPlaySong    NEAR
  679. LOCAL    trackNum : word
  680.  
  681.     mov    [playCount],0        ; reset player counter
  682.  
  683.     cmp    [delayCount],0
  684.     je    @@nodelay
  685.  
  686.     ; pattern delay counter is non-zero. Decrement it and process
  687.     ; continuous commands.
  688.  
  689.     dec    [delayCount]
  690.     call    modRunCommands
  691.     ; pass possible error code on
  692.     jmp    @@done
  693.  
  694.  
  695. @@nodelay:
  696.     mov    [delayFlag],0        ; no pattern delay active
  697.     cmp    [skipFlag],0        ; should some rows be skipped?
  698.     je    @@noskip
  699.  
  700.     call    modSkipRows
  701.     test    ax,ax            ; error?
  702.     jnz    @@done            ; if yes, pass error code on
  703.  
  704. @@noskip:
  705.     les    si,[module]        ; point es:si to module structure
  706.     mov    bx,[position]
  707.  
  708.     lgs    di,[es:si+mpModule.orders]    ; point gs:di to orders
  709.     movzx    bx,[byte gs:di+bx]        ; bx = pattern number
  710.  
  711.     mov    cx,[numChans]        ; cx = number of channels
  712.     imul    bx,cx            ; bx = first track number
  713.     mov    [trackNum],bx        ; store track number
  714.  
  715.     mov    di,offset channels    ; point ds:di to channel structures
  716.  
  717.     ; process pattern data for all channels:
  718.  
  719. @@dataloop:
  720.     les    si,[module]        ; point es:si to module structure
  721.     mov    al,[di+modChannel.comp] ; al = compression info for current ch
  722.     test    al,40h            ; if bit 6 of compression info is 1,
  723.     jz    @@empty         ; rows of same data follow
  724.  
  725.  
  726.     and    al,3Fh            ; al = number of rows of same data
  727.     jz    @@nocomp        ; if zero, go to next row
  728.     dec    [di+modChannel.comp]    ; decrease compression counter
  729.     jmp    @@skip            ; do not process pattern data
  730.  
  731. @@empty:
  732.     and    al,3Fh            ; al = number of empty rows
  733.     jz    @@nocomp        ; if zero, go to next row
  734.     dec    [di+modChannel.comp]    ; decrease compression counter
  735.  
  736.     mov    [di+modChannel.note],0    ; no new note
  737.     mov    [di+modChannel.inst],0    ; no new instrument
  738.     mov    [di+modChannel.cmd],0    ; no new command
  739.     mov    [di+modChannel.info],0    ; no new infobyte
  740.     jmp    @@skip            ; do not process pattern data
  741.  
  742.  
  743. @@nocomp:
  744.     ; No compression - process next row of pattern data
  745.     push    di
  746.     mov    bx,[trackNum]
  747.     lgs    di,[es:si+mpModule.pattEMS] ; point gs:di to track EMS flags
  748.     mov    al,[byte gs:di+bx]         ; al = EMS flag
  749.  
  750.     lgs    di,[es:si+mpModule.patterns]  ; point gs:di to track pointers
  751.     shl    bx,2
  752.     mov    edx,[gs:di+bx]        ; edx = pointer to track memory
  753.  
  754.     pop    di
  755.  
  756.     cmp    al,0            ; is EMS flag 0?
  757.     je    @@noEMS         ; if so, pattern is not in EMS
  758.  
  759.  
  760.     ; map pattern data to conventional memory:
  761.     push    cx
  762.     call    emsMap LANG, edx, seg modMemPtr offset modMemPtr
  763.     pop    cx
  764.     test    ax,ax            ; error?
  765.     jnz    @@done            ; if so, pass it on
  766.  
  767.     les    si,[modMemPtr]        ; point es:si to track in
  768.     jmp    @@dataok        ; conventional memory
  769.  
  770.  
  771. @@noEMS:
  772.     mov    si,dx
  773.     shr    edx,16            ; point es:si to track data
  774.     mov    es,dx
  775.  
  776. @@dataok:
  777.     add    si,[di+modChannel.playoff]    ; add playing position to si
  778.  
  779.     ; es:si now points to current row of track data
  780.  
  781.     mov    dl,[es:si]        ; dl = first data byte
  782.     inc    si
  783.  
  784.     mov    al,dl
  785.     and    al,7Fh
  786.     cmp    al,01111000b        ; if data = x1111000b, the row is
  787.     je    @@emptyrow        ; empty
  788.  
  789.     and    al,01111000b        ; if data = x1110xxxb, there is a
  790.     cmp    al,01110000b        ; note and an instrument
  791.     je    @@noteInst
  792.  
  793.     and    al,01110000b        ; if data = x110xxxxb, there is a
  794.     cmp    al,01100000b        ; command
  795.     je    @@command
  796.  
  797.  
  798.     ; there is a note, instrument and command:
  799.     mov    al,dl
  800.     and    al,7Eh            ; al = note number
  801.     shr    al,1
  802.     mov    [di+modChannel.note],al
  803.  
  804.     mov    ah,dl            ; ah = first data byte
  805.     mov    al,[es:si]        ; al = next data byte
  806.     inc    si
  807.  
  808.     mov    dh,al
  809.         and     dh,0Fh                  ; dh = command number
  810.     mov    [di+modChannel.cmd],dh
  811.  
  812.     shr    ax,4
  813.     and    ax,1Fh            ; ax = instrument number
  814.     mov    [di+modChannel.inst],al
  815.  
  816.     mov    al,[es:si]
  817.     inc    si            ; al = next data byte = command
  818.     mov    [di+modChannel.info],al ; infobyte
  819.  
  820.     add    [di+modChannel.playoff],3    ; 3 bytes played
  821.  
  822.     jmp    @@checkcomp        ; check for compression info
  823.  
  824.  
  825.     ; there is only a command:
  826. @@command:
  827.     mov    al,dl
  828.     and    al,0Fh            ; al = command number
  829.     mov    [di+modChannel.cmd],al
  830.  
  831.     mov    al,[es:si]
  832.     inc    si            ; al = next data byte = command
  833.     mov    [di+modChannel.info],al ; infobyte
  834.  
  835.     mov    [di+modChannel.note],0    ; there is no new note or
  836.     mov    [di+modChannel.inst],0    ; instrument
  837.  
  838.     add    [di+modChannel.playoff],2
  839.  
  840.     jmp    @@checkcomp
  841.  
  842.  
  843.     ; there is a note and an instrument:
  844.  
  845. @@noteInst:
  846.     mov    ah,dl            ; ah = first data byte
  847.     mov    al,[es:si]        ; al = next
  848.     inc    si
  849.  
  850.     mov    dh,al            ; dh = second data byte
  851.     and    dh,1Fh            ; dh = instrument number
  852.     mov    [di+modChannel.inst],dh
  853.  
  854.     shr    ax,5
  855.     and    ax,3Fh            ; al = note number
  856.     mov    [di+modChannel.note],al
  857.  
  858.     mov    [di+modChannel.cmd],0    ; no command
  859.     mov    [di+modChannel.info],0    ; no infobyte
  860.  
  861.     add    [di+modChannel.playoff],2
  862.  
  863.     jmp    @@checkcomp
  864.  
  865.  
  866.     ; empty row:
  867.  
  868. @@emptyrow:
  869.     mov    [di+modChannel.note],0    ; no new note
  870.     mov    [di+modChannel.inst],0    ; no new instrument
  871.     mov    [di+modChannel.cmd],0    ; no new command
  872.     mov    [di+modChannel.info],0    ; no new infobyte
  873.     inc    [di+modChannel.playoff]
  874.  
  875. @@checkcomp:
  876.     test    dl,80h            ; if bit 7 of first data byte is 1,
  877.     jz    @@skip
  878.     mov    al,[es:si]        ; a compression info byte follows
  879.     inc    si
  880.     mov    [di+modChannel.comp],al ; store it
  881.     inc    [di+modChannel.playoff] ; one more byte played
  882.  
  883. @@skip:
  884.     inc    [trackNum]        ; next channel
  885.     add    di,SIZE modChannel    ; point ds:di to next channel
  886.     loop    @@dataloop
  887.  
  888.     les    si,[module]
  889.     call    modSave         ; save values for GetInformation()
  890.  
  891.  
  892.     ; Process possible new values on all channels:
  893.  
  894.     mov    [chan],0        ; channel number = 0
  895.     mov    di,offset channels    ; point ds:di to channel structures
  896.     lgs    si,[sdevice]        ; point gs:si to Sound Device
  897.  
  898.  
  899. @@chanloop:
  900.     xor    bx,bx
  901.     mov    bl,[di+modChannel.inst]     ; check if there is a new
  902.     test    bl,bl                ; instrument
  903.     jz    @@nonewinst
  904.  
  905.     mov    [di+modChannel.sample],bl    ; set instrument number
  906.  
  907.     push    si
  908.     les    si,[module]
  909.     les    si,[es:si+mpModule.insts]    ; point es:si to instruments
  910.     dec    bx
  911.     imul    bx,bx,SIZE mpInstrument     ; bx = offset in instruments
  912.     add    si,bx                ; point es:si to new inst
  913.     mov    al,[es:si+mpInstrument.volume]        ; al = volume
  914.     mov    bx,[es:si+mpInstrument.sdInstHandle]    ; bx = SD inst handle
  915.     pop    si
  916.  
  917.     mov    [di+modChannel.volume],al    ; set new volume
  918.     or    [di+modChannel.status],1    ; status bit 0 = 1 - new inst
  919.     mov    [di+modChannel.coff],0        ; current Sample Offset = 0
  920.  
  921.     mov    ax,[chan]        ; ax = Sound Device channel number
  922.     add    ax,[firstSDChan]
  923.  
  924.     ; set Sound Device instrument:
  925.     push    gs
  926.     call    [gs:si+SoundDevice.SetInstrument] LANG, ax, bx
  927.     pop    gs
  928.     test    ax,ax            ; error?
  929.     jnz    @@done            ; if so, pass it on
  930.  
  931.  
  932.     cmp    [masterVolume],64    ; is master volume 64
  933.     je    @@nonewinst        ; if so, current volume is OK
  934.  
  935.     mov    al,[di+modChannel.volume]
  936.     call    SetSDVolume        ; set volume to Sound Device
  937.     test    ax,ax
  938.     jnz    @@done
  939.  
  940.  
  941. @@nonewinst:
  942.     movzx    dx,[di+modChannel.note]
  943.     test    dx,dx            ; is there a new note?
  944.     jz    @@nonewnote
  945.  
  946.     movzx    bx,[di+modChannel.sample]    ; bx = current instrument
  947.     test    bx,bx
  948.     jz    @@nonewnote
  949.  
  950.     push    si
  951.  
  952.     les    si,[module]
  953.     les    si,[es:si+mpModule.insts]
  954.     dec    bx            ; point es:si to current instrument
  955.     imul    bx,bx,SIZE mpInstrument
  956.     add    si,bx
  957.  
  958.     mov    al,[es:si+mpInstrument.finetune]   ; al = instrument finetune
  959.     pop    si
  960.  
  961.     dec    dx
  962.     add    dx,dx
  963.     mov    bl,12*3*2
  964.     mul    bl            ; bx = period table offset for
  965.     mov    bx,ax            ; new note
  966.     add    bx,dx
  967.  
  968.     mov    [di+modChannel.snote],bx    ; store period table offset
  969.     mov    bx,[Periods+bx]     ; bx = period number for this note
  970.  
  971.     ; check if current command is a tone portamento:
  972.     mov    al,[di+modChannel.cmd]
  973.     cmp    al,3            ; Tone Portamento
  974.     je    @@tport
  975.     cmp    al,5            ; Tone Portamento + VSlide
  976.     je    @@tport
  977.  
  978.     mov    [di+modChannel.period],bx    ; save period
  979.     or    [di+modChannel.status],3    ; status bit 1 = 1 - new note
  980.  
  981.     mov    ah,[di+modChannel.cmd]
  982.     mov    al,[di+modChannel.info]
  983.     and    ax,0FF0h        ; is current command ED (Note Delay)?
  984.     cmp    ax,0ED0h
  985.     je    @@notedone        ; if is, do not set note
  986.  
  987.  
  988.     movzx    ebx,bx
  989.     mov    eax,3546895        ; eax = PAL clock constant
  990.     cdq                ; PAL clock constant / period
  991.     idiv    ebx            ; = playing rate
  992.  
  993.     mov    ebx,eax         ; ebx = playing rate
  994.  
  995.     mov    ax,[chan]        ; ax = SD channel number
  996.     add    ax,[firstSDChan]
  997.  
  998.     cmp    [di+modChannel.cmd],9    ; is command 9 (sample offset)
  999.     je    @@smpoff
  1000.  
  1001.     mov    [di+modChannel.vibpos],0    ; clear vibrato position
  1002.     mov    [di+modChannel.trepos],0    ; clear tremolo position
  1003.  
  1004.     cmp    [di+modChannel.coff],0    ; if current sample offset is != 0,
  1005.     jne    @@dooffset        ; do not set position
  1006.  
  1007.     ; Start playing sound with rate ebx:
  1008.     push    es gs
  1009.     call    [gs:si+SoundDevice.PlaySound] LANG, ax, ebx
  1010.     pop    gs es
  1011.     test    ax,ax
  1012.     jnz    @@done
  1013.  
  1014.     jmp    @@notedone
  1015.  
  1016.  
  1017. @@dooffset:
  1018.     ; sample offset - only set playing rate
  1019.     push    es gs
  1020.     call    [gs:si+SoundDevice.SetRate] LANG, ax, ebx
  1021.     pop    gs es
  1022.     test    ax,ax
  1023.     jnz    @@done
  1024.  
  1025.     jmp    @@setoffset
  1026.  
  1027. @@smpoff:
  1028.     ; sample offset command
  1029.     push    es gs
  1030.     call    [gs:si+SoundDevice.SetRate] LANG, ax, ebx
  1031.     pop    gs es
  1032.     test    ax,ax
  1033.     jnz    @@done
  1034.  
  1035.     mov    bh,[di+modChannel.info]     ; if command infobyte is 0,
  1036.     test    bh,bh                ; use previous sample offset
  1037.     jnz    @@so1                ; value as new offset
  1038.     mov    bh,[di+modChannel.loff]
  1039.  
  1040. @@so1:
  1041.     mov    [di+modChannel.loff],bh     ; save current sample offset
  1042.     add    [di+modChannel.coff],bh     ; add infobyte to offset
  1043.  
  1044. @@setoffset:
  1045.     ; set sample offset
  1046.     xor    bl,bl            ; bx = new sample playing position
  1047.     mov    bh,[di+modChannel.coff]
  1048.  
  1049.     mov    ax,[chan]        ; ax = SD channel number
  1050.     add    ax,[firstSDChan]
  1051.  
  1052.     ; set playing position:
  1053.     push    es gs
  1054.     call    [gs:si+SoundDevice.SetPosition] LANG, ax, bx
  1055.     pop    gs es
  1056.     test    ax,ax
  1057.     jnz    @@done
  1058.  
  1059.     jmp    @@notedone
  1060.  
  1061.  
  1062. @@tport:
  1063.     ; tone portamento
  1064.     mov    [di+modChannel.toperi],bx    ; store period as slide dest
  1065.     jmp    @@notedone
  1066.  
  1067.  
  1068. @@nonewnote:
  1069.     ; no new note - reset period and volume
  1070.  
  1071.     ; set period:
  1072.     call    SetPeriod
  1073.     test    ax,ax
  1074.     jnz    @@done
  1075.  
  1076.     ; set volume:
  1077.     mov    al,[di+modChannel.volume]
  1078.     call    SetSDVolume
  1079.     test    ax,ax
  1080.     jnz    @@done
  1081.  
  1082.  
  1083. @@notedone:
  1084.     movzx    bx,[di+modChannel.cmd]    ; bx = command number
  1085.     add    bx,bx
  1086.     movzx    ax,[di+modChannel.info] ; ax = command infobyte
  1087.     call    [commands+bx]        ; process command
  1088.     test    ax,ax
  1089.     jnz    @@done
  1090.  
  1091.     add    di,size modChannel    ; point ds:di to next channel
  1092.  
  1093.     mov    ax,[chan]
  1094.     inc    ax            ; next channel number
  1095.     cmp    ax,[numChans]
  1096.     jae    @@no
  1097.     mov    [chan],ax
  1098.     jmp    @@chanloop
  1099.  
  1100. @@no:    cmp    [pbFlag],0
  1101.     jne    @@break
  1102.  
  1103.     inc    [row]            ; next row
  1104.     cmp    [row],64        ; did we reach pattern end?
  1105.     jb    @@noend
  1106.  
  1107.     mov    [row],0
  1108.  
  1109.     ; pattern end - reset playing offset and compression info on
  1110.     ; all channels:
  1111.  
  1112. @@break:
  1113.     mov    cx,[numChans]
  1114.     mov    di,offset channels
  1115. @@l1:    mov    [di+modChannel.playoff],0
  1116.     mov    [di+modChannel.comp],0
  1117.     add    di,size modChannel
  1118.     loop    @@l1
  1119.  
  1120.     inc    [position]        ; next song position
  1121.  
  1122.     mov    bx,[songLength]
  1123.     cmp    [position],bx        ; did we reach song end?
  1124.     jb    @@noend
  1125.  
  1126.     mov    [position],0        ; restart song
  1127.     inc    [loopCnt]        ; increase song loop conter
  1128.  
  1129. @@noend:
  1130.     mov    [pbFlag],0        ; clear pattern break flag
  1131.     call    modUpdBars        ; update volume bars
  1132.  
  1133.     xor    ax,ax            ; success
  1134. @@done:
  1135.     ret
  1136. ENDP
  1137.  
  1138.  
  1139.  
  1140.  
  1141. ;/***************************************************************************\
  1142. ;*
  1143. ;* Function:    SetSDVolume
  1144. ;*
  1145. ;* Description: Sets SD volume to current channel, scaled according to
  1146. ;*        masterVolume
  1147. ;*
  1148. ;* Input:    al        volume
  1149. ;*
  1150. ;* Returns:    MIDAS error code in ax
  1151. ;*
  1152. ;\***************************************************************************/
  1153.  
  1154. PROC    SetSDVolume    NEAR
  1155.  
  1156.     mul    [masterVolume]        ; bx = volume scaled according to
  1157.     shr    ax,6            ; master volume
  1158.     mov    bx,ax
  1159.  
  1160.     mov    ax,[chan]        ; ax = Sound Device channel number
  1161.     add    ax,[firstSDChan]
  1162.  
  1163.     ; set Sound Device volume:
  1164.     push    gs
  1165.     call    [gs:si+SoundDevice.SetVolume] LANG, ax, bx
  1166.     pop    gs
  1167.  
  1168.     ; pass possible error code on
  1169.  
  1170.     ret
  1171. ENDP
  1172.  
  1173.  
  1174.  
  1175. ;/***************************************************************************\
  1176. ;*
  1177. ;* Function:    SetSDPeriod
  1178. ;*
  1179. ;* Description: Sets Sound Device playing period for current channel
  1180. ;*
  1181. ;* Input:    ebx        period number
  1182. ;*
  1183. ;* Returns:    MIDAS error code in ax
  1184. ;*
  1185. ;\***************************************************************************/
  1186.  
  1187. PROC    SetSDPeriod    NEAR
  1188.  
  1189.     test    ebx,ebx             ; skip if zero period
  1190.     jz    @@ok
  1191.  
  1192.     movzx    ebx,bx
  1193.     mov    eax,3546895        ; eax = PAL clock constant
  1194.     cdq                ; PAL clock constant / period
  1195.     idiv    ebx            ; = playing rate
  1196.  
  1197.     mov    ebx,eax         ; ebx = playing rate
  1198.  
  1199.     mov    ax,[chan]        ; ax = SD channel number
  1200.     add    ax,[firstSDChan]
  1201.  
  1202.     ; Set Sound Device playing rate:
  1203.     push    gs
  1204.     call    [gs:si+SoundDevice.SetRate] LANG, ax, ebx
  1205.     pop    gs
  1206.  
  1207.     ; pass possible error code on
  1208.     jmp    @@done
  1209.  
  1210. @@ok:
  1211.     xor    ax,ax
  1212.  
  1213. @@done:
  1214.     ret
  1215. ENDP
  1216.  
  1217.  
  1218.  
  1219.  
  1220.  
  1221. ;/***************************************************************************\
  1222. ;*    Protracker command processing:
  1223. ;\***************************************************************************/
  1224.  
  1225.  
  1226. ; Command F - Set Speed
  1227.  
  1228. PROC    SetSpeed    NEAR
  1229.  
  1230.     test    al,al            ; skip if zero speed
  1231.     jz    @@ok
  1232.  
  1233.     cmp    [ptTempo],1        ; are BPM tempos used?
  1234.     jne    @@speed         ; if not, value is always speed
  1235.  
  1236.     cmp    al,32            ; is infobyte >= 32?
  1237.     jbe    @@speed
  1238.  
  1239.     ; infobyte >= 32 - it is the BPM tempo, not speed
  1240.  
  1241.     mov    [tempo],al        ; store new tempo
  1242.     xor    ah,ah
  1243.  
  1244.     mov    bx,40
  1245.     mul    bx            ; ax = update rate in 100*Hz
  1246.     mov    [mpMOD.updRate],ax
  1247.     mov    bx,ax
  1248.  
  1249.     ; set Sound Device update rate:
  1250.     push    gs bx
  1251.     call    [gs:si+SoundDevice.SetUpdRate] LANG, bx
  1252.     pop    bx gs
  1253.     test    ax,ax
  1254.     jnz    @@done
  1255.  
  1256.     ; set timer update rate:
  1257.     push    gs
  1258.     call    tmrSetUpdRate LANG, bx        ; set timer update rate
  1259.     pop    gs
  1260.  
  1261.     jmp    @@done
  1262.  
  1263. @@speed:
  1264.     mov    [speed],al        ; set speed
  1265.  
  1266. @@ok:    xor    ax,ax
  1267. @@done:
  1268.     ret
  1269. ENDP
  1270.  
  1271.  
  1272.  
  1273.  
  1274. ; Command B - Position Jump
  1275.  
  1276. PROC    PositionJump    NEAR
  1277.  
  1278.     cmp    [position],ax        ; is jump forward?
  1279.     jl    @@fwd
  1280.  
  1281.     inc    [loopCnt]        ; no, increase song loop counter
  1282.  
  1283. @@fwd:
  1284.     dec    ax
  1285.     mov    [position],ax        ; set new position
  1286.     mov    [pbFlag],1        ; break to new pattern
  1287.     mov    [row],0         ; start from row 0
  1288.     xor    ax,ax            ; success
  1289.     ret
  1290. ENDP
  1291.  
  1292.  
  1293.  
  1294. ; Command D - Pattern Break
  1295.  
  1296. PROC    PatternBreak    NEAR
  1297.  
  1298.     mov    ah,al
  1299.     and    al,0fh
  1300.     shr    ah,4            ; ax = new row (infobyte is in
  1301.     aad                ; BCD)
  1302.     cmp    ax,63
  1303.     jbe    @@ok
  1304.     mov    ax,63
  1305. @@ok:    mov    [row],ax        ; store new row
  1306.  
  1307.     mov    [skipFlag],1        ; skip rows next time
  1308.     mov    [pbFlag],1        ; break pattern flag on
  1309.     xor    ax,ax
  1310.     ret
  1311. ENDP
  1312.  
  1313.  
  1314.  
  1315.  
  1316. ; Command C - Set Volume
  1317.  
  1318. PROC    SetVolume    NEAR
  1319.  
  1320.     cmp    al,64
  1321.     jbe    @@vok            ; make sure volume is <= 64
  1322.     mov    al,64
  1323.  
  1324. @@vok:
  1325.     mov    [di+modChannel.volume],al
  1326.     call    SetVol
  1327.  
  1328.     ; pass possible error code on
  1329.     ret
  1330. ENDP
  1331.  
  1332.  
  1333.  
  1334.  
  1335. ; Command A - Volume Slide
  1336.  
  1337. PROC    VolumeSlide    NEAR
  1338.  
  1339.     mov    bl,[di+modChannel.volume]    ; bl = current volume
  1340.  
  1341.     test    al,0F0h
  1342.     jnz    @@add
  1343.  
  1344.     ; Upper nybble of infobyte is 0 - substract lower from volume
  1345.     sub    bl,al
  1346.     jns    @@setv
  1347.     xor    bl,bl
  1348.     jmp    @@setv
  1349.  
  1350. @@add:
  1351.     ; Upper nybble of infobyte is nonzero - add it to volume
  1352.     shr    al,4
  1353.     add    bl,al
  1354.     cmp    bl,64
  1355.     jle    @@setv
  1356.     mov    bl,64
  1357. @@setv:
  1358.     or    [di+modChannel.status],1
  1359.     mov    [di+modChannel.volume],bl
  1360.     mov    al,bl
  1361.     call    SetSDVolume
  1362.  
  1363.     ; pass possible error value on
  1364.  
  1365.     ret
  1366. ENDP
  1367.  
  1368.  
  1369.  
  1370.  
  1371. ; Command E2 - Fine Slide Down
  1372.  
  1373. PROC    FineSlideDown    NEAR
  1374.  
  1375.     and    ax,0Fh
  1376.     cmp    [playCount],0        ; no only if playCount is zero
  1377.     jne    @@ok
  1378.  
  1379.     call    SlideDown
  1380.     jmp    @@done
  1381.  
  1382. @@ok:
  1383.     xor    ax,ax            ; success
  1384.  
  1385. @@done:
  1386.     ret
  1387. ENDP
  1388.  
  1389.  
  1390.  
  1391.  
  1392. ; Command 2 - Slide Down
  1393.  
  1394. PROC    SlideDown NEAR
  1395.  
  1396.     add    [di+modChannel.period],ax
  1397.     call    CheckLimits
  1398.     call    SetPeriod
  1399.     ret
  1400. ENDP
  1401.  
  1402.  
  1403.  
  1404. ; Command E1 - Fine Slide Up
  1405.  
  1406. PROC    FineSlideUp NEAR
  1407.  
  1408.     and    ax,0Fh
  1409.     cmp    [playCount],0        ; no only if playCount is zero
  1410.     jne    @@ok
  1411.  
  1412.     call    SlideUp
  1413.     jmp    @@done
  1414.  
  1415. @@ok:
  1416.     xor    ax,ax            ; success
  1417.  
  1418. @@done:
  1419.     ret
  1420. ENDP
  1421.  
  1422.  
  1423.  
  1424.  
  1425. ; Command 1 - Slide Up
  1426.  
  1427. PROC    SlideUp     NEAR
  1428.     sub    [di+modChannel.period],ax
  1429.     call    CheckLimits
  1430.     call    SetPeriod
  1431.     ret
  1432. ENDP
  1433.  
  1434.  
  1435.  
  1436. ; make sure channel period is within limits
  1437.  
  1438. PROC    CheckLimits    NEAR
  1439.  
  1440.     cmp    [di+modChannel.period],113
  1441.     jge    @@ok1
  1442.     mov    [di+modChannel.period],113
  1443. @@ok1:
  1444.     cmp    [di+modChannel.period],856
  1445.     jle    @@ok2
  1446.     mov    [di+modChannel.period],856
  1447. @@ok2:
  1448.     ret
  1449. ENDP
  1450.  
  1451.  
  1452.  
  1453.  
  1454. ; Command 3 - Tone Portamento
  1455.  
  1456. PROC    TonePortamento NEAR
  1457.  
  1458.     test    ax,ax            ; is infobyte 0?
  1459.     jnz    @@1
  1460.  
  1461.     movzx    ax,[di+modChannel.notepsp]    ; if yes, use old speed
  1462.  
  1463. @@1:    mov    [di+modChannel.notepsp],al    ; store portamento speed
  1464.     mov    bx,[di+modChannel.toperi]
  1465.     test    bx,bx                ; portamento destination zero?
  1466.     jz    @@setperiod            ; if yes, skip
  1467.  
  1468.     cmp    [di+modChannel.period],bx    ; should we slide up?
  1469.     jg    @@up
  1470.  
  1471.     ; slide down:
  1472.     add    [di+modChannel.period],ax    ; increase period
  1473.     cmp    [di+modChannel.period],bx    ; past portamento dest?
  1474.     jl    @@setperiod
  1475.     mov    [di+modChannel.period],bx    ; if yes, set to porta dest
  1476.     mov    [di+modChannel.toperi],0    ; do not slide anymore
  1477.     jmp    @@setperiod
  1478.  
  1479. @@up:
  1480.     ; slide up:
  1481.     sub    [di+modChannel.period],ax    ; decrease period
  1482.     cmp    [di+modChannel.period],bx    ; past portamento dest?
  1483.     jg    @@setperiod
  1484.     mov    [di+modChannel.period],bx    ; if yes, set to porta dest
  1485.     mov    [di+modChannel.toperi],0    ; do not slide anymore
  1486.  
  1487. @@setperiod:
  1488.     call    SetPeriod
  1489.     ret
  1490. ENDP
  1491.  
  1492.  
  1493.  
  1494. ; Set period on channel to Sound Device
  1495.  
  1496. PROC    SetPeriod    NEAR
  1497.  
  1498.     movzx    ebx,[di+modChannel.period]
  1499.  
  1500.     ; Set Sound Device period:
  1501.     call    SetSDPeriod
  1502.  
  1503.     ret
  1504. ENDP
  1505.  
  1506.  
  1507.  
  1508. ; Command 4 - Vibrato
  1509.  
  1510. PROC    Vibrato     NEAR
  1511.  
  1512.     test    al,0Fh            ; is new vibrato depth non-zero?
  1513.     jnz    @@1
  1514.  
  1515.     mov    bl,[di+modChannel.vibcmd]    ; bl = old vibrato infobyte
  1516.     and    bl,0Fh               ; no, set old vibrato depth
  1517.     or    al,bl
  1518.  
  1519. @@1:
  1520.     test    al,0F0h         ; is new vibrato speed non-zero?
  1521.     jnz    @@2
  1522.  
  1523.     mov    bl,[di+modChannel.vibcmd]    ; bl = old vibrato infobyte
  1524.     and    bl,0F0h          ; no, set old vibrato speed
  1525.     or    al,bl
  1526.  
  1527. @@2:
  1528.     mov    [di+modChannel.vibcmd],al    ; store new vibrato infobyte
  1529.  
  1530.     mov    bl,[di+modChannel.vibpos]    ; bx = vibrato table position
  1531.     and    bx,1Fh
  1532.     xor    eax,eax
  1533.     mov    al,[vibratoTable+bx]    ; eax = vibrato value
  1534.     mov    cl,[di+modChannel.vibcmd]
  1535.     and    cl,0Fh            ; multiply with depth
  1536.     mul    cl
  1537.     shr    ax,7            ; divide with 128
  1538.  
  1539.     movzx    ebx,[di+modChannel.period]    ; ebx = channel base period
  1540.  
  1541.     test    [di+modChannel.vibpos],32      ; is vibrato position >= 32?
  1542.     jnz    @@vibneg
  1543.  
  1544.     ; vibrato position < 32 - positive
  1545.     add    ebx,eax
  1546.     jmp    @@setperiod
  1547.  
  1548. @@vibneg:
  1549.     ; vibrato position >= 32 - negative
  1550.     sub    ebx,eax
  1551.  
  1552. @@setperiod:
  1553.     mov    al,[di+modChannel.vibcmd]    ; add vibrato speed  to
  1554.     shr    al,4
  1555.     add    [di+modChannel.vibpos],al    ; vibrato position
  1556.  
  1557.     ; Set period to Sound Device:
  1558.     call    SetSDPeriod
  1559.  
  1560.     ret
  1561. ENDP
  1562.  
  1563.  
  1564.  
  1565.  
  1566. ; Command 0 - Arpeggio
  1567.  
  1568. PROC    Arpeggio    NEAR
  1569.  
  1570.     test    ax,ax            ; is infobyte zero?
  1571.     jz    @@ok            ; skip if is
  1572.  
  1573.     mov    dx,ax            ; save infobyte
  1574.  
  1575.     mov    bx,[di+modChannel.snote]    ; bx = base index to period table
  1576.  
  1577.     movzx    ax,[playCount]
  1578.     mov    cl,3            ; divide player counter with 3
  1579.     div    cl
  1580.     test    ah,ah            ; is modulus zero?
  1581.     jz    @@a0            ; if yes, use base note
  1582.     dec    ah            ; is modulus one?
  1583.     jz    @@a1            ; if yes, use infobyte upper nybble
  1584.  
  1585.     ; modulus is 2 - use infobyte lower nybble
  1586.     and    dx,0Fh
  1587.     add    dx,dx            ; add infobyte lower nybble to note
  1588.     add    bx,dx
  1589.     jmp    @@a0
  1590.  
  1591. @@a1:
  1592.     ; modulus is 1 - use infobyte upper nybble
  1593.     shr    dx,4
  1594.     add    dx,dx            ; add infobyte upper nybble to note
  1595.     add    bx,dx
  1596.  
  1597. @@a0:
  1598.     movzx    ebx,[Periods+bx]    ; get period value
  1599.  
  1600.     ; set period to Sound Device:
  1601.     call    SetSDPeriod
  1602.     jmp    @@done
  1603.  
  1604. @@ok:
  1605.     xor    ax,ax
  1606.  
  1607. @@done:
  1608.     ret
  1609. ENDP
  1610.  
  1611.  
  1612.  
  1613. ; Command 5 - Tone Portamento and Volume Slide
  1614.  
  1615. PROC    TPortVSlide    NEAR
  1616.  
  1617.     call    VolumeSlide        ; do volume slide
  1618.     test    ax,ax
  1619.     jnz    @@done
  1620.  
  1621.     xor    ax,ax
  1622.     call    TonePortamento        ; do tone portamento with 0 infobyte
  1623.  
  1624. @@done:
  1625.     ret
  1626. ENDP
  1627.  
  1628.  
  1629.  
  1630.  
  1631. ; Command 6 - Vibrato and Volume Slide
  1632.  
  1633. PROC    VibratoVSlide    NEAR
  1634.  
  1635.     call    VolumeSlide        ; do volume slide
  1636.     test    ax,ax
  1637.     jnz    @@done
  1638.  
  1639.     xor    ax,ax
  1640.     call    Vibrato         ; do vibrato with 0 infobyte
  1641.  
  1642. @@done:
  1643.     ret
  1644. ENDP
  1645.  
  1646.  
  1647.  
  1648. ; Command 8 - Set Panning
  1649.  
  1650. PROC    SetPanning NEAR
  1651.  
  1652.     cmp    [usePanning],0        ; should panning command be supported?
  1653.     je    @@ok            ; skip if not
  1654.  
  1655.     cmp    al,0A4h         ; DMP-compatible surround panning
  1656.     jne    @@nsurround        ; value 0A4h
  1657.  
  1658.     mov    ax,panSurround        ; set surround panning
  1659.     jmp    @@set
  1660.  
  1661. @@nsurround:
  1662.     cmp    al,128            ; skip illegal panning values
  1663.     ja    @@ok
  1664.  
  1665.     sub    al,40h            ; convert DMP panning values to
  1666.     cbw                ; MIDAS (0-128) to (-64 - 64)
  1667.  
  1668. @@set:
  1669.     mov    bx,[chan]        ; bx = Sound Device channel number
  1670.     add    bx,[firstSDChan]
  1671.  
  1672.     ; Set Sound Device panning:
  1673.     push    gs
  1674.     call    [gs:si+SoundDevice.SetPanning], bx, ax
  1675.     pop    gs
  1676.     jmp    @@done
  1677.  
  1678. @@ok:
  1679.     xor    ax,ax
  1680.  
  1681. @@done:
  1682.     ret
  1683. ENDP
  1684.  
  1685.  
  1686. ; Command E8 - 16-Step Set Panning
  1687.  
  1688. PROC NOLANGUAGE SetPanning16 NEAR
  1689.  
  1690.     cmp    [usePanning],0        ; should panning command be supported?
  1691.     je    @@ok            ; skip if not
  1692.  
  1693.     sub    ax,8
  1694.     js    @@ski
  1695.     inc    ax
  1696. @@ski:
  1697.     sal    ax,3
  1698.     mov    bx,[chan]        ; bx = Sound Device channel number
  1699.     add    bx,[firstSDChan]
  1700.  
  1701.     ; Set Sound Device panning:
  1702.     push    gs
  1703.     call    [gs:si+SoundDevice.SetPanning], bx, ax
  1704.     pop    gs
  1705.     jmp    @@done
  1706. @@ok:
  1707.     xor    ax,ax
  1708. @@done:
  1709.     ret
  1710. ENDP
  1711.  
  1712.  
  1713. ; Command E9 - Retrig Note
  1714.  
  1715. PROC    SetRetrigNote NEAR
  1716.  
  1717.     mov    [di+modChannel.retrigc],1
  1718.  
  1719.     xor    ax,ax
  1720.     ret
  1721. ENDP
  1722.  
  1723.  
  1724.  
  1725. PROC    RetrigNote NEAR
  1726.  
  1727.     cmp    [playCount],0        ; playing song data?
  1728.     jne    @@noset
  1729.  
  1730.     call    SetRetrigNote        ; yes, just set count
  1731.     jmp    @@done
  1732.  
  1733. @@noset:
  1734.     and    al,0Fh            ; should note be retrigged?
  1735.     cmp    [di+modChannel.retrigc],al    ; (retrig count = infobyte)
  1736.     jb    @@no
  1737.  
  1738.     or    [di+modChannel.status],3    ; note triggered
  1739.     mov    [di+modChannel.retrigc],1    ; reset retrig count
  1740.  
  1741.     mov    ax,[chan]        ; ax = Sound Device channel number
  1742.     add    ax,[firstSDChan]
  1743.  
  1744.     ; Start from beginning of sample:
  1745.     push    gs
  1746.     call    [gs:si+SoundDevice.SetPosition], ax, 0
  1747.     pop    gs
  1748.     jmp    @@done
  1749.  
  1750. @@no:    inc    [di+modChannel.retrigc]
  1751.     xor    ax,ax
  1752.  
  1753. @@done:
  1754.     ret
  1755. ENDP
  1756.  
  1757.  
  1758.  
  1759.  
  1760. ; Command 7 - Tremolo
  1761.  
  1762. PROC    Tremolo     NEAR
  1763.  
  1764.     test    al,0Fh            ; is new tremolo depth non-zero?
  1765.     jnz    @@1
  1766.  
  1767.     mov    bl,[di+modChannel.trecmd]    ; bl = old tremolo infobyte
  1768.     and    bl,0Fh               ; no, set old tremolo depth
  1769.     or    al,bl
  1770.  
  1771. @@1:
  1772.     test    al,0F0h         ; is new tremolo speed non-zero?
  1773.     jnz    @@2
  1774.  
  1775.     mov    bl,[di+modChannel.trecmd]    ; bl = old tremolo infobyte
  1776.     and    bl,0F0h          ; no, set old tremolo speed
  1777.     or    al,bl
  1778.  
  1779. @@2:
  1780.     mov    [di+modChannel.trecmd],al    ; store new tremolo infobyte
  1781.  
  1782.     mov    bl,[di+modChannel.trepos]    ; bx = tremolo table position
  1783.     and    bx,1Fh
  1784.     xor    eax,eax
  1785.     mov    al,[vibratoTable+bx]    ; eax = tremolo value
  1786.     mov    cl,[di+modChannel.trecmd]
  1787.     and    cl,0Fh            ; multiply with depth
  1788.     mul    cl
  1789.     shr    ax,7            ; divide with 128
  1790.  
  1791.  
  1792.     movzx    bx,[di+modChannel.volume]    ; bx = channel base volume
  1793.  
  1794.     test    [di+modChannel.trepos],32      ; is position >= 32 ?
  1795.     jnz    @@neg
  1796.  
  1797.     ; Position < 32 - positive
  1798.     add    bx,ax
  1799.     jmp    @@setvol
  1800.  
  1801. @@neg:
  1802.     ; Position >= 32 - negative
  1803.     sub    bx,ax
  1804.  
  1805. @@setvol:
  1806.     mov    al,[di+modChannel.trecmd]
  1807.     shr    al,4                ; add tremolo speed to
  1808.     add    [di+modChannel.trepos],al    ; vibrato position
  1809.  
  1810.     or    [di+modChannel.status],1
  1811.  
  1812.     ; Make sure volume is within limits:
  1813.     cmp    bx,0
  1814.     jge    @@11
  1815.     xor    bx,bx
  1816. @@11:
  1817.     cmp    bx,64
  1818.     jle    @@22
  1819.     mov    bx,64
  1820. @@22:
  1821.     mov    al,bl
  1822.     ; Set volume to Sound Device:
  1823.     call    SetSDVolume
  1824.  
  1825.     ret
  1826. ENDP
  1827.  
  1828.  
  1829.  
  1830.  
  1831. ; Command E - extended commands. Infobyte upper nybble is command number
  1832.  
  1833. PROC    ECommand NEAR
  1834.  
  1835.     mov    bl,al
  1836.         and     bx,0F0h
  1837.     shr    bx,3            ; bx = index to offset table
  1838.     and    ax,0Fh            ; al = infobyte
  1839.     call    [ecmds+bx] LANG     ; process command
  1840.  
  1841.     ret
  1842. ENDP
  1843.  
  1844.  
  1845.  
  1846. ; Command E6 - Pattern Loop
  1847.  
  1848. PROC    PatternLoop NEAR
  1849.  
  1850.     cmp    [playCount],0        ; do only when playing song data
  1851.     jne    @@ok
  1852.  
  1853.     cmp    al,0            ; if infobyte is zero, set loop
  1854.     je    @@setloop        ; starting row
  1855.  
  1856.     cmp    [loopFlag],0        ; already looping?
  1857.     je    @@setcount
  1858.  
  1859.     dec    [loopCount]        ; yes, just decrease loop counter
  1860.     jnz    @@loop            ; counter zero?
  1861.     mov    [loopFlag],0        ; yes, do not loop anymore
  1862.     jmp    @@ok
  1863.  
  1864. @@loop:
  1865.     mov    ax,[loopRow]
  1866.     dec    ax            ; loop to saved row
  1867.     mov    [row],ax
  1868.     mov    [skipFlag],1        ; skip to new row next time
  1869.     jmp    @@ok
  1870.  
  1871. @@setcount:
  1872.     ; start looping - set loop counter
  1873.     mov    [loopCount],al        ; loop counter = infobyte
  1874.     mov    ax,[loopRow]
  1875.     dec    ax            ; loop to saved row
  1876.     mov    [row],ax
  1877.     mov    [loopFlag],1        ; looping
  1878.     mov    [skipFlag],1        ; skip to new row next time
  1879.     jmp    @@ok
  1880.  
  1881. @@setloop:
  1882.     mov    ax,[row]        ; save current row as loop destination
  1883.     mov    [loopRow],ax
  1884. @@ok:
  1885.     xor    ax,ax
  1886.     ret
  1887. ENDP
  1888.  
  1889.  
  1890.  
  1891.  
  1892. ;/***************************************************************************\
  1893. ;*
  1894. ;* Function:    modSkipRows
  1895. ;*
  1896. ;* Description: Skips to current row in pattern data
  1897. ;*
  1898. ;* Returns:    MIDAS error code in ax
  1899. ;*
  1900. ;\***************************************************************************/
  1901.  
  1902. PROC    modSkipRows    NEAR
  1903. LOCAL    skipCount : word, chanCount : word, trackNum : word
  1904.  
  1905.     mov    di,offset channels    ; point ds:di to channel structures
  1906.  
  1907.     mov    cx,[numChans]
  1908.  
  1909.     ; Reset playing offset and compression info from all channels:
  1910. @@clearlp:
  1911.     mov    [di+modChannel.playoff],0
  1912.     mov    [di+modChannel.comp],0
  1913.     add    di,size modChannel
  1914.     loop    @@clearlp
  1915.  
  1916.  
  1917.     les    si,[module]        ; point es:si to module structure
  1918.     mov    bx,[position]
  1919.     lgs    di,[es:si+mpModule.orders]    ; point gs:di to orders
  1920.     movzx    ax,[byte gs:di+bx]        ; ax = current pattern
  1921.  
  1922.     mul    [numChans]        ; ax = current track number
  1923.     mov    [trackNum],ax        ; save track number
  1924.  
  1925.     mov    di,offset channels    ; point ds:di to channel structures
  1926.  
  1927.     mov    ax,[numChans]
  1928.     mov    [chanCount],ax        ; set channel counter
  1929.  
  1930.  
  1931. @@chanloop:
  1932.     mov    [skipCount],0        ; set skipped rows counter to 0
  1933.  
  1934.     cmp    [row],0         ; should we skip to row 0?
  1935.     je    @@endskip        ; if so, we are finished skipping
  1936.  
  1937.     les    si,[module]        ; point es:si to module structure
  1938.  
  1939.     mov    bx,[trackNum]        ; bx = current track number
  1940.     push    di
  1941.     lgs    di,[es:si+mpModule.pattEMS] ; point gs:di to track EMS flags
  1942.     mov    al,[byte gs:di+bx]         ; al = EMS flag
  1943.  
  1944.     lgs    di,[es:si+mpModule.patterns]  ; point gs:di to track pointers
  1945.     shl    bx,2
  1946.     mov    edx,[gs:si+bx]        ; edx = pointer to track memory
  1947.  
  1948.     pop    di
  1949.  
  1950.     cmp    al,0            ; is EMS flag 0?
  1951.     je    @@noEMS         ; if so, pattern is not in EMS
  1952.  
  1953.  
  1954.     ; map pattern data to conventional memory:
  1955.     call    emsMap LANG, edx, seg modMemPtr offset modMemPtr
  1956.     test    ax,ax            ; error?
  1957.     jnz    @@done            ; if so, pass it on
  1958.  
  1959.     les    si,[modMemPtr]        ; point es:si to track in
  1960.     jmp    @@dataok        ; conventional memory
  1961.  
  1962.  
  1963. @@noEMS:
  1964.     mov    si,dx
  1965.     shr    edx,16            ; point es:si to track data
  1966.     mov    es,dx
  1967.  
  1968. @@dataok:
  1969.     add    si,[di+modChannel.playoff]    ; add playing position to si
  1970.  
  1971.  
  1972.     ; now skip rows:
  1973. @@rowloop:
  1974.     mov    ax,[skipCount]        ; ax = number of rows skipped
  1975.     cmp    [row],ax        ; are we at correct row?
  1976.     je    @@endskip        ; if so, we are finished
  1977.  
  1978.     mov    al,[di+modChannel.comp] ; al = compression info for current ch
  1979.     test    al,40h            ; if bit 6 of compression info is 1,
  1980.     jz    @@empty         ; rows of same data follow
  1981.  
  1982.  
  1983.     and    al,3Fh            ; al = number of rows of same data
  1984.     jz    @@nocomp        ; if zero, go to next row
  1985.     dec    [di+modChannel.comp]    ; decrease compression counter
  1986.     jmp    @@skip            ; do not process pattern data
  1987.  
  1988. @@empty:
  1989.     and    al,3Fh            ; al = number of empty rows
  1990.     jz    @@nocomp        ; if zero, go to next row
  1991.     dec    [di+modChannel.comp]    ; decrease compression counter
  1992.  
  1993.     mov    [di+modChannel.note],0    ; no new note
  1994.     mov    [di+modChannel.inst],0    ; no new instrument
  1995.     mov    [di+modChannel.cmd],0    ; no new command
  1996.     mov    [di+modChannel.info],0    ; no new infobyte
  1997.     jmp    @@skip            ; do not process pattern data
  1998.  
  1999.  
  2000. @@nocomp:
  2001.     ; no compression - process next row of pattern data
  2002.     mov    dl,[es:si]        ; dl = first data byte
  2003.     inc    si
  2004.  
  2005.     mov    al,dl
  2006.     and    al,7Fh
  2007.     cmp    al,01111000b        ; if data = x1111000b, the row is
  2008.     je    @@emptyr        ; empty
  2009.  
  2010.     and    al,01111000b        ; if data = x1110xxxb, there is a
  2011.     cmp    al,01110000b        ; note and an instrument
  2012.     je    @@noteInst
  2013.  
  2014.     and    al,01110000b        ; if data = x110xxxxb, there is a
  2015.     cmp    al,01100000b        ; command
  2016.     je    @@command
  2017.  
  2018.  
  2019.     ; there is a note, instrument and command:
  2020.     mov    al,dl
  2021.     and    al,7Eh            ; al = note number
  2022.     shr    al,1
  2023.     mov    [di+modChannel.note],al
  2024.  
  2025.     mov    ah,dl            ; ah = first data byte
  2026.     mov    al,[es:si]        ; al = next data byte
  2027.     inc    si
  2028.  
  2029.     mov    dh,al
  2030.     and    dh,0Fh            ; dh = command number
  2031.     mov    [di+modChannel.cmd],dh
  2032.  
  2033.     shr    ax,4
  2034.     and    ax,1Fh            ; ax = instrument number
  2035.     mov    [di+modChannel.inst],al
  2036.  
  2037.     mov    al,[es:si]
  2038.     inc    si            ; al = next data byte = command
  2039.     mov    [di+modChannel.info],al ; infobyte
  2040.  
  2041.     add    [di+modChannel.playoff],3    ; 3 bytes played
  2042.  
  2043.     jmp    @@checkcomp        ; check for compression info
  2044.  
  2045.  
  2046.     ; there is only a command:
  2047. @@command:
  2048.     mov    al,dl
  2049.     and    al,0fh            ; al = command number
  2050.     mov    [di+modChannel.cmd],al
  2051.  
  2052.     mov    al,[es:si]
  2053.     inc    si            ; al = next data byte = command
  2054.     mov    [di+modChannel.info],al ; infobyte
  2055.  
  2056.     mov    [di+modChannel.note],0    ; there is no new note or
  2057.     mov    [di+modChannel.inst],0    ; instrument
  2058.  
  2059.     add    [di+modChannel.playoff],2
  2060.  
  2061.     jmp    @@checkcomp
  2062.  
  2063.  
  2064.     ; there is a note and an instrument:
  2065. @@noteInst:
  2066.     mov    ah,dl            ; ah = first data byte
  2067.     mov    al,[es:si]        ; al = next
  2068.     inc    si
  2069.  
  2070.     mov    dh,al            ; dh = second data byte
  2071.     and    dh,1Fh            ; dh = instrument number
  2072.     mov    [di+modChannel.inst],dh
  2073.  
  2074.     shr    ax,5
  2075.     and    ax,3Fh            ; al = note number
  2076.     mov    [di+modChannel.note],al
  2077.  
  2078.     mov    [di+modChannel.cmd],0    ; no command
  2079.     mov    [di+modChannel.info],0    ; no infobyte
  2080.  
  2081.     add    [di+modChannel.playoff],2
  2082.  
  2083.     jmp    @@checkcomp
  2084.  
  2085.  
  2086.     ; empty row:
  2087. @@emptyr:
  2088.     mov    [di+modChannel.note],0    ; no new note
  2089.     mov    [di+modChannel.inst],0    ; no new instrument
  2090.     mov    [di+modChannel.cmd],0    ; no new command
  2091.     mov    [di+modChannel.info],0    ; no new infobyte
  2092.     inc    [di+modChannel.playoff]
  2093.  
  2094. @@checkcomp:
  2095.     test    dl,80h            ; if bit 7 of first data byte is 1,
  2096.     jz    @@skip
  2097.     mov    al,[es:si]        ; a compression info byte follows
  2098.     inc    si
  2099.     mov    [di+modChannel.comp],al ; store it
  2100.     inc    [di+modChannel.playoff] ; one more byte played
  2101.  
  2102.  
  2103. @@skip:
  2104.     ; one row of data processed
  2105.     inc    [skipCount]
  2106.     jmp    @@rowloop
  2107.  
  2108.  
  2109.  
  2110. @@endskip:
  2111.     ; all rows succesfully skipped for this channel - we are now playing
  2112.     ; at the correct row
  2113.     inc    [trackNum]        ; next track
  2114.     add    di,SIZE modChannel    ; next channel
  2115.  
  2116.     dec    [chanCount]
  2117.     jnz    @@chanloop
  2118.  
  2119.     mov    [skipFlag],0        ; do not skip data now
  2120.  
  2121.     xor    ax,ax
  2122.  
  2123. @@done:
  2124.     ret
  2125. ENDP
  2126.  
  2127.  
  2128.  
  2129. ; Command EA - Fine Volume Slide Up
  2130.  
  2131. PROC    FineVolumeSlideUp NEAR
  2132.  
  2133.     cmp    [playCount],0        ; do only when playing song data
  2134.     jne    @@ok
  2135.  
  2136.     add    [di+modChannel.volume],al    ; add infobyte to volume
  2137.     cmp    [di+modChannel.volume],64    ; make sure volume is within
  2138.     jle    @@set                ; limits (<= 64)
  2139.     mov    [di+modChannel.volume],64
  2140.  
  2141. @@set:
  2142.     call    SetVol
  2143.     jmp    @@done
  2144.  
  2145. @@ok:
  2146.     xor    ax,ax
  2147.  
  2148. @@done:
  2149.     ret
  2150. ENDP
  2151.  
  2152.  
  2153.  
  2154.  
  2155. ; Command EB - Fine Volume Slide Down
  2156.  
  2157. PROC    FineVolumeSlideDown    NEAR
  2158.  
  2159.     cmp    [playCount],0        ; do only when playing song data
  2160.     jne    @@ok
  2161.  
  2162.     sub    [di+modChannel.volume],al    ; substract infobyte from vol
  2163.     cmp    [di+modChannel.volume],0    ; make sure volume is positive
  2164.     jge    @@set
  2165.     mov    [di+modChannel.volume],0
  2166.  
  2167. @@set:
  2168.     call    SetVol
  2169.     jmp    @@done
  2170.  
  2171. @@ok:
  2172.     xor    ax,ax
  2173.  
  2174. @@done:
  2175.     ret
  2176. ENDP
  2177.  
  2178.  
  2179.  
  2180.  
  2181. ; Command EC - Note Cut
  2182.  
  2183. PROC    NoteCut     NEAR
  2184.  
  2185.     cmp    [playCount],al        ; cut note when play counter is equal
  2186.     jne    @@ok            ; to infobyte
  2187.  
  2188.     ; Cut note by setting colume to zero:
  2189.     mov    [di+modChannel.volume],0
  2190.     call    SetVol
  2191.     jmp    @@done
  2192.  
  2193. @@ok:
  2194.     xor    ax,ax
  2195.  
  2196. @@done:
  2197.     ret
  2198. ENDP
  2199.  
  2200.  
  2201.  
  2202. ; Command ED - Note Delay
  2203.  
  2204. PROC    NoteDelay    NEAR
  2205.  
  2206.     cmp    [playCount],al        ; start note when player count is
  2207.     jne    @@ok            ; equal to infobyte
  2208.  
  2209.     movzx    ebx,[di+modChannel.period]    ; ebx = period
  2210.     test    bx,bx                ; skip if zero period
  2211.     jz    @@ok
  2212.  
  2213.     or    [di+modChannel.status],3    ; note set
  2214.  
  2215.     movzx    ebx,bx
  2216.     mov    eax,3546895        ; eax = PAL clock constant
  2217.     cdq                ; PAL clock constant / period
  2218.     idiv    ebx            ; = playing rate
  2219.  
  2220.     mov    ebx,eax         ; ebx = playing rate
  2221.  
  2222.     mov    ax,[chan]        ; ax = SD channel number
  2223.     add    ax,[firstSDChan]
  2224.  
  2225.     ; Start playing sound:
  2226.     push    gs
  2227.     call    [gs:si+SoundDevice.PlaySound] LANG, ax, ebx
  2228.     pop    gs
  2229.     jmp    @@done
  2230.  
  2231. @@ok:
  2232.     xor    ax,ax
  2233.  
  2234. @@done:
  2235.     ret
  2236. ENDP
  2237.  
  2238.  
  2239.  
  2240.  
  2241. ; Command EE - Pattern Delay
  2242.  
  2243. PROC    PatternDelay    NEAR
  2244.  
  2245.     cmp    [delayFlag],0        ; do not set delay counter if pattern
  2246.     jne    @@ok            ; delay is already active
  2247.  
  2248.     mov    [delayCount],al     ; pattern delay count = infobyte
  2249.     mov    [delayFlag],1        ; pattern delay active
  2250.  
  2251. @@ok:
  2252.     xor    ax,ax
  2253.  
  2254.     ret
  2255. ENDP
  2256.  
  2257.  
  2258.  
  2259.  
  2260. ;/***************************************************************************\
  2261. ;*
  2262. ;* Function:    SetVol
  2263. ;*
  2264. ;* Description: Sets current channel volume to Sound Device
  2265. ;*
  2266. ;* Returns:    MIDAS error code in ax
  2267. ;*
  2268. ;\***************************************************************************/
  2269.  
  2270. PROC    SetVol        NEAR
  2271.  
  2272.     or    [di+modChannel.status],1    ; volume set
  2273.     mov    al,[di+modChannel.volume]    ; al = channel volume
  2274.     mov    bl,[masterVolume]
  2275.     mul    bl
  2276.     shr    ax,6                ; bx = volume scaled according
  2277.     mov    bx,ax                ; to master volume
  2278.  
  2279.     mov    ax,[chan]        ; ax = Sound Device channel number
  2280.     add    ax,[firstSDChan]
  2281.  
  2282.     ; Set Sound Device playing volume:
  2283.     push    gs
  2284.     call    [gs:si+SoundDevice.SetVolume] LANG, ax, bx
  2285.     pop    gs
  2286.  
  2287.     ret
  2288. ENDP
  2289.  
  2290.  
  2291.  
  2292.  
  2293. ; Do nothing - just clear ax to mark success
  2294.  
  2295. PROC    DoNothing    NEAR
  2296.  
  2297.     xor    ax,ax
  2298.     ret
  2299. ENDP
  2300.  
  2301.  
  2302.  
  2303.  
  2304. ;/***************************************************************************\
  2305. ;*     Calling offset tables to commands:
  2306. ;\***************************************************************************/
  2307.  
  2308.     ; Commands run when song data is played:
  2309. LABEL    commands    WORD
  2310.     DW    offset Arpeggio
  2311.     DW    offset DoNothing
  2312.     DW    offset DoNothing
  2313.     DW    offset DoNothing
  2314.     DW    offset Vibrato
  2315.     DW    offset DoNothing
  2316.     DW    offset DoNothing
  2317.     DW    offset Tremolo
  2318.     DW    offset SetPanning
  2319.     DW    offset DoNothing
  2320.     DW    offset DoNothing
  2321.     DW    offset PositionJump
  2322.     DW    offset SetVolume
  2323.     DW    offset PatternBreak
  2324.     DW    offset ECommand
  2325.     DW    offset SetSpeed
  2326.  
  2327.     ; Continuous commands, run when song data is not played:
  2328. LABEL    contCmd     WORD
  2329.     DW    offset Arpeggio
  2330.     DW    offset SlideUp
  2331.     DW    offset SlideDown
  2332.     DW    offset TonePortamento
  2333.     DW    offset Vibrato
  2334.     DW    offset TPortVSlide
  2335.     DW    offset VibratoVSlide
  2336.     DW    offset Tremolo
  2337.     DW    offset DoNothing
  2338.     DW    offset DoNothing
  2339.     DW    offset VolumeSlide
  2340.     DW    offset DoNothing
  2341.     DW    offset DoNothing
  2342.     DW    offset DoNothing
  2343.     DW    offset ECommand
  2344.     DW    offset DoNothing
  2345.  
  2346.     ; Protracker extended E-commands:
  2347. LABEL    ecmds        WORD
  2348.     DW    offset DoNothing
  2349.     DW    offset FineSlideUp
  2350.     DW    offset FineSlideDown
  2351.     DW    offset DoNothing
  2352.     DW    offset DoNothing
  2353.     DW    offset DoNothing
  2354.     DW    offset PatternLoop
  2355.     DW    offset DoNothing
  2356.     DW    offset SetPanning16
  2357.     DW    offset RetrigNote
  2358.     DW    offset FineVolumeSlideUp
  2359.     DW    offset FineVolumeSlideDown
  2360.     DW    offset NoteCut
  2361.     DW    offset NoteDelay
  2362.     DW    offset PatternDelay
  2363.     DW    offset DoNothing
  2364.  
  2365. ENDP
  2366.  
  2367.  
  2368.  
  2369. ;/***************************************************************************\
  2370. ;*
  2371. ;* Function:    int modSetPosition(ushort pos)
  2372. ;*
  2373. ;* Description: Jumps to a specified position in module
  2374. ;*
  2375. ;* Input:    ushort    pos        Position to jump to
  2376. ;*
  2377. ;* Returns:    MIDAS error code
  2378. ;*
  2379. ;\***************************************************************************/
  2380.  
  2381. PROC    modSetPosition    FAR    pos : word
  2382. USES    di
  2383.  
  2384.     mov    ax,[pos]        ; ax = new position
  2385.  
  2386.     cmp    ax,0            ; new position negative?
  2387.     jge    @@ok1
  2388.     mov    ax,[songLength]     ; if is, set to end of song
  2389.     dec    ax
  2390.  
  2391. @@ok1:
  2392.     mov    [position],ax        ; set new position
  2393.     mov    [poss],ax
  2394.  
  2395.     mov    [row],0         ; start from row 0
  2396.  
  2397.     mov    bx,[songLength]
  2398.     cmp    [position],bx        ; is position past song end?
  2399.     jl    @@ok2
  2400.  
  2401.     mov    [position],0        ; if is, start from the beginning
  2402.  
  2403. @@ok2:
  2404.     ; clear playing offset and compression info from all channels:
  2405.  
  2406.     mov    cx,[numChans]
  2407.     mov    di,offset channels
  2408. @@chanloop:
  2409.     mov    [di+modChannel.playoff],0
  2410.     mov    [di+modChannel.comp],0
  2411.     add    di,size modChannel
  2412.     loop    @@chanloop
  2413.  
  2414.     mov    [pbFlag],0        ; clear pattern break and loop
  2415.     mov    [loopFlag],0        ; flags
  2416.  
  2417.     xor    ax,ax            ; success
  2418.  
  2419.     ret
  2420. ENDP
  2421.  
  2422.  
  2423.  
  2424.  
  2425. ;/***************************************************************************\
  2426. ;*
  2427. ;* Function:    int modGetInformation(mpInformation *info);
  2428. ;*
  2429. ;* Description: Fills the Module Player information structure
  2430. ;*
  2431. ;* Input:    mpInformation *info    information structure to be filled
  2432. ;*
  2433. ;* Returns:    MIDAS error code
  2434. ;*
  2435. ;\***************************************************************************/
  2436.  
  2437. PROC    modGetInformation    FAR    info : dword
  2438. USES    si,di,ds
  2439.  
  2440.     les    si,[info]        ; point es:si to information structure
  2441.     mov    di,offset channels    ; point ds:di to channel structures
  2442.  
  2443.     mov    ax,[setFrame]
  2444.     mov    [es:si+mpInformation.setFrame],ax      ; copy set-frame flag
  2445.     mov    [setFrame],0            ; set set-frame flag to 0
  2446.  
  2447.     mov    ax,[rows]
  2448.     mov    [es:si+mpInformation.row],ax
  2449.     mov    ax,[poss]            ; copy saved row, position and
  2450.     mov    [es:si+mpInformation.pos],ax           ; pattern numbers
  2451.     mov    ax,[pats]
  2452.     mov    [es:si+mpInformation.pattern],ax
  2453.  
  2454.     movzx    ax,[speed]
  2455.     mov    [es:si+mpInformation.speed],ax           ; copy speed and tempo values
  2456.     movzx    ax,[tempo]
  2457.     mov    [es:si+mpInformation.BPM],ax
  2458.  
  2459.     movzx    ax,[loopCnt]            ; copy song loop counter
  2460.     mov    [es:si+mpInformation.loopCnt],ax
  2461.  
  2462.     mov    cx,[es:si+mpInformation.numChannels]   ; cx = number of channels
  2463.     les    si,[es:si+mpInformation.chans]           ; es:si points to channel
  2464.                         ; information structure
  2465.  
  2466. @@chanloop:
  2467.     mov    [es:si+mpChanInfo.flags],0    ; clear channel info flags
  2468.  
  2469.     mov    ax,[di+modChannel.snote]    ; ax = current period table
  2470.                         ; index
  2471.     mov    bl,12*3*2
  2472.     div    bl                ; convert ax to note number
  2473.     mov    al,ah
  2474.     xor    ah,ah
  2475.     shr    ax,1
  2476.  
  2477.     mov    bl,12                ; divide note number with 12
  2478.     div    bl                ; al = octave, ah = note
  2479.  
  2480.     inc    al
  2481.     shl    al,4                ; set octave to upper nybble
  2482.     or    al,ah                ; and note to lower
  2483.  
  2484.     mov    [es:si+mpChanInfo.note],al    ; store note and octave
  2485.  
  2486.     or    [es:si+mpChanInfo.flags],32
  2487.  
  2488.  
  2489.     mov    al,[di+modChannel.sample]        ; copy current
  2490.     mov    [es:si+mpChanInfo.instrument],al    ; instrument number
  2491.     or    [es:si+mpChanInfo.flags],32
  2492.  
  2493.     mov    al,[di+modChannel.info]         ; copy command
  2494.     mov    [es:si+mpChanInfo.infobyte],al        ; infobyte
  2495.  
  2496.     mov    al,[di+modChannel.volume]        ; copy volume
  2497.     mov    [es:si+mpChanInfo.volume],al
  2498.  
  2499.     mov    al,[di+modChannel.volbar]        ; copy volume bar
  2500.     mul    [masterVolume]
  2501.     shr    ax,6
  2502.     mov    [es:si+mpChanInfo.volumebar],al
  2503.  
  2504.     mov    al,[di+modChannel.cmd]
  2505.     and    al,0Fh                ; if command number is
  2506.     jnz    @@cmd                ; non-zero, or infobyte is
  2507.     cmp    [di+modChannel.info],0        ; non-zero, there is a command
  2508.     jne    @@cmd
  2509.  
  2510.     ; no command - point commandname to empty string:
  2511.     mov    [es:si+mpChanInfo.command],0
  2512.     mov    [word es:si+mpChanInfo.commandname],offset strNoCmd
  2513.     mov    [word es:si+2+mpChanInfo.commandname],seg strNoCmd
  2514.     jmp    @@cmdok
  2515.  
  2516. @@cmd:
  2517.     or    [es:si+mpChanInfo.flags],128    ; there is a command
  2518.  
  2519.     movzx    bx,al
  2520.     cmp    bx,0Eh                ; E-command?
  2521.     jne    @@notecmd
  2522.  
  2523.     ; the command is E-command. Store infobyte upper nybble + 10h as the
  2524.     ; command number and infobyte lower nybble as infobyte:
  2525.     mov    al,[es:si+mpChanInfo.infobyte]
  2526.     shr    al,4
  2527.     movzx    bx,al
  2528.     add    al,10h
  2529.     mov    [es:si+mpChanInfo.command],al
  2530.     and    [es:si+mpChanInfo.infobyte],0Fh
  2531.  
  2532.     shl    bx,2
  2533.     mov    eax,[ecmdNames+bx]            ; eax = command name
  2534.     mov    [es:si+mpChanInfo.commandname],eax    ; string pointer
  2535.     jmp    @@cmdok
  2536.  
  2537. @@notecmd:
  2538.     ; normal command
  2539.     mov    [es:si+mpChanInfo.command],al
  2540.  
  2541.     shl    bx,2            ; eax = command name string pointer
  2542.     mov    eax,[cmdNames+bx]
  2543.     mov    [es:si+mpChanInfo.commandname],eax     ; store pointer
  2544.  
  2545. @@cmdok:
  2546.     add    si, SIZE mpChanInfo    ; next channel
  2547.     add    di, SIZE modChannel
  2548.     loop    @@chanloop
  2549.  
  2550.     xor    ax,ax            ; success
  2551.     ret
  2552. ENDP
  2553.  
  2554.  
  2555.  
  2556. ;/***************************************************************************\
  2557. ;*
  2558. ;* Function:    int modSetMasterVolume(uchar volume)
  2559. ;*
  2560. ;* Description: Sets the module player master volume
  2561. ;*
  2562. ;* Input:    uchar  volume          New master volume
  2563. ;*
  2564. ;* Returns:    MIDAS error code
  2565. ;*
  2566. ;\***************************************************************************/
  2567.  
  2568. PROC    modSetMasterVolume  FAR     vol : word
  2569.  
  2570.     mov    ax,[vol]
  2571.     cmp    al,64
  2572.     jbe    @@ok
  2573.     mov    al,64
  2574. @@ok:
  2575.     mov    [masterVolume],al
  2576.     xor    ax,ax            ; success
  2577.     ret
  2578. ENDP
  2579.  
  2580.  
  2581.  
  2582. ;/***************************************************************************\
  2583. ;*
  2584. ;* Function:    modSave
  2585. ;*
  2586. ;* Description: Saves row, position and pattern values for GetInformation()
  2587. ;*
  2588. ;\***************************************************************************/
  2589.  
  2590. PROC    modSave     NEAR
  2591. USES    di
  2592.  
  2593.     mov    [setFrame],1        ; set set-frame flag
  2594.     mov    ax,[row]
  2595.     mov    [rows],ax        ; save row and position
  2596.     mov    bx,[position]
  2597.     mov    [poss],bx
  2598.  
  2599.     lgs    di,[es:si+mpModule.orders]
  2600.     movzx    bx,[gs:di+bx]        ; save pattern number
  2601.     mov    [pats],bx
  2602.  
  2603.     xor    ax,ax
  2604.  
  2605.     ret
  2606. ENDP
  2607.  
  2608.  
  2609.  
  2610.  
  2611. ;/***************************************************************************\
  2612. ;*
  2613. ;* Function:    modUpdBars
  2614. ;*
  2615. ;* Description: Updates "fake" volume bars
  2616. ;*
  2617. ;\***************************************************************************/
  2618.  
  2619. PROC    modUpdBars    NEAR
  2620. USES    di
  2621.  
  2622.     mov    di,offset channels    ; point ds:di to channel structures
  2623.     mov    cx,[numChans]
  2624.  
  2625. @@chanloop:
  2626.     cmp    [di+modChannel.volbar],0    ; is volume bar zero?
  2627.     je    @@1
  2628.     dec    [di+modChannel.volbar]        ; if not, decrement it
  2629. @@1:
  2630.     test    [di+modChannel.status],1    ; has volume been changed?
  2631.     jz    @@nochange
  2632.     mov    al,[di+modChannel.volume]
  2633.     test    [di+modChannel.status],2    ; force new volume?
  2634.     jnz    @@force
  2635.     cmp    [di+modChannel.volbar],al    ; do not force volume
  2636.     jbe    @@nochange            ; is bar above volume level?
  2637. @@force:
  2638.     mov    [di+modChannel.volbar],al    ; set new volume
  2639.  
  2640. @@nochange:
  2641.     and    [di+modChannel.status],not 3    ; clear volume change bits
  2642.     add    di,SIZE modChannel        ; next channel
  2643.     loop    @@chanloop
  2644.  
  2645.     xor    ax,ax
  2646.     ret
  2647. ENDP
  2648.  
  2649.  
  2650.  
  2651.  
  2652. ;/***************************************************************************\
  2653. ;*
  2654. ;* Function:    int modConvertSample(uchar *sample, ushort length);
  2655. ;*
  2656. ;* Description: Converts signed 8-bit sample to unsigned.
  2657. ;*
  2658. ;* Input:       uchar *sample           pointer to sample data
  2659. ;*        ushort length        sample length in bytes
  2660. ;*
  2661. ;* Returns:    MIDAS error code
  2662. ;*
  2663. ;\***************************************************************************/
  2664.  
  2665. PROC    modConvertSample    FAR    sample : dword, slength : word
  2666.  
  2667.     les    bx,[sample]        ; point es:bx to sample data
  2668.     mov    cx,[slength]        ; cx = sample length
  2669.     test    cx,cx            ; skip if zero length
  2670.     jz    @@ok
  2671.  
  2672. @@lp:    xor    [byte es:bx],80h    ; convert sample byte
  2673.     inc    bx
  2674.     loop    @@lp
  2675.  
  2676. @@ok:
  2677.     xor    ax,ax
  2678.  
  2679.     ret
  2680. ENDP
  2681.  
  2682.  
  2683.  
  2684.  
  2685. ;/***************************************************************************\
  2686. ;*
  2687. ;* Function:    int modConvertTrack(void *track, ushort type,
  2688. ;*            ushort *trackLen);
  2689. ;*
  2690. ;* Description: Converts one Protracker format track to internal format
  2691. ;*
  2692. ;* Input:    void *track        pointer to track data
  2693. ;*        ushort type        track type (0 = normal Protracker)
  2694. ;*        ushort *trackLen    pointer to track length variable
  2695. ;*
  2696. ;* Returns:    MIDAS error code.
  2697. ;*        Converted track length stored in *trackLen.
  2698. ;*
  2699. ;\***************************************************************************/
  2700.  
  2701. PROC    modConvertTrack FAR    track : dword, trackType : word, \
  2702.                 trackLen : dword
  2703. LOCAL    period : word, note : word, inst : word, cmd : word, tLength : word, \
  2704.     lastOff : word, firstData : word, lastData : dword, comp : word, \
  2705.     rowCount : byte
  2706. USES    si,di
  2707.  
  2708.     mov    [rowCount],64        ; row counter = 64
  2709.     les    si,[track]        ; point es:si to track data
  2710.  
  2711.     mov    di,si            ; point es:di to conversion dest
  2712.     mov    [lastOff],di
  2713.  
  2714.     mov    [firstData],1        ; flag - first data, no compression
  2715.     mov    [lastData],0        ; no previous pattern data
  2716.     mov    [comp],0        ; no compression
  2717.  
  2718. @@rowloop:
  2719. ;    MTM support, now removed:
  2720. ;     cmp     [type],1
  2721. ;     je     @@mtm
  2722.  
  2723.     ; Read period from pattern data:
  2724.     mov    ax,[es:si]
  2725.     xchg    ah,al
  2726.     mov    bh,ah
  2727.     and    ax,0FFFh
  2728.     mov    [period],ax
  2729.  
  2730.     ; Read instrument number:
  2731.     mov    bl,[es:si+2]
  2732.     shr    bl,4
  2733.     and    bh,0F0h
  2734.     or    bl,bh
  2735.     xor    bh,bh
  2736.     mov    [inst],bx
  2737.  
  2738.     ; Read command and infobyte:
  2739.     mov    ax,[es:si+2]
  2740.     xchg    ah,al
  2741.     and    ax,0FFFh
  2742.     mov    [cmd],ax
  2743.  
  2744.     ; Find note number corresponding to the period:
  2745.     mov    [note],0        ; no note
  2746.     cmp    [period],0        ; is period zero?
  2747.     je    @@nosearch        ; if yes, there is no note
  2748.     push    si
  2749.  
  2750.     mov    cx,36            ; there are 36 note numbers
  2751.     xor    si,si            ; si = period table index
  2752.     mov    bx,1            ; current note number = 1
  2753.  
  2754. @@findnote:
  2755.     mov    ax,[Periods+si]     ; ax = period for this note
  2756.     cmp    [period],ax        ; equal to period in pattern?
  2757.     je    @@found
  2758.     inc    bx            ; no, try next note
  2759.     add    si,2
  2760.     loop    @@findnote
  2761.  
  2762.     ; no note found for period - invalid pattern data
  2763.     pop    si
  2764.     jmp    @@error
  2765.  
  2766. @@found:
  2767.     ; note corresponding to the period found
  2768.     mov    [note],bx
  2769.     pop    si
  2770.  
  2771. @@nosearch:
  2772.     add    si,4            ; point es:si to next row
  2773.  
  2774.  
  2775. @@compress:
  2776.     cmp    [cmd],0         ; is there a command?
  2777.     jne    @@cmd
  2778.  
  2779.     ; there is no command
  2780.     cmp    [note],0        ; is there a note?
  2781.     jne    @@ncmd
  2782.     cmp    [inst],0        ; or instrument
  2783.     jne    @@ncmd
  2784.  
  2785.     ; no note, command or instrument
  2786.     mov    [lastData],0        ; an empty row
  2787.  
  2788.     cmp    [firstData],1        ; is this the first row?
  2789.     je    @@putempty
  2790.  
  2791.     mov    bx,[lastOff]        ; does previous row already have
  2792.     test    [byte es:bx],80h    ; compression info?
  2793.     jne    @@cinfo
  2794.  
  2795.     mov    [comp],1        ; add compression info - empty rows
  2796.  
  2797.     or    [byte es:bx],80h    ; compression info follows prev. row
  2798.     mov    [byte es:di],1        ; one empty row
  2799.     jmp    @@next            ; do next row
  2800.  
  2801.  
  2802.     ; There was already compression info:
  2803. @@cinfo:
  2804.     cmp    [comp],1        ; is compression info empty rows?
  2805.     jne    @@putempty        ; if not, put empty row
  2806.     inc    [byte es:di]        ; one more empty row
  2807.     jmp    @@next
  2808.  
  2809.     ; store one empty row:
  2810. @@putempty:
  2811.     cmp    [comp],0        ; is there compression info?
  2812.     je    @@1            ; if yes, save space it
  2813.     inc    di
  2814.     mov    [comp],0        ; no compression info
  2815.  
  2816. @@1:    mov    [byte es:di],01111000b    ; one empty row
  2817.     mov    [lastOff],di        ; store destination pointer
  2818.     inc    di
  2819.     jmp    @@next
  2820.  
  2821.  
  2822.     ; there is a command:
  2823. @@cmd:
  2824.     cmp    [note],0        ; is there a note?
  2825.     jne    @@all
  2826.     cmp    [inst],0        ; or an instrument
  2827.     jne    @@all
  2828.  
  2829.     ; only a command:
  2830.     movzx    eax,[cmd]        ; eax = command
  2831.  
  2832.     cmp    [firstData],1        ; is this the first row?
  2833.     je    @@putcmd
  2834.     cmp    eax,[lastData]        ; is command same as the previous
  2835.     jne    @@putcmd        ; row? if not, store it
  2836.  
  2837.     ; this row has the same data as the previous one:
  2838.     mov    bx,[lastOff]
  2839.     test    [byte es:bx],80h    ; is there compression info?
  2840.     jne    @@cinfo2
  2841.  
  2842.     mov    [comp],2        ; compression - rows of same data
  2843.     or    [byte es:bx],80h    ; compression info follows
  2844.     mov    [byte es:di],01000001b    ; one same row
  2845.     jmp    @@next
  2846.  
  2847.     ; There was already compression info:
  2848. @@cinfo2:
  2849.     cmp    [comp],2        ; is compression info same data?
  2850.     jne    @@putcmd        ; if not, store this row
  2851.     inc    [byte es:di]        ; one more row of same data
  2852.     jmp    @@next
  2853.  
  2854.     ; store command and infobyte:
  2855. @@putcmd:
  2856.     cmp    [comp],0        ; is there compression info?
  2857.     je    @@2            ; if yes, save space for it
  2858.     inc    di
  2859.     mov    [comp],0
  2860. @@2:    mov    [lastData],eax        ; save this row data
  2861.     or    ax,0110000000000000b    ; there is only a command
  2862.     mov    [lastOff],di        ; store destination pointer
  2863.     xchg    ah,al
  2864.     stosw                ; store data
  2865.     jmp    @@next
  2866.  
  2867.  
  2868.  
  2869.     ; there is a note and an instrument with no command:
  2870.  
  2871. @@ncmd: movzx    eax,[note]
  2872.     shl    ax,8            ; eax = data for this row
  2873.     or    ax,[inst]
  2874.     shl    eax,16
  2875.  
  2876.     cmp    [firstData],1        ; is this the first row?
  2877.     je    @@putnote
  2878.     cmp    eax,[lastData]        ; is this row same as the previous?
  2879.     jne    @@putnote
  2880.  
  2881.     ; this row has the same data as the previous one:
  2882.     mov    bx,[lastOff]
  2883.     test    [byte es:bx],80h    ; is there compression info?
  2884.     jne    @@cinfo3
  2885.  
  2886.     mov    [comp],2        ; compression - rows of same data
  2887.     or    [byte es:bx],80h    ; compression info follows
  2888.     mov    [byte es:di],01000001b    ; one same row
  2889.     jmp    @@next
  2890.  
  2891.     ; There was already compression info:
  2892. @@cinfo3:
  2893.     cmp    [comp],2        ; is compression info same data?
  2894.     jne    @@putnote        ; if not, store this row
  2895.     inc    [byte es:di]        ; one more row of same data
  2896.     jmp    @@next
  2897.  
  2898.     ; store note and instrument:
  2899. @@putnote:
  2900.     cmp    [comp],0        ; is there compression info?
  2901.     je    @@3            ; if yes, save space for it
  2902.     inc    di
  2903.     mov    [comp],0
  2904. @@3:    mov    [lastData],eax        ; save this row data
  2905.     mov    ax,[note]
  2906.     shl    ax,5
  2907.     or    ax,[inst]
  2908.     or    ax,0111000000000000b    ; there is a note and instrument
  2909.     mov    [lastOff],di        ; save destination pointer
  2910.     xchg    ah,al
  2911.     stosw                ; store data
  2912.     jmp    @@next
  2913.  
  2914.  
  2915.     ; there is a note, instrument and command:
  2916. @@all:    movzx    eax,[note]
  2917.     shl    ax,8            ; eax = data for this row
  2918.     or    ax,[inst]
  2919.     shl    eax,16
  2920.     or    ax,[cmd]
  2921.  
  2922.     cmp    [firstData],1        ; is this the first row?
  2923.     je    @@putall
  2924.     cmp    eax,[lastData]        ; is this row same as the previous?
  2925.     jne    @@putall
  2926.  
  2927.     ; this row has the same data as the previous one:
  2928.     mov    bx,[lastOff]
  2929.     test    [byte es:bx],80h    ; is there compression info?
  2930.     jne    @@cinfo4
  2931.  
  2932.     mov    [comp],2        ; compression - rows of same data
  2933.     or    [byte es:bx],80h    ; compression info follows
  2934.     mov    [byte es:di],01000001b    ; one same row
  2935.     jmp    @@next
  2936.  
  2937.     ; There was already compression info:
  2938. @@cinfo4:
  2939.     cmp    [comp],2        ; is compression info same data?
  2940.     jne    @@putall        ; if not, store this row
  2941.     inc    [byte es:di]        ; one more row of same data
  2942.     jmp    @@next
  2943.  
  2944.     ; store note and instrument:
  2945. @@putall:
  2946.     mov    [lastData],eax        ; save this row data
  2947.  
  2948.     cmp    [comp],0        ; is there compression info?
  2949.     je    @@4            ; if yes, save space for it
  2950.     inc    di
  2951.     mov    [comp],0
  2952.  
  2953. @@4:    mov    [lastOff],di        ; store destination pointer
  2954.  
  2955.     mov    ax,[note]
  2956.     shl    ax,5            ; write note and instrument
  2957.     or    ax,[inst]
  2958.     shr    ax,4
  2959.     stosb
  2960.     mov    ax,[inst]
  2961.     shl    al,4
  2962.     or    al,[byte cmd+1]     ; command
  2963.     stosb
  2964.     mov    al,[byte cmd]        ; command infobyte
  2965.     stosb
  2966.  
  2967.  
  2968. @@next:
  2969.     ; go to next row:
  2970.     mov    [firstData],0        ; not the first row
  2971.     dec    [rowCount]
  2972.     jnz    @@rowloop
  2973.  
  2974.     cmp    [comp],0        ; was there compression info for
  2975.     je    @@nocomp        ; last data?
  2976.  
  2977.     inc    di            ; leave space for it
  2978.  
  2979. @@nocomp:
  2980.     sub    di,[word track]     ; calculate compressed length
  2981.  
  2982.     les    bx,[trackLen]
  2983.     mov    [es:bx],di        ; store compressed length in *trackLen
  2984.  
  2985.     xor    ax,ax            ; success
  2986.     jmp    @@done
  2987.  
  2988. @@error:
  2989.     mov    ax,errInvalidPatt    ; invalid pattern data
  2990.     ERROR    ID_modConvertTrack
  2991.  
  2992. @@done:
  2993.     ret
  2994. ENDP
  2995.  
  2996. END
  2997.  
  2998.  
  2999. ; MTM track conversion code: (removed)
  3000.  
  3001. ; MTM-Data coming
  3002.  
  3003. IF 0
  3004.  
  3005. @@mtm:    movzx    ax,[es:si]
  3006.     shr    ax,2
  3007.     mov    [note],ax
  3008.  
  3009.     mov    ax,[es:si]
  3010.     xchg    ah,al
  3011.     and    ax,03f0h
  3012.     shr    ax,4
  3013.     mov    [inst],ax
  3014.  
  3015.     mov    ax,[es:si+1]
  3016.     xchg    ah,al
  3017.     and    ax,0fffh
  3018.     mov    [cmd],ax
  3019.  
  3020.     add    si,3
  3021.     jmp    @@back
  3022. ENDIF
  3023.  
  3024.