home *** CD-ROM | disk | FTP | other *** search
/ Acorn User 7 / AU_CD7.iso / _movies / _armovie / documents / tousesound < prev   
Text File  |  1994-01-31  |  24KB  |  526 lines

  1.             Using Replay Sound Code
  2.             =======================
  3.  
  4. When sound compression field is 1, there are 10 different sound formats
  5. currently available for Replay:
  6.  
  7. 4bit: mono and stereo 4 bit ADPCM               SoundA4, SoundA4x2 
  8.  
  9. 8bit: mono and stereo 8 bit linear signed       SoundS8, SoundS8x2
  10.                             linear unsigned     SoundU8, SoundU8x2
  11.                             exponential (uLaw)  SoundE8, SoundE8x2
  12.  
  13. 16bit: mono and stereo 16 bit linear signed     SoundS16, SoundS16x2
  14.  
  15. When sound compression field is 2, the actual name of the sound decompressor
  16. follows the field; for example '2 ADPCM' would provide a new format which used
  17. the decompressor components in ADPCM: this is a directory in
  18. <ARMovie$SoundDir>.
  19.  
  20. For all formats, there is an appropriate piece of machine code which can be
  21. called to play the format directly. For format 2 there is a set of resources
  22. which can be used to play, compress and decompress the sound data, though only
  23. some of these may be present. These are all stored in the named directory
  24. inside <ARMovie$SoundDir>. A full implementation of a format 2 system would
  25. look like:
  26.  
  27. ADPCM.Play                       play the data out of the computer
  28.       Playx2                     ditto, but stereo
  29.       Playx???                   extra files possible for more channels
  30.       To16                       convert data to 16 bit linear signed
  31.       From16                     convert data from 16 bit linear signed
  32.       Info                       find out information on the format
  33.  
  34. Only the Play (or Playx2) and Info files are essential. The Info file
  35. contains the following:
  36.  
  37. line 1: name of compression
  38.      2: copyright details
  39.      3: if 0, decompression can only start at beginning of chunk;
  40.         if 1, decompression can start at any sample in chunk;
  41.         other values reserved.
  42.      4: n: buffer size multiplier - how many bits of storage per sample the
  43.         Play program needs to work: see section (3).
  44.      5: if 0, compression is in fixed ratio (i.e. constant bits/sample); if
  45.         1, compression ratio is variable (but bounded). See section (10).
  46.      6: c: maximum size of a compressed sample, in bits. This is a real (not
  47.         just integer) number, since some schemes may use fractional bits; but
  48.         if a whole number, no `.' or `.0' is needed. See section (10).
  49.      7: m: constant (header/framing) overhead for From16 destination buffer,
  50.         per channel, in bytes (an integer). See section (10).
  51. line 8: //more data if required...
  52.  
  53. (1) getting the right piece of code.
  54.  
  55. The Replay movie header contains textual information which is used to deduce
  56. the format of the data and thus which of the sound code files to use. The
  57. Replay MovingLines sound files should be used only if the sound type is 1 or 2.
  58. In format 2, the file header gives the exact name of the decompressor directory
  59. to use: add the string 'Play' and the number of tracks.
  60.  
  61. For format 1, the SoundA/SoundS/SoundU/SoundE comes from the comments in the
  62. bits per sample field: if the text fragment ADPCM (in any case) is present,
  63. then SoundA; if LIN, then if UNSIGN then SoundU else SoundS; otherwise SoundE.
  64. 4/8/16 bits comes directly from the ARMovie header's bits per sample field.
  65.  
  66. Mono/Stereo is easy: the number of channels in the ARMovie header is 1 for mono
  67. (no suffix on the file name) and 2 for stereo (suffix x2 on the file name).
  68.  
  69. Stereo data for both formats 1 and 2 may be in normal left/right sense, or
  70. reversed: it is reversed if the sound channels field contains REVER (in any
  71. case).
  72.  
  73. To play the desired track, the information for the correct fields must be
  74. extracted! The following BASIC fragment extracts a field from a string j$ for a
  75. desired track I%:
  76.  
  77. DEF FNa(j$,I%)
  78. IFI%>1 j$=MID$(j$,INSTR(j$,"|"+STR$I%)+LENSTR$I%+2)
  79. IFINSTR(j$,"|") j$=LEFT$(j$,INSTR(j$,"|")-1)
  80. =j$
  81.  
  82. Assuming an uppercasing function FNuc, then the following is correct code to
  83. find the name of the sound file for track 'track%' from an ARMovie opened as
  84. 'file%' reading from :
  85.  
  86. FORI%=1TO9:a$=GET$#file%:NEXT:       REM ignore video header
  87.  
  88. snd$=FNa(GET$#file%,track%):snd%=VALsnd$:REM sound compression
  89. IFsnd%=1 OR snd%=2 THEN
  90.  REM safe to read all the other stuff...
  91.  sndrep=VALFNa(GET$#file%,track%):   REM sound replay rate (fp value)
  92.  lin$=FNa(GET$#file%,track%):        REM sound channels
  93.  reversed%=FALSE:IFINSTR(FNuc(lin$),"REVER") reversed%=TRUE
  94.  channels%=VALlin$:                  REM channels variable
  95.  lin$=FNa(GET$#file%,track%):        REM sound precision/linear
  96.  sndbits%=VALlin$:                   REM sound precision
  97.  sndmul%=8:                          REM default value for storage
  98.  IFsnd%=1 THEN
  99.   IFsndbits%=16 OR INSTR(FNuc(lin$),"LIN") THEN
  100.    IFINSTR(FNuc(lin$),"UNSIGN") lin$="U" ELSE lin$="S"
  101.   ELSE
  102.    IFsndbits%=4 OR INSTR(FNuc(lin$),"ADPCM") THEN
  103.     lin$="A":sndmul%=16
  104.    ELSE
  105.     lin$="E"
  106.    ENDIF
  107.   ENDIF
  108.   lin$+=STR$sndbits%
  109.   lin$="Sound"+lin$:      REM lin$ is now the name of the sound decompressor
  110.  ELSE
  111.   lin$=MID$(snd$,3)+" ":              REM format asserts this is OK!
  112.   lin$=LEFT$(lin$,INSTR(lin$," ")-1)
  113.   f2info%=OPENIN(<ARMovie$SoundDir>."+lin$+".Info"):IFf2info% THEN
  114.    snd$=GET$#f2info%:REM name
  115.    snd$=GET$#f2info%:REM copyright
  116.    snd$=GET$#f2info%:REM 0/1
  117.    sndmul%=VALGET$#f2info%: REM bits per sample
  118.    CLOSE#f2info%
  119.   ENDIF
  120.   lin$+=".Play"
  121.  ENDIF
  122.  IFchannels%>1 lin$+="x"+STR$channels%
  123.  
  124. Now 'lin$' contains the suffix for the sound file name and a variable 'sndmul%'
  125. contains the number of bits per output sample required for decompression (for
  126. format 1, this is 8 or 16 depending on ADPCM - for which the decompression
  127. buffer needs to be larger than the sample buffer supplied). Variables
  128. 'reversed%', 'channels%', 'sndbits%' and 'sndrep' will be needed!
  129.  
  130. (2) loading the code.
  131.  
  132. The various sound code files are stored as "<ARMovie$SoundDir>."+lin$ and have
  133. different sizes: enough memory should be allocated to load the particular file:
  134. each file is position independant code which can be loaded into RMA memory or
  135. into application memory (from where it must not be multi-tasked out until
  136. finished with!). An array of entry points is at the beginning of the code. 
  137.  
  138. When a sound file (at least, one which drives the internal sound system) has
  139. been loaded it needs to establish the particular clock rate of the VIDC chip:
  140. this will usually be 24MHz, but may be 25.175MHz (VGA) or other frequencies if
  141. a 'VIDC enhancer' is in use. Therefore it is started playing silently,
  142. recording the sound interrupts. After a while the time and number of sound
  143. interrupts can be used to calculate the VIDC clock rate. A control state is
  144. passed in r0 and the address of a control block in r1. The size of the control
  145. block is 64 bytes (older versions of the sound code used just 8 bytes). The
  146. name mute% used below is historical: one of the control functions of the first
  147. word of the block is muting of sound during play.
  148.  
  149.  REM does it exist? how large is it?
  150.  SYS"OS_File",17,"<ARMovie$SoundDir>."+lin$ TO r0%,,,,r4%
  151.  IFr0%<>1 ERROR 1,"Sound playback code "+lin$+" not found"
  152.  DIM sndcode% r4%-1,mute% 63: REM get memory for the sound code and control block
  153.  SYS"OS_File",16,"<ARMovie$SoundDir>."+lin$,sndcode%: REM load it
  154.  
  155.  SOUND ON:REM configure the sound system to defaults
  156.  SYS"Sound_Configure" TO oldchan%,,oldspeed%
  157.  
  158.  REM symbols for the entry points
  159.  sndplay%=sndcode%:            REM play the sound or start VIDC timing test.
  160.  sndstop%=sndplay%+4:          REM stop playing the sound
  161.  snddata%=sndstop%+4:          REM give data to be played
  162.  sndcounter%=snddata%+4:       REM count address
  163.  sndifflags%=sndcounter%:      REM sound interface flags (see below)
  164.  sndbuffer%=sndcounter%+4:     REM buffer address: 2 words
  165.  sndpause=mute%+4:             REM if 0 pause when sound data runs out, if
  166.                                    non-zero don't pause
  167.  
  168. When calling via sndplay%, the value in R0 is key to operation of the sound
  169. code.
  170.  
  171. If R0 on the call is 0 then it's an old style timing check and the sound code
  172. will from then on assume that old code is calling it and will operate in a mode
  173. which is compatible with such code. Do not use this value in new code.
  174.  
  175. If R0 on call is >= 0x10000 then it is a compatibility mode play call (and R0
  176. must have been 0 on the preceding sndplay% timing call); in this case it will
  177. start playing with R0 as the sample rate conversion fixed-point interpolation
  178. fraction (in 8.24 format), and R1 assumed to point at a 2 word control block,
  179. where the first word controls muting/stopping of the sound and the second is
  180. used to determine the treatment of data underrun - see section (4).
  181.  
  182. If R0 = 1 or 2 then it is respectively a new-style timing check or play call.
  183. R1 points at an information block. The first two words of this block have the
  184. same meaning as with old-style calls. For the play call, R1 is assumed to point
  185. at a 16-word information block (format given below) which tells the sound code
  186. what it needs to know: the contents of this block are maintained partly by the
  187. caller, partly by the sound code. Certain parts must be be initialised by the
  188. caller (see below) before the first play call.
  189.  
  190. Values of R0 between 3 and 0xFFFF inclusive are currently reserved and must not
  191. be used.
  192.  
  193. The values to initialise the control block (pointed at by mute% in this example
  194. code) are as follows:
  195.  
  196.         REM mute%!0 is global flags word (caller-maintained)
  197.         mute%!0 = 0:  REM clear all flags
  198.  
  199.         REM mute%!4 is soundpause flag: see section (5)
  200.  
  201.         REM mute%!8 and !12 are the source sample frequency, as a 32.24
  202.         REM fixed-point unsigned number, measured in Hz.
  203.  
  204. This initialisation must be done before the sndplay% call to start playing the
  205. data. It can also be done anytime earlier (obviously!) as convenient.
  206.  
  207. The value sndrep (a real +ve quantity) taken from the Replay file header, is
  208. the sample frequency in Hz if >= 256.0, or sample period in usec if < 256.0 We
  209. need the frequency form here.
  210.  
  211.         sfr = sndrep: IF sfr <= 255 THEN sfr = 1E6/sfr
  212.         mute%!8 = INT(sfr):                     REM whole part of frequency
  213.         mute%!12 = (1<<24) * (sfr - INT(sfr)):   REM fractional part, to 24 bits
  214.  
  215.         REM mute%?16 is requested quality flag, treated as an unsigned byte.
  216.  
  217. Defined quality range is 1..4 (1=lowest quality .. 4=highest). It is up to the
  218. caller to put in a 'suitable' value. It is up to the sound code as to what to
  219. do with this.
  220.  
  221. As an aid in making the decision, bit 1 of !sndifflags% (only well-defined once
  222. the initial (timing) sndplay% call has returned) provides a hint from the sound
  223. code. It is used to indicate whether quality is `free', or whether it has a
  224. significant cost in terms of cpu or bus bandwidth. If set, there is a
  225. significant cpu cost factor in using higher quality levels, over and above the
  226. normal cost of simply moving the original data around once (or perhaps twice)
  227. at its natural sample rate.
  228.  
  229. Some sound hardware may be flexible and/or powerful enough to keep the ARM
  230. processing cost to little more than moving the base-rate data around, in which
  231. case !sndifflags% AND 2 would be 0, and the caller would in general then set
  232. the quality level to 4 (or perhaps allowing user choice if appropriate). 
  233.  
  234. In other cases the sound code may use more cpu cycles and/or memory-bandwidth
  235. with increasing quality factor, so the caller may therefore choose an
  236. appropriate quality factor after consideration of the available performance of
  237. the processor/memory system in use (clock speed(s), bus rates, cache, etc), and
  238. also with regard to the demands of any video data processing which may be going
  239. on.
  240.  
  241. For internal (VIDC) sound, this bit is set, since oversampling is used (with
  242. the factor determined by the quality level), and the processor must therefore
  243. deal with more and more generated data at higher quality levels, for the same
  244. source sample rate. The quality value controls the output sample rate used: 1:
  245. 13.889kHz (72usec), 2: 20.833kHz (48usec) 3: 31.250kHz (32usec) 4: 41.667kHz
  246. (24usec); value 0 is treated as 1, values >4 are treated as 4. However, if the
  247. basic source sample rate is over 14.0 kHz and the quality level is 1, then
  248. 48usec is used, to avoid too much noise from the implied undersampling.
  249.  
  250.         mute%?16 = 4: REM (using highest quality in this example)
  251.  
  252. There is one remaining item defined in the control block:
  253.  
  254.         REM mute%?17 is stereo channel ordering: 0 (norm) is {L,R}, 1 is {R,L}. 
  255.         REM In mono case, value is ignored by sound code.
  256.         mute%?17 = reversed% AND 1
  257.  
  258. All the remaining bytes in the control block must be zero, for now.
  259.  
  260.         REM Clear remaining control words, for future expandability.
  261.         FOR I% = 18 TO 63: mute%?I% = 0: NEXT
  262.  
  263. The first call on the sound code is a timing call, via sndplay%:
  264.  
  265.  REM start sound timing check
  266.  !mute%=0: A%=1: B%=mute%:sndtime%=TIME:CALLsndplay%:sndtime%=TIME
  267. [ old code:
  268.  !mute%=0: A%=0: B%=mute%:sndtime%=TIME:CALLsndplay%:sndtime%=TIME
  269. ]
  270.  
  271.  REM if something goes wrong from now on, then this is how to put it back
  272.  ON ERROR CALLsndstop%:REPORT:PRINT" at line ";ERL:END
  273.  
  274. The purpose of the timing call is to allow for variable rate master clocks used
  275. to drive the sound output sample rate. This problem is only relevant on
  276. VIDC1-based systems, some of which have VIDC-enhancer (multiple video clock)
  277. circuitry, either as standard or as a hardware enhancement: the video and sound
  278. clocks are linked within VIDC1. However, the sound code may know (or be able to
  279. work out) that the master clock driving the sound sample rate does not vary
  280. with video mode, e.g. it might actually be driving separate sound output
  281. hardware (not linked to VIDC), or be driving VIDC20 which has a separate sound
  282. clock input.
  283.  
  284. Normally (for current and old machines), the master clock for the sound may be
  285. variable according to video mode, so the timing test needs to go on for a
  286. while: the timing will be accurate enough after 1 second. In this case,
  287. initialise other parts of the system or calculate or whatever, in the
  288. intervening time.
  289.  
  290. If the master sound clock rate does not vary with video mode, then the sound
  291. code will set bit 0 of !sndifflags% during the initial sndplay% timing call.
  292. Hence the calling code can do the sndstop% call (still necessary) whenever
  293. it wishes, and does not need to wait for the normal minimum of a whole
  294. second. See code in section (4).
  295.  
  296. Once the timing test has been performed, the sound code will have worked out
  297. the current sound master clock rate, and will keep a record of this (but see
  298. next paragraph). It will discard the information if another timing test call
  299. is made, since it does not itself know when the video mode changes. It is up
  300. to the caller to know that the video mode has been (or might have been)
  301. changed, and hence to re-do the timing test. Conversely, the timing test
  302. does not need to be redone (provided that the same sound code module remains
  303. resident, untouched) if the caller is sure that the video clock frequency
  304. has not been changed, or if the sound master clock rate is independent of
  305. video mode, as may be indicated on the first timing call. However, the
  306. timing test MUST be done at least once after loading new sound code.
  307.  
  308. For internal VIDC sound (which is expected to be the only sound output type
  309. for which the timing may vary with video mode), the timing check cannot be
  310. done if sound is globally disabled (via *audio off or the Sound_Enable SWI),
  311. since no sound DMA interrupts then occur. Hence, after the initial timing
  312. test sndplay% call has returned, if bit 0 of !sndifflags% is not set (and
  313. therefore the sound timing is potentially variable with video mode), bit 2
  314. should also be checked. If this is set, it identifies the fact that the
  315. internal sound system was found to be globally disabled. This has two
  316. consequences: (a) no sound will be output during the subsequent sound
  317. playing time (the data passed to snddata% calls will just be thrown away);
  318. (b) the sound code cannot determine the master clock frequency, and so
  319. cannot record it - therefore the timing test must be performed again, each
  320. time sound is to be played, until the global sound system is finally 
  321. re-enabled.
  322.  
  323. (3) setting up the sound buffers.
  324.  
  325. The sound play code needs 2 buffers of the duration of the sample chunk size -
  326. i.e. 'maximum possible number of samples in a sound chunk'*'sndmul%'/8 plus
  327. some space for semaphore flags: another 16 bytes - all word aligned. Compute
  328. the maximum number of samples in a sound chunk by reading the ARMovie 'sndrep'
  329. sound repetition rate variable, the 'frames per chunk' and the 'frames per
  330. second' variables and add 1% of this number of samples to allow for variations
  331. in capture programs. Then allocate the buffers, and in each set the word at
  332. byte offset 4 to 1 to signal them being empty and set !sndbuffer% and
  333. sndbuffer%!4 to the addresses:
  334.  
  335.  IFsndrep<256 THEN
  336.   Z%=(fpf/fps*(1E6/sndrep)*channels%*1.01*sndmul%+7)DIV8+12+4+3ANDNOT3
  337.  ELSE
  338.   Z%=(fpf/fps*sndrep*channels%*1.01*sndmul%+7)DIV8+12+4+3ANDNOT3
  339.  ENDIF
  340.  DIM sndbA% Z%-1,sndbB% Z%-1
  341.  sndbA%!4=1:sndbB%!4=1
  342.  !sndbuffer%=sndbA%:sndbuffer%!4=sndbB%
  343.  
  344. Obviously this can be done at any time, but it is something to do while the
  345. sound playback timing test is being performed.
  346.  
  347. (4) calculating the system sound clock frequency.
  348.  
  349. This is now done (if necessary) by the sound code itself, either on the
  350. sndstop% call after the timing test, or in the subsequent sndplay% call.
  351. Applications using the sound code in the new standard mode only need to stop
  352. the timing check. Floating point is used, so the FPEmulator (or whatever is
  353. providing ARM FP instructions) should be present.
  354.  
  355.  REM Wait for the rest of the second since starting the timing 
  356.  REM check, if required, to ensure timing accuracy.
  357.  IF (!sndifflags% AND 1) = 0 THEN
  358.    REPEAT UNTIL TIME-sndtime%>99
  359.  ENDIF
  360.  
  361.  REM stop the timing check
  362.  CALLsndstop%:sndtime%=TIME-sndtime%
  363.  
  364. [For old code, after the requisite second, the sound play code was stopped and
  365. the VIDC clock frequency calculated. The following code computes the frequency
  366. and also 'snaps' values near to 25.175MHz or an integral number of MHz to those
  367. numbers:
  368.  
  369.  IFsndcounter%!12 sndfreq=sndcounter%!16/sndcounter%!12*sndcounter%!20*24 ELSE sndfreq=24
  370.  C%=sndfreq+.5
  371.  IFsndfreq>.998*25.175 IFsndfreq<1.002*25.175 sndfreq=25.175
  372.  IFC%*1.002>sndfreq IFC%*.998<sndfreq sndfreq=C%
  373.  
  374. 'sndfreq' is the VIDC clock rate. The sound code uses a fixed point number to
  375. express the ratio faster or slower to play the sample:
  376.  
  377.  sndratio%=24/sndfreq*(1<<24)
  378.  
  379. gives 'sndratio%' which will be used to cause the sound code to play the sample
  380. at the correct rate.]
  381.  
  382. (5) configuring the system for playing the sound.
  383.  
  384. Most of this is done by the sound code itself, during the main sndplay% call
  385. (see section (7) below), using information in the block pointed to by R1 on
  386. that call.
  387.  
  388. [In old code, the RISC OS sound system had to be configured by the caller to
  389. play the sound properly: this requires selecting the right number of channels,
  390. and the right basic sound sample rate. Oversampling (selecting a higher play
  391. rate than the sample was recorded at) improves the sound at the cost of greater
  392. processing (more cpu cycles used): the variable 'slow%' is TRUE for a slow
  393. machine. The 'sndrep' value is taken to mean a period in uS if less than 256 or
  394. a frequency in Hz if greater.
  395.  
  396.  IFsndrep>255 THEN
  397.   sndrep=sndrep*speed
  398.   sndplayrate%=24:IFslow% sndplayrate%=72
  399.   SYS"Sound_Configure",channels%,0,sndplayrate%
  400.   sndratio%=sndratio%*(sndplayrate%/(1E6/sndrep))
  401.  ELSE
  402.   sndrep=sndrep/speed
  403.   IFslow% OR sndrep<48 THEN
  404.    SYS"Sound_Configure",channels%,0,sndrep
  405.   ELSE
  406.    SYS"Sound_Configure",channels%,0,sndrep DIV3
  407.    sndratio%=sndratio%DIV3
  408.   ENDIF
  409.  ENDIF
  410.  IFchannels%=1 THEN
  411.   SYS"Sound_Stereo",1,0:REM mono in the middle
  412.  ELSE
  413.   IFreversed% THEN
  414.    SYS"Sound_Stereo",2,-127:SYS"Sound_Stereo",1,127
  415.   ELSE
  416.    SYS"Sound_Stereo",1,-127:SYS"Sound_Stereo",2,127
  417.   ENDIF
  418.  ENDIF
  419. ]
  420.  
  421.  !sndpause=0
  422.  
  423. The actual value set in here is treated as a zero/non-zero flag. Zero means
  424. that the sound code should automatically pause whenever sound data runs out;
  425. that is, it will stop incrementing its view of logical time (amount of sound
  426. data played/skipped), and will wait for, and play, late data, rather than
  427. ignoring it and skipping past it when it does arrive. When non zero, it does
  428. the converse, and data arriving after its "play-by" time is skipped over, in
  429. order to catch up with real time.
  430.  
  431. Set this flag to the desired value before starting to play the sound, and do
  432. not change this flag until sound playing has been stopped, or you will horribly
  433. confuse the sound code!
  434.  
  435. (6) giving data to the sound code.
  436.  
  437. The sound code needs to be continually fed data via its 'snddata%' routine: r0
  438. specifies the address of the data, r1 the number of bytes: after the routine
  439. returns, the source is not required anymore. The snddata% routine will wait for
  440. a buffer to become available - callers can check the value at offset 4 in the
  441. sound buffer: if this is non-zero in either buffer, then a call to snddata%
  442. will return as quickly as possible.
  443.  
  444.  IFsndbA%!4<>0 OR sndbB%!4<>0 THEN
  445.   A%=dataptr%:B%=length%:CALLsnddata%
  446.  ENDIF
  447.  
  448. The sound code itself doesn't modify interrupt status (other than disabling
  449. them for very short periods during internal operations), so interrupts should
  450. be enabled around the call to ensure that IRQ latency doesn't get hit by e.g.
  451. ADPCM decompression time.
  452.  
  453. (7) starting it playing.
  454.  
  455. After giving some data to 'snddata%', the sound code can be started:
  456.  
  457. [ Old style:
  458.  A%=sndratio%:B%=mute%:CALLsndplay%
  459. ]
  460.  
  461. A% = 2: B% = mute%: CALL sndplay%
  462.  
  463. (8) in flight entertainment.
  464.  
  465. While the sound code is playing, the value at address 'mute%' can be changed so
  466. as to control it. Bit zero is pause (if set), bit 1 is mute (if set). 
  467.  
  468. Whilst sound is playing (even if muted), the sound code maintains a pair of
  469. words (sndcounter%!24 and sndcounter%!28), representing the time as far as the
  470. sound code is concerned, i.e. how far through the sound track it had got at the
  471. most recent sound IRQ. This is measured in units of input sample times, that
  472. is, 1/(sample playback frequency as specified in the file); the number of
  473. channels in use is not significant in this calculation. sndcounter%!24 records
  474. the number of whole sample times so far, and sndcounter%!28 is the fractional
  475. part (which must be maintained, for accuracy, but can be ignored by code
  476. checking the sound time).
  477.  
  478.  temp_time%=start_time%+((sndcounter%!24/my_sample_rate%)*100)
  479.  
  480. (9) stopping.
  481.  
  482. A call to 'sndstop%' stops the sound code. If this is using the RISC OS sound
  483. system, it will itself put the RISC OS sound parameters back as they were
  484. [unless the corresponding sndplay% call was an old-style one].
  485.  
  486.  CALLsndstop%
  487. [ old code had to do:
  488.  SYS"Sound_Configure",oldchan%,0,oldspeed%
  489. ]
  490.  
  491. (10) format 2: To16 and From16.
  492.  
  493. These convert a chunk's worth of samples between the compressed format and raw
  494. 16 bit signed linear (sample-by-sample interleaved for multi-channel formats).
  495. The code has one entry point at the beginning and takes the following
  496. parameters in registers:
  497.  
  498. r0: source data
  499. r1: destination data
  500. r2: number of sample-time units in the chunk
  501. r3: number of channels
  502.  
  503. On exit it returns updated values of source and destination registers. The
  504. values of r0 and r1 should be word aligned. The value in r2 is measured in
  505. sample-time units, and is independent of the number of channels involved.
  506.  
  507. The correct number of channels for the data in hand should always be passed in
  508. r3. If the converter cannot handle conversion of the specified number of
  509. channels, for whatever reason, it will return with r0 zero, and no data will
  510. have been written into the destination buffer.
  511.  
  512. For To16, the required size of the destination data buffer in bytes is easy to
  513. calculate:
  514.  
  515.         destsize = number of sample times * number of channels * 2
  516.  
  517. For From16, details from the Info file must be used to compute the maximum
  518. required size of the destination buffer. Take the number of sample-times the
  519. source data represents (s%), multiply by c, convert this from (possibly
  520. fractional) total bits to whole bytes (add 1 byte for certainty), round up to 4
  521. bytes, add the per-channel byte overhead (m%), and multiply by the number of
  522. channels. Hence:
  523.  
  524. destbuffersize% = ((INT(s% * c / 8 + 1) + 3) DIV 4 * 4 + m) * chans%
  525.  
  526.