?login_element?

Subversion Repositories NedoOS

Rev

Rev 746 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. ;TODO микшировать трек в фильтр
  2.  
  3. initplayer
  4.         ld a,1
  5.         ld (player_state),a
  6.         ret
  7.  
  8. player
  9.         ;di
  10.         ;jr $
  11. player_state=$+1
  12.         ld a,1
  13.         dec a
  14.         jr nz,player_playnote
  15.         call initnote
  16.         call untr_play_right
  17.         ld a,3
  18. player_playnote
  19.         ld (player_state),a        
  20.         jp playnote
  21.  
  22. checkeof
  23.         ld de,MAXTIME-1
  24.         or a
  25.         sbc hl,de
  26.         add hl,de
  27.         ret c
  28.         ld h,d
  29.         ld l,e
  30.         ret ;nc=eof, hl=eof time
  31.  
  32. untr_play_right
  33.         ld hl,(playtime)
  34.         call checkeof ;nc=eof
  35.         ret nc
  36.         inc hl
  37. playend=$+1
  38.         ld de,0
  39.         or a
  40.         sbc hl,de
  41.         add hl,de
  42.         jr nz,untr_play_right_noloop
  43. playbegin=$+1
  44.         ld hl,0
  45. untr_play_right_noloop
  46.         ld (playtime),hl
  47. nowplaying=$+1
  48.         ld a,0
  49.        or a
  50.        ret nz ;включено фоновое проигрывание
  51.         jr untr_right_ok ;только при проигрывании по Enter
  52. untr_right
  53.         ld hl,(curtime)
  54.         call checkeof ;nc=eof
  55.         ret nc
  56.         inc hl
  57.         ld (curtime),hl
  58. untr_right_ok
  59.         ex de,hl
  60.         ld hl,(lefttime)
  61.         ld bc,SCRTRACKWID
  62.         add hl,bc
  63.         ex de,hl ;de=lefttime+SCRTRACKWID
  64.         or a
  65.         sbc hl,de
  66.         add hl,de ;curtime < (lefttime+SCRTRACKWID)?
  67.         ret c
  68.         ld hl,(lefttime)
  69.         inc hl
  70.         ld (lefttime),hl
  71.         ret
  72.  
  73. ;A0gO123
  74.  
  75. ;bass, pad и tone имеют параметры:
  76. ;сэмпл
  77. ;громкость
  78. ;смещение в сэмпле
  79. ;рабочая октава
  80.  
  81. ;фильтр имеет параметры:
  82. ;тип фильтра (g=gain, Vv=vib, Ee=env(vib/gliss up/down), n=noise down)
  83. ;для вибрато: глубина (0=бесконечность, т.е. gliss)
  84. ;для вибрато: период
  85. ;для вибрато: скорость изменения
  86.  
  87. playnote
  88.         call setpgsamples
  89.         call playnote_tracksplaysample
  90.         call setpgroots
  91.  
  92.         ld a,2
  93.         call mixchn_all_channela
  94.         push iy ;chn для C ;если нет ни одного трека для канала, то нам вернули emptychn
  95.         ld a,1
  96.         call mixchn_all_channela
  97.         push iy ;chn для B ;если нет ни одного трека для канала, то нам вернули emptychn
  98.         ld a,0
  99.         call mixchn_all_channela
  100.         push iy ;chn для A ;если нет ни одного трека для канала, то нам вернули emptychn
  101.         pop ix ;chn для A
  102.         pop hl ;chn для B
  103.         pop de ;chn для C
  104.         ld iy,chip0 ;ix=fromA ;hl=fromB ;de=fromC ;iy=chip
  105.         call rendchip
  106.         call setchip0
  107.         ld hl,chip0
  108.         call outchip
  109.  
  110.         ld a,3+2
  111.         call mixchn_all_channela
  112.         push iy ;chn для C ;если нет ни одного трека для канала, то нам вернули emptychn
  113.         ld a,3+1
  114.         call mixchn_all_channela
  115.         push iy ;chn для B ;если нет ни одного трека для канала, то нам вернули emptychn
  116.         ld a,3+0
  117.         call mixchn_all_channela
  118.         push iy ;chn для A ;если нет ни одного трека для канала, то нам вернули emptychn
  119.         pop ix ;chn для A
  120.         pop hl ;chn для B
  121.         pop de ;chn для C
  122.         ld iy,chip1 ;ix=fromA ;hl=fromB ;de=fromC ;iy=chip
  123.         call rendchip
  124.         call setchip1
  125.         ld hl,chip1
  126.         call outchip
  127.        
  128.         ret
  129.  
  130.  
  131. inittracks
  132. ;настраивает треки по заданным параметрам
  133. ;в каналах с пустышкой включает паузу, форсирует ретриггер огибающей
  134.         ld a,0x80 ;точно не совпадёт, так что будет retrigenv
  135.         ld (chip0+chip.envtype),a
  136.         ld (chip1+chip.envtype),a
  137.  
  138.         ld iy,ttypes
  139.         ld ix,chns
  140.         ld a,(ntracks)
  141. inittrackspars0
  142.         ex af,af' ;'
  143.         ;ld a,(ix-2);(hl) ;chntype
  144.         ;inc a
  145.         ;jp z,inittrackspars0q
  146.         ld a,(iy+2) ;track type
  147.         ld c,CHNTYPE_ORDER
  148.         cp _O
  149.         jr z,inittrackspars_typeok
  150.         ld c,CHNTYPE_NOTES
  151.         cp _t
  152.         jr z,inittrackspars_typeok
  153.         ld c,CHNTYPE_SAMPLES
  154.         cp _d
  155.         jr z,inittrackspars_typeok
  156.         ld c,CHNTYPE_FILTER
  157. inittrackspars_typeok
  158.         ld a,(ix-2);(hl) ;chntype
  159.         xor c
  160.         and 0x80
  161.         xor c
  162.         ld (ix-2),a;(hl),a        
  163.          ld c,(iy+3) ;order (_O/0)
  164.          ld (ix-1),c;(hl),c
  165.          and CHNTYPEMASK
  166.          cp CHNTYPE_ORDER
  167.          jr z,inittrackspars0ok
  168.          cp CHNTYPE_FILTER
  169.          jr z,inittrackspars0filter
  170.         ld (ix+chn.oldnote_in),0 ;for gliss
  171.         ld a,(iy+0) ;channel
  172.         sub _A
  173.         ld (ix+chn.channel_in),a
  174.         ld a,(iy+1) ;priority
  175.         sub _0
  176.         ld (ix+chn.keepme_in),a
  177.         ld a,(iy+4) ;sample
  178.         ;add a,a
  179.         ;ld l,a
  180.         ;ld h,0
  181.         ;ld bc,tsamples
  182.         ;add hl,bc
  183.         ;ld c,(hl)
  184.         ;inc hl
  185.         ;ld b,(hl) ;TODO add sample offset (par2?)
  186.         add a,0x40
  187.         ld b,a
  188.         ld a,(iy+5) ;par2 ;sample offset
  189.         sub 1
  190.         adc a,0 ;space == '0'
  191.         ld c,a
  192.          ;jr nz,$
  193.         add a,a
  194.         add a,a
  195.         add a,a
  196.         sub c
  197.         ld c,a;0
  198.         ld (ix+chn.smp_in),c
  199.         ld (ix+chn.smp_in+1),b
  200.         ;ld a,(iy+5) ;par2
  201.         ;ld (ix+chn.par2_in),a
  202.         ld a,(iy+6) ;par3
  203.         ;ld (ix+chn.par3_in),a
  204.          sub 1+15
  205.         ld (ix+chn.volume_in),a
  206.         call initchnnote_pause ;устанавливает smpcuraddr паузы, выключает глисс
  207. inittrackspars0ok
  208.         ld bc,8
  209.         add iy,bc
  210.         ld bc,chnsstep
  211.         add ix,bc
  212.         ex af,af' ;'
  213.         dec a
  214.         jr nz,inittrackspars0
  215.         ret
  216. inittrackspars0filter
  217.         ld a,(iy+2) ;track type (filter type)
  218.         ld bc,filterhandler_vol
  219.         cp _g
  220.         jr z,inittrackspars_filtertypeok
  221.         ld bc,filterhandler_vib
  222.         cp _v
  223.         jr z,inittrackspars_filtertypeok
  224.         cp _V
  225.         jr z,inittrackspars_filtertypeok
  226.         ld bc,filterhandler_env
  227.         cp _e
  228.         jr z,inittrackspars_filtertypeok
  229.         cp _E
  230.         jr z,inittrackspars_filtertypeok
  231.         ld bc,filterhandler_noise
  232.         cp _n
  233.         jr z,inittrackspars_filtertypeok
  234.         ld bc,play_reter
  235. inittrackspars_filtertypeok
  236.         ld (ix+chn.handler),c
  237.         ld (ix+chn.handler+1),b
  238.         ld a,(iy+4) ;par1
  239.         ld (ix+chn.par1_in),a
  240.         ld a,(iy+5) ;par2
  241.         ld (ix+chn.par2_in),a
  242.         ld a,(iy+6) ;par3
  243.         ld (ix+chn.par3_in),a
  244.         jr inittrackspars0ok
  245.  
  246. initnote
  247. ;инициализирует ноты в каналах в процессе проигрывания
  248.         ld ix,chns
  249.         ld hy,0 ;track
  250. initnote0
  251.         ld a,(ix-2);(hl) ;chntype
  252.         ;inc a
  253.         ;ret z
  254.          and CHNTYPEMASK
  255.          cp CHNTYPE_FILTER;+1
  256.          jp z,initnotefilter;inittracks0skip
  257.          cp CHNTYPE_SAMPLES;+1
  258.          jp z,initnotesamples;inittracks0skip
  259.          cp CHNTYPE_ORDER;+1
  260.          jr z,initnote0skip
  261.         ld a,hy ;a=track
  262.         call peekplaytime_tracka
  263.         cp NOTE_SPACE
  264.         jr z,initnote0skip
  265.         cp NOTE_GLISS
  266.         ld c,(ix+chn.oldnote_in)
  267.         ld (ix+chn.oldnote_in),a
  268.         jr z,initnotegliss
  269. ;если ближайшая нота слева - глисс, то не переинициализировать сэмпл
  270.         dec a
  271.         ld (ix+chn.note_in),a
  272.         inc c
  273.         inc c ;cp NOTE_GLISS
  274.         ld d,c
  275.         ld e,c
  276.         jp z,initnoteglissq_de;initnotelegato ;de=0
  277.         ld de,smp_pause
  278.         cp NOTE_PAUSE-1
  279.         jr z,initnote0_pause
  280.         ld e,(ix+chn.smp_in)
  281.         ld d,(ix+chn.smp_in+1)
  282. initnote0_pause
  283.         call initchnnote_setsmpde_nogliss ;устанавливает сэмпл, как указано в канале, выключает глисс
  284. initnote0skip
  285.         ld bc,chnsstep
  286.         add ix,bc
  287.         inc hy ;track
  288.         ld a,(ntracks)
  289.         cp hy
  290.         jr nz,initnote0
  291.         ret
  292. initnotegliss
  293. ;найти ближайшую ноту справа - цель глисса
  294.         ld a,hy;(curtrack)
  295.         ld hl,(playtime)
  296.         push hl
  297.         call tracktime_totrackpartindex ;hl=index ;lx=part ;a=track
  298.         ex de,hl ;de=index
  299.         pop hl
  300.         or a
  301.         sbc hl,de ;beg=time-index (index=time-beg)
  302.        push hl ;beg
  303.         call getroot ;out: hl=root
  304. ;hl=track root (4 bytes: left poi, right poi)
  305. ;de=index
  306.         inc de ;не на месте, а только вправо
  307.         call findright ;out: de=nonempty index (or ffff), a=data
  308.        pop hl ;beg
  309.         add hl,de ;hl=righttime=index+beg (beg=time-index)
  310.         or a ;a=rightval
  311.         ld d,a
  312.         ld e,a
  313.         jr z,initnoteglissq ;de=0
  314.         ld de,(playtime)
  315.         ;or a
  316.         sbc hl,de ;hl=glisstime
  317.         ld d,h
  318.         ld e,l
  319.         add hl,hl
  320.         add hl,de ;*3 ;TODO умножить на темп
  321.        push hl ;hl=glisstime
  322. ;где взять glisshgt, она же зависит от рабочей октавы!!!??? рабочая октава в параметрах канала? (нельзя брать из первого фрейма сэмпла, т.к. там может быть всплеск! можно из текущего?)
  323. ;и как делать глисс на огибающей? отдельные поля chn? но где взять glisshgt, он же зависит от envsemitoneshift? (нельзя брать из первого фрейма сэмпла, т.к. там может быть всплеск! можно из текущего?)
  324.         push af
  325.         call setpgsamples
  326.         pop af
  327.         ld l,(ix+chn.smpcuraddr)
  328.         ld h,(ix+chn.smpcuraddr+1)
  329.         inc hl ;skip mask
  330. ;вычисляем частоту будущей ноты
  331.        dec a
  332.         add a,(hl) ;semitone shift
  333.         jp po,initnotegliss_nosemitoneshift2 ;no signed overflow
  334.         rla
  335.         sbc a,a ;a=0 for negative overflow, a=255 for positive overflow
  336.         xor 0x80 ;a=-128 for negative overflow, a=127 for positive overflow
  337. initnotegliss_nosemitoneshift2
  338.         ld c,a
  339.         ld b,tfrq/256
  340.         ld a,(bc)
  341.         ld e,a
  342.         inc b
  343.         ld a,(bc)
  344.         ld d,a ;hl=частота будущей ноты
  345. ;вычисляем частоту текущей ноты
  346.         ld a,(ix+chn.note_in)
  347.         add a,(hl) ;semitone shift
  348.         jp po,initnotegliss_nosemitoneshift ;no signed overflow
  349.         rla
  350.         sbc a,a ;a=0 for negative overflow, a=255 for positive overflow
  351.         xor 0x80 ;a=-128 for negative overflow, a=127 for positive overflow
  352. initnotegliss_nosemitoneshift
  353.         ld c,a
  354.         ld a,(bc)
  355.         ld h,a
  356.         dec b
  357.         ld a,(bc)
  358.         ld l,a ;hl=частота текущей ноты
  359.         ex de,hl
  360.         or a
  361.         sbc hl,de ;hl=частота будущей ноты - частота текущей ноты
  362.         call setpgroots
  363.        pop de ;de=glisstime
  364.         call divsignedfixedpoint3 ;hl = hl/de = +-12./16. = +-12.3
  365.         ex de,hl ;de = glissspeed_in = glisshgt/glisstime = +-12./16. = +-12.3
  366. initnoteglissq
  367. initnoteglissq_de
  368.         xor a
  369.         ld (ix+chn.curgliss),a
  370.         ld (ix+chn.curgliss+1),a
  371.         ld (ix+chn.glissspeed_in),e
  372.         ld (ix+chn.glissspeed_in+1),d
  373.         jr initnote0skip
  374.        
  375. initnotesamples
  376.         ld a,hy ;a=track
  377.         call peekplaytime_tracka
  378.         or a
  379.         jp z,initnote0skip ;SPACE
  380.         ld (ix+chn.note_in),3*12 ;C-4
  381.         ;add a,a
  382.         ;ld l,a
  383.         ;ld h,0
  384.         ;ld bc,tsamples
  385.         ;add hl,bc
  386.         ;ld c,(hl)
  387.         ;inc hl
  388.         ;ld b,(hl)
  389.         add a,0x40
  390.         ld b,a
  391.         ld c,0
  392.         ld (ix+chn.smpcuraddr),c
  393.         ld (ix+chn.smpcuraddr+1),b
  394.         jp initnote0skip
  395.        
  396. initnotefilter
  397.          ;ld a,hx
  398.          ;or a
  399.          ;jp z,initnote0skip ;когда фильтр по ошибке стоит выше любого канала
  400. ;ищем ближайшее число слева (или на месте) и ближайшее число справа
  401. ;(если справа ничего нет, то такое же число, как слева)
  402. ;текущее значение для фильтра - это линейная интерполяция между ними
  403. ;k = (playtime-lefttime)/(righttime-lefttime)
  404. ;val = leftval + k*(rightval-leftval)
  405.         ld a,hy;(curtrack)
  406.         ld hl,(playtime)
  407.         push hl
  408.         call tracktime_totrackpartindex ;hl=index
  409.         ex de,hl ;de=index
  410.         pop hl
  411.         or a
  412.         sbc hl,de ;beg=time-index (index=time-beg)
  413.        push hl ;beg
  414.        push de ;de=index
  415.        push hl ;beg
  416.         ld a,hy;(curtrack)
  417.         call getroot ;out: hl=track root (4 bytes: left poi, right poi)
  418.         call findleft ;de=index ;out: de=nonempty index (or 0), a=data
  419.        pop hl ;beg
  420.         add hl,de ;hl=lefttime=index+beg (beg=time-index)
  421.         ld (initnotefilter_lefttime),hl
  422.         or a ;a=leftval
  423.         jr nz,$+4
  424.          ld a,1+15 ;"f"
  425.         ld (initnotefilter_leftval),a
  426.        pop de ;de=index
  427.         ld a,hy;(curtrack)
  428.         call getroot ;out: hl=root
  429. ;hl=track root (4 bytes: left poi, right poi)
  430. ;de=index
  431.         inc de ;не на месте, а только вправо
  432.         call findright ;out: de=nonempty index (or ffff), a=data
  433.        pop hl ;beg
  434.         add hl,de ;hl=righttime=index+beg (beg=time-index)
  435.         or a ;a=rightval
  436.          jr nz,$+5
  437.          ld a,(initnotefilter_leftval)
  438.         push af ;ld (rightval),a
  439. initnotefilter_lefttime=$+1
  440.         ld bc,0
  441.         ;or a
  442.         sbc hl,bc ;righttime-lefttime
  443.         ex de,hl ;de=righttime-lefttime
  444.         ld hl,(playtime)
  445.         or a
  446.         sbc hl,bc ;hl=playtime-lefttime
  447.         call divlessthan1 ;out: k = bc = hl / de (.16) = (playtime-lefttime)/(righttime-lefttime)
  448.         pop af ;rightval
  449. initnotefilter_leftval=$+1
  450.         ld e,0
  451.         sub e
  452.         call mulsigned8bylessthan1 ;a = +-a*bc = k*(rightval-leftval)
  453.         add a,e ;a = val = leftval + k*(rightval-leftval)
  454.         ld (ix+chn.curvalue),a
  455.         jp initnote0skip
  456.  
  457. mulsigned8bylessthan1
  458. ;a = +-a*bc
  459.         rla
  460.         jr nc,mul8bylessthan1
  461.         neg
  462.         call mul8bylessthan1
  463.         neg
  464.         ret
  465. mul8bylessthan1
  466.         ld hl,0
  467.         dup 7
  468.         srl b
  469.         rr c
  470.         rla
  471.         jr nc,$+3
  472.         add hl,bc
  473.         edup
  474.         ld a,h
  475.         srl a
  476.         ret
  477.  
  478. playnote_tracksplaysample
  479.         ld ix,chns
  480.         ld hy,0
  481. playnote_tracksplaysample0
  482.         ld a,(ix-2);(hl) ;chntype
  483.         ;inc a
  484.         ;ret z
  485.          and CHNTYPEMASK
  486.          cp CHNTYPE_FILTER;+1
  487.          jr z,playnote_filter
  488.          cp CHNTYPE_ORDER;+1
  489.         ;jr z,playnote_tracksplaysample0skip
  490.         call nz,playsample
  491. playnote_tracksplaysample0skip
  492.         ld bc,chnsstep
  493.         add ix,bc
  494.         inc hy
  495.         ld a,(ntracks)
  496.         cp hy
  497.         jr nz,playnote_tracksplaysample0
  498.         ret
  499. playnote_filter
  500. ;bc=filter addr
  501.          ;ld a,hx
  502.          ;or a
  503.          ;jr z,playnote_tracksplaysample0skip ;т.е. фильтр по ошибке стоит выше любого канала
  504.         push ix
  505.         ld l,(ix+chn.handler)
  506.         ld h,(ix+chn.handler+1)
  507.         ld b,(ix+chn.par1_in)
  508.         ld c,(ix+chn.par2_in)
  509.         ld d,(ix+chn.par3_in)
  510.         ld e,(ix+chn.curvalue)
  511.         push bc
  512.         ld bc,-chnsstep
  513.         add ix,bc
  514.         pop bc
  515.         call jphl
  516.         pop ix
  517.         jr playnote_tracksplaysample0skip
  518.  
  519. jphl
  520.         jp (hl)
  521.  
  522. mixchn_all_channela
  523. ;a=channel=0..5
  524. ;out: iy=chn, куда всё смикшировалось
  525. ;микшируем сверху вниз все подканалы, у которых канал == a
  526.          ld (mixchn_all_channela_a),a
  527.         ld iy,0
  528.         ld ix,chns
  529.         ld a,(ntracks)
  530. mixchn_all_channela0
  531.         ex af,af' ;'
  532.         ld a,(ix-2);(hl) ;chntype
  533.         ;inc a
  534.         ;jr z,mixchn_all_channelaq
  535.          and CHNTYPEMASK
  536.          cp CHNTYPE_FILTER;+1
  537.          jr z,mixchn_all_channela0skip
  538.          cp CHNTYPE_ORDER;+1
  539.         jr z,mixchn_all_channela0skip
  540. mixchn_all_channela_a=$+1
  541.         ld a,0
  542.         cp (ix+chn.channel_in)
  543.         jr nz,mixchn_all_channela0skip
  544.         ld a,hy
  545.         or ly
  546.         jr z,mixchn_all_channela0_first ;первый подходящий трек попадает в first
  547.         call mixchn ;iy+ix микшируем в iy
  548.         jr mixchn_all_channela0_firstq
  549. mixchn_all_channela0_first
  550.         push ix
  551.         pop iy
  552. mixchn_all_channela0_firstq
  553. mixchn_all_channela0skip
  554.         ld bc,chnsstep
  555.         add ix,bc
  556.         ex af,af' ;'
  557.         dec a
  558.         jr nz,mixchn_all_channela0
  559. ;mixchn_all_channelaq
  560.         ld a,hy
  561.         or ly
  562.         ret nz
  563.         ld iy,emptychn ;не найдено ни одного трека для этого канала
  564.         ret
  565.  
  566. initchnnote_pause
  567.         ld de,smp_pause
  568. initchnnote_setsmpde_nogliss
  569.         ld (ix+chn.smpcuraddr),e
  570.         ld (ix+chn.smpcuraddr+1),d
  571.         xor a
  572.         ld (ix+chn.curgliss),a
  573.         ld (ix+chn.curgliss+1),a
  574.         ld (ix+chn.glissspeed_in),a
  575.         ld (ix+chn.glissspeed_in+1),a
  576.         ret
  577.  
  578. divlessthan1
  579. ;out: bc = hl / de (0.16)
  580.         ld b,8
  581. divlessthan10.
  582.         add hl,hl ;no carry
  583.         sbc hl,de
  584.         jr nc,$+3
  585.         add hl,de
  586. ;carry = inverted bit of result
  587.         rla
  588.         djnz divlessthan10.
  589.         cpl
  590.         ld c,a
  591.         ld b,8
  592. divlessthan11.
  593.         add hl,hl ;no carry
  594.         sbc hl,de
  595.         jr nc,$+3
  596.         add hl,de
  597. ;carry = inverted bit of result
  598.         rla
  599.         djnz divlessthan11.
  600.         ld b,c
  601.         cpl
  602.         ld c,a
  603.         ret
  604.  
  605. divsignedfixedpoint3
  606. ;hl / de
  607. ;out: hl
  608. ;+-12./16. = +-12.3
  609. ;домножаем делимое на 8 и делим нацело
  610.         add hl,hl
  611.         add hl,hl
  612.         add hl,hl
  613. ;divsignedhl_de
  614.         bit 7,h
  615.         jr z,_DIV.
  616.         xor a
  617.         sub l
  618.         ld l,a
  619.         sbc a,h
  620.         sub l
  621.         ld h,a
  622.         call _DIV.
  623.         xor a
  624.         sub l
  625.         ld l,a
  626.         sbc a,h
  627.         sub l
  628.         ld h,a
  629.         ret
  630. ;hl / de
  631. ;out: hl
  632. ;работает так: hl.ca - de и т.д.
  633. _DIV.
  634.         ld c,h
  635.         ld a,l
  636.         ld hl,0
  637.         ld b,16
  638. ;don't mind carry
  639. _DIV0.
  640. ;shift left hlca
  641.         rla
  642.         rl c
  643.         adc hl,hl ;no carry
  644.         sbc hl,de
  645.         jr nc,$+3
  646.         add hl,de
  647. ;carry = inverted bit of result
  648.         djnz _DIV0.
  649.         rla
  650.         cpl
  651.         ld l,a
  652.         ld a,c
  653.         rla
  654.         cpl
  655.         ld h,a
  656. play_reter
  657.         ret
  658.