Introduction and Overview
AMPlayer is a module for playing Audio MPEG data through the computers sound output, or to a streaming destination. Where sound is to be output, it will select the 8 or 16 bit output depending on the normal configuration (and availability).
The module has been designed so it is easy to make other frontends, or add support for the module to existing player-frontends.
The AMPlayer module supports MPEG version 1, 2 and 2.5, for layers I, II and III. Mixed data may be safely used with the module. The AMPlayer is resilient when faced with corrupt data, and will skip unknown data in a safe manner. Streams of data may contain ID3v2 tags, and may be terminated by ID3v1.1 tags. ID3v2 footers are skipped and not parsed.
Terminology
MPEG audio data is used as a generic term, covering MPEG 1/2/2.5 audio data, using layers I, II, or III.
The term VBR is used to mean 'Variable Bit-Rate'. VBR data is data which contains non-constant bitrate through the track. It is still assumed that the MPEG version and layer remain constant.
Technical Details
In order to play MPEG audio data, AMPlayer processes data in the background using callbacks. This allows the module to continue in, and out of the desktop with no supervision from any other component.
MPEG data input methods
MPEG audio data can come from either a file, or from a data stream. When operating in both of these modes, the functionality of AMPlayer is similar.
File playback
During file playback, the AMPlayer module continually takes data from the file as it needs it. File data is buffered by the module.
File playback will initially read the ID3v1.1 tags from the file if present, and store these for later retrieval by front ends. During playback, ID3v2 tags will be processed (if enabled) and services issued announcing their arrival.
Streaming playback
When streaming, an application must feed data to AMPlayer in a timely fashion. Data is supplied to a ring of buffers which are drained individually by the AMPlayer module. As each buffer is emptied it is the job of the streaming application to provide further data or to close the stream.
The player will take data from buffers supplied by the streaming application in the order given. When the end of a buffer is reached, the player will continue seamlessly to the next buffer. There is no necessity to provide frame-aligned data to the buffers. Where frames straddle the buffer end, it may be necessary for the player to retain the buffer until the frame can be processed. Because of this streaming application must supply at least two buffers and at least 2000 bytes in total for streaming playback. When a buffer is no longer required, a service will be issued to inform the streaming application.
Metadata can be supplied to the AMPlayer module during streaming. This data will be inserted in-line with the stream and made available at the point at which it is played. This data is incompatible with ID3v1.1 data, and with ID3v2 data. During playback, ID3v1.1 and ID3v2 tags are skipped. ID3v2 tags larger than the total size of the ring of buffers will cause the player to stall.
File output methods
AMPlayer is able to output to a number of different destinations. Where the destination is the physical sound system (8bit, 16bit or SharedSound), the interface to the module is unchanged.
8 bit sound output
All sound output is generated as 16bit-stereo data. When only the 8bit sound system is available, a lookup table will be used by the output code to generate the correct logarithmic output. This will result in a slight degradation in quality, but only to the level of the system accuracy. The overall frequency of the sound system will track that of the sound being generated to the limits of the sound system itself. This may result in further inaccuracies.
Because AMPlayer takes over the entire sound system to handle its output, no other sounds (for example, the system beep) will be heard in this mode.
16 bit sound output
Where 16 bit sound is available, but SharedSound support is not, the standard 16 bit sound drivers will be used. The overall frequency of the sound system will track the sound being output to the limits that it is capable.
In this mode, AMPlayer uses the entire 16 bit sound system. As a consequence, no other sound will be generated whilst AMPlayer is playing.
SharedSound output
Where the SharedSound module is available, it will be used by the AMPlayer module. When playing through the SharedSound module, the frequency of the sound system is unaffected by playback. In this mode, the sound most closely matches that which would be generated within the limits of the sound system and its configuration. Importantly, if the overall sound system frequency is configured lower than any of the clients of SharedSound, the output quality will suffer.
Sound from other sources is unaffected by AMPlayer playback, allowing other clients to share the sound system.
Streaming output
AMPlayer can be used to stream generated sound data to any other destination through the use of the streaming output interface. In this mode, the sound system is totally unaffected by processing performed by the module. The streaming interface can obtain the frequency at which the data being read should be played through this interface.
Multiple instantiation
AMPlayer is able to function as a decoder for multiple clients. It achieves this by multiple instantiation of the AMPlayer module. The SWI SWI AMPlayer_Instance manages the instances for clients such that it is not necessary for every client to duplicate the same code.
In addition to this, all AMPlayer SWIs may have bit 31 of their flags set to indicate that the operation should be directed to the instance of the AMPlayer module held in R8. This allows background processes to communicate with just the instance to which they are interested. When services are issued to notify clients of events from the decoder, R8 will be set to the instance handle that generated the service.
If a SWI is not directed at a particular instance, then the currently preferred instance will deal with the request.
User front ends
Front end applications which are controlled by the user, queue tracks, or just monitor the state of the player should only communicate with the base instance of AMPlayer. This allows them to function with any number of other concurrent utilities.
Under most circumstances it is advisable that front ends not worry about the existance of multiple instances and merely communicate with the currently preferred instance. This allows for the greatest flexibility with clients selecting alternative instances as the private for control if necessary
Plugins
Plugins should be aware of the existance of plugins, and only register themselves with the base instance unless explicitly requested otherwise. Because of their nature, plugins are only really suitable for the base instance, or a secondary instance which is being mixed with the base.
* Commands
*Commands will always be issued to the currently 'preferred' instance. In general this will be the base, but under specialised circumstances another instance may be preferred. The AMPlayer module itself will retain the current preferred instance through all operations, and therefore the only mechanism by which another AMPlayer instance may be the preferred is by explicitly issuing the relevant OS_Module, or by issuing a * Command directly to an instance.
Data structures
In order to communicate with AMPlayer, a number of data structures are required. These provide information about the streams being processed.
File Information Block
The File Information Block provides information about the file currently being played.
Offset | Required flags | Contents | |||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | none | flags :
| |||||||||||||||||||||||||||||||||
4 | none | buffer usage ratio in % (*) | |||||||||||||||||||||||||||||||||
8 | bit 0 | projected total time in cs | |||||||||||||||||||||||||||||||||
12 | bit 1 | time elapsed in cs | |||||||||||||||||||||||||||||||||
16 | bit 2 | pointer to ID3 song title | |||||||||||||||||||||||||||||||||
20 | bit 2 | pointer to ID3 artist | |||||||||||||||||||||||||||||||||
24 | bit 2 | pointer to ID3 album name | |||||||||||||||||||||||||||||||||
28 | bit 2 | pointer to ID3 year string | |||||||||||||||||||||||||||||||||
32 | bit 2 | pointer to ID3 comment | |||||||||||||||||||||||||||||||||
36 | bit 3 | left channel VU | |||||||||||||||||||||||||||||||||
40 | bit 3 | right channel VU | |||||||||||||||||||||||||||||||||
44 | none | main volume (0..127) (*) | |||||||||||||||||||||||||||||||||
48 | bit 4 | pointer to most recent error/warning message, or 0 if no message is pending | |||||||||||||||||||||||||||||||||
52 | bit 5 | pointer to filename of the "next" file, or 0 if no file currently queued | |||||||||||||||||||||||||||||||||
56 | bit 2 | ID3v1 genre (a number) | |||||||||||||||||||||||||||||||||
60 | bit 2+7 | ID3v1.1 track (a number), or 0 if not specified | |||||||||||||||||||||||||||||||||
64 | bit 6 | lowest bitrate used | |||||||||||||||||||||||||||||||||
68 | bit 6 | highest bitrate used |
Fields marked with (*) are not valid when returned from an AMPlayer_FileInfo call.
Projected total time
The projected total time for the track is based on the bitrate used by the file so far (unless supplied in another manner). It is assumed that the bitrate remains constant for this calculation. The total time given will be wrong if :
- the file size is unknown, e.g. if playing a stream
- the frame type will later change in a way that alters the number of bytes per frame (eg change in bit rate)
- the data is partially corrupt or contains skippable data (ID3v2 tags, rogue unsynchronised data, etc)
None of the above exceptions are true in the vast majority of MPEG files. The first case is determined by the module, and bit 0 of the flags will be clear. The second case cannot be known in advance, and it will also affect the elapsed time. No matter what happens, the time will always move forward, it just might not be counting centiseconds in these cases.
Within VBR files generated by the Xing encoder (or applying a Xing compatible header) the total time will be calculated from the header. If the file has been truncated, this time will be estimated based on the information in the header.
ID3v1 genre values
ID3v1 genre values are defined elsewhere. See http://www.id3.org for more details.
ID3v1.1 track numbers
ID3v1.1 is an extension to ID3 which, if present, declares the track number within an album.
VU-var values
When the VU level is available, it is a number between 0 and 255. The value is from -42 to 0 dB, in 1/6th dB steps. The level is the peak of the average level since last calling this SWI.
Bitrate values
Where VBR Audio MPEG data is being processed, the high and low bitrate values are used to indicate the current known limits of the data.
Frame Information Block
The Frame Information Block provides information about the most recent frame processed.
Offset | Contents | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | MPEG version as 3 ASCII chars and a 0 terminator, e.g. "2.0" | ||||||||||||
4 | layer type (1..3). 0 is unknown layer | ||||||||||||
8 | sampling frequency in Hz | ||||||||||||
12 | bitrate in kbit/sec | ||||||||||||
16 | mode :
| ||||||||||||
20 | number of channels | ||||||||||||
24 | frame flags :
| ||||||||||||
28 | pointer to left channel DCT array (*) | ||||||||||||
32 | pointer to right channel DCT array (*) |
Fields marked with (*) are not valid when returned from an AMPlayer_FileInfo call.
Plugin Information Block
The Plugin Information Block is used when registering and enumerating plugins present.
Offset | Contents |
---|---|
0 | Filter name, padded with 0's (16 chars) |
16 | Filter author, padded with 0's (32 chars) |
48 | Filter version, padded with 0's (8 chars) |
IDTag Information block
The IDTag Information Block is passed to the service handlers for ID3v2 processing. It provides information on the overall structure of the ID3v2 tag.
Offset | Contents | ||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | Version of original tag data (major * 256 + minor) | ||||||||||||||||||||||||
4 | Header flags :
|
IDFrame Information block
The IDFrame Information Block is passed to the service handlers for ID3v2 processing. It provides information on the specific ID3v2 frame being processed.
Offset | Contents | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
0 | frame number (within this tag) | ||||||||||||||||||||||||||||||||||||||||
4 | frame name (0 terminated) | ||||||||||||||||||||||||||||||||||||||||
12 | flags for this frame :
| ||||||||||||||||||||||||||||||||||||||||
16 | Pointer to frame data (decompressed, de-unsynchronised) | ||||||||||||||||||||||||||||||||||||||||
20 | Frame data length | ||||||||||||||||||||||||||||||||||||||||
24 | Encryption type, or -1 if not given | ||||||||||||||||||||||||||||||||||||||||
28 | Compressed length, or -1 if not compressed | ||||||||||||||||||||||||||||||||||||||||
32 | Frame group, or -1 if not given |
Flags will be promoted to those used by ID3v2.4, if they are of a lower version than that.
Frame data will be terminated by a 0 (not included in the length) for ease of decoding text fields.
System variables
When starting playback, AMPlayer checks the file being played against the variable AMPlayer$Buffer$part path, where part path is the longest component of the path name which is set as a system variable. For example, if you were to play ADFS::Music.$.Lennon.Imagine and had the system variables AMPlayer$Buffer$ and AMPlayer$Buffer$ADFS set, the latter would be used in preference to the former.
The value given is used to determine the number of 'blocks' of output data that will be buffered in the 'Antishock buffer'. The larger this buffer is, the longer the system can be busy before playback ceases. Larger buffers have a greater initial load on the machine as more data is decoded to fill the buffer when the first file is played.
A 'block' is an arbitrary size, currently around 4.5K. The reason for supplying a buffering value in blocks is to provide a more robust means of storing the buffering size. If in future the block size changes, the amount of time that that buffer corresponds to will remain constant (for a given frequency of data).
In the case of streams, the variable AMPlayer$Buffer$Stream will be used to determine the initial output buffer size.
When starting playback, AMPlayer allocates a buffer for data from the file. Whereas AMPlayer$Buffer$* determines the output buffer size, AMPlayer$FileBuffer determines the input buffer size. If you are accessing files on a filing system which has a slow start up time, (for example networks or CDs) you may wish to set this higher value than the default.
The value this variable is set to is in Kilobytes. Unlike the output buffer, the input cannot be measured in blocks because that would require knowing in advance the data contained in the blocks.
For Streams AMPlayer$FileBuffer has no meaning and is not used.
When AMPlayer initialises, it reads AMPlayer$Volume to determine the initial volume. This is a linear volume level, with a maximum at 127, a minimum at 0, and a default level of 112.
Whenever the volume level is changed in the base instance, this system variable is updated to reflect this. When an instance starts (in the same manner as the base AMPlayer instantiation intialising), it reads the state of AMPlayer$Volume and sets its volume to that specified. The result of this is that at any time that an instance is created it starts with the same volume level as the base instance. Should an instance wish to control the volume level of its instance, it should do so with care and pay attention to the initial volume level where appropriate. For example, if the user is playing their base instance at a volume level of 12, they will not wish to have a new instance playing at 112 unless they specifically requested it.
When AMPlayer initialises, it reads AMPlayer$DecimationThreshold to determine the initial decimation threshold. This threshold is used to determine during playback whether decimation of input data is used to provide output data.
Whenever the decimation threshold is changed in the base instance, this system variable is updated to reflect this. When an instance starts (in the same manner as the base AMPlayer instantiation intialising), it reads the state of AMPlayer$DecimationThreshold and sets its threshold to that specified. The result of this is that at any time that an instance is created it starts with the same threshold as the base instance.
When decimating input data, the upper half of the frequency data is discarded, resulting in a frequency of half that normally required for the input data. This reduces the processing required by the data, and therefore reduces the load that AMPlayer places on the system. This speed increase is to the detriment of the quality of the output data.
Service calls
R0 | = | reason code : |
R1 | = | service call number |
R2 - RR7 | = | dependant on reason code |
R8 | = | instance handle of issuing instance, or 0 for the base |
R1 | preserved |
Service_AMPlayer is issued by the AMPlayer module to inform clients of a change in state, or other information about playback. Consult the individual reason codes for more details.
R0 | = | reason code |
R1 | = | service call number |
R8 | = | instance handle of issuing instance, or 0 for the base |
R1 | preserved |
Service_AMPlayer 0 is issued by the AMPlayer module when it initialises. Clients wishing to add plugins to the output of the module should register themselves.
R0 | = | reason code |
R1 | = | service call number |
R8 | = | instance handle of issuing instance, or 0 for the base |
R1 | preserved |
Service_AMPlayer 1 is issued by the AMPlayer module (or an instance of AMPlayer) when it is killed. Clients wishing to only run during the lifetime of AMPlayer should either become dormant or terminate.
R0 | = | reason code |
R1 | = | service call number |
R8 | = | instance handle of issuing instance, or 0 for the base |
R1 | preserved |
Service_AMPlayer 2 is issued by the AMPlayer module when it is about to stat playing a track. Clients wishing to monitor the progress of the track in the background, or to schedule new tracks may wish to watch for this service.
R0 | = | reason code |
R1 | = | service call number |
R8 | = | instance handle of issuing instance, or 0 for the base |
R1 | preserved |
Service_AMPlayer 3 is issued by the AMPlayer module when it has stopped playing and moved to state 'Dormant'.
R0 | = | reason code |
R1 | = | service call number |
R8 | = | instance handle of issuing instance, or 0 for the base |
R1 | preserved |
Service_AMPlayer 4 is issued by the AMPlayer module when it has changed to playing the next track queued. Clients wishing to track the file being played should watch for this service.
R0 | = | reason code |
R1 | = | service call number |
R2 | = | pointer to IDTag Information Block |
R3 | = | pointer to IDFrame Information Block |
R8 | = | instance handle of issuing instance, or 0 for the base |
R1 | preserved |
Service_AMPlayer 5 is issued by the AMPlayer module during playback, when an ID3v2 tag has been encountered. Clients wishing to process ID3v2 as they arrive should watch for this service.
R0 | = | reason code |
R1 | = | service call number |
R2 | = | stream handle |
R3 | = | flag word (currently 0) |
R8 | = | instance handle of issuing instance, or 0 for the base |
R1 | preserved |
Service_AMPlayer 6 is issued by the AMPlayer module during playback from an AMPlayer stream for which service call reporting was requested at creation time when one or more blocks previously passed to that stream have been marked as being freed. Clients wishing to be informed when their blocks are no longer being held by the module should watch for this service.
SWI calls
R0 | = | flags :
| ||||||||||||||||||||||||
R1 | = | pointer to filename | ||||||||||||||||||||||||
R2 | = | if bit 2 of R0 set: volume level to set, or -1 for default | ||||||||||||||||||||||||
R3 | = | if bit 2 of R0 set: pointer to instance name, or 0 to name automatically | ||||||||||||||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R0 | = | if bit 2 of R0 set: handle of created instance |
This SWI is used to play or queue a file for playback. When starting play transiently, the current play is unchaged and only the new instance is affected.
R0 | = | flags :
| ||||||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
This SWI is used to stop playback, or start the skip to the queued file.
R0 | = | flags :
| ||||||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
This SWI is used to pause or resume playback. When paused, decoding to the output buffer continues, but at a much reduced rate. There is no sound output.
Pause mode may also be cancelled by stopping. If SWI AMPlayer_Stop is used to cut to the next file, or if a different file is started, pause mode will continue to be in effect, freezing the new file at the start of the file. This can be used to ensure that playback starts at the instant of calling AMPlayer_Pause (as opposed to calling SWI AMPlayer_Play, which can have a delay while opening the file etc).
R0 | = | flags :
| |||||||||
R1 | = | target time in centi-seconds | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
This SWI locates the position of the target time, and continues playback (or pausing) from there. This has no effect unless the status is either Playing, Locating or Paused. This may take some time, and the playback buffer may empty (which will mute the sound).
The time given here corresponds to the elapsed time returned from SWI AMPlayer_Info. This is true even when the elapsed time is wrong. So when, at time X, the Info call returns the wrong time Y, giving time Y to this call will still start playing at the right time X.
Playback can only start on a frame boundary, so the resolution of the start point is around 2 cs (for 128kbit/sec, 44.1kHz frames).
R0 | = | flags :
| |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R0 | = | Player status :
|
This call will return information about the current state of the player.
When locating, the current time can be read from the file info block, as it moves toward the target time returned in R4.
This call might be made from BASIC with :
SYS "AMPlayer_Info",,"" TO ,Filename$,FIB%
This will set Filename$ to either "" or the filename. Similarily, FIB% will be 0 if there is no info at this stage, or a pointer to it if there is.
There is a brief period when the status might be returned as Locating (2) or Playing (3), but where there is no valid FIB or FRIB, because the first frame has yet to be read.
R0 | = | flags :
| ||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
This SWI is used to configure various aspects of the AMPlayer module's operation.
R0 | = | flags :
| ||||||||||||
R1 | = | new volume level (0-127), or -1 to read current level | ||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R1 | = | old volume level |
This SWI is used to read or write the main volume level of the player.
R0 | = | flags :
| |||||||||||||||
R1 | = | new buffer size in bytes or blocks, or -1 to read current size | |||||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R1 | = | old size in bytes or blocks |
This control call is used to read or write the size of the audio buffer used by AMPlayer to store decoded data. The size can be specified in bytes or in blocks. It is recommended that you use the blocks size to be compatible with the system variable usage, and to ensure that similar amounts of data are buffered in future.
If the buffer isn't currently created, this controls how large it will be when it eventually is. If it exists, OS_ChangeDynamicArea is used to change the size. This may fail with an error, even if some of the job was done (this can happen when reducing the size, as the amount that can be released depends on what is currently being played). This effect is greatly reduced in AMPlayer 1.29 and later.
If it succeeds, the sound may be broken up slightly. On versions of AMPlayer prior to 1.29, this will always cause at least one 'jump' in the playback.
R0 | = | flags :
| ||||||||||||
R1 | = | new level (in words), or 0 for default | ||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R1 | = | old level |
This SWI call is used to set the stack check level used when a callback occurs
When receiving a callback, the SVC stack depth is checked to see if the kernel is reasonably unthreaded. By using this call, you can control what is considered "reasonable". The default value is currently 64, i.e. if there are more than 64 words on the stack by the time of the callback, a new callback will be registered later instead. Setting this too low will cause the player to stall, and you can only stop it by killing the module (or putting the level back up).
It is not expected that users of the AMPlayer API will need to use this SWI.
R0 | = | flags :
| ||||||||||||
R1 | = | sub-reason code :
| ||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R1 | = | old level |
This control call is used to control ID3v2 processing within the player.
ID3v2 processing is quite intensive and can have a performance hit, especially when compressed frames are used.
R0 | = | flags :
| ||||||||||||
R1 | = | 0 (sub-reason code) | ||||||||||||
R2 | = | type of change :
| ||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R2 | = | enable count, or 0 if disabled |
This SWI is used to enable or disable the processing of ID3v2 tags by the AMPlayer module.
When disabled, no ID3v2 processing at all is performed - the tags are merely skipped. This will improve performance when such tags are encountered.
R0 | = | flags :
| ||||||||||||
R1 | = | 1 (sub-reason code) | ||||||||||||
R2 | = | pointer to frame name, or 0 for 'all frames' | ||||||||||||
R3 | = | filtering operation :
| ||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R2 | = | enable count, or 0 if disabled |
This SWI is used to enable or disable specific frames or groups of frames for processing through the service interface.
A single character frame name will select all frames starting with that character. Three character frame names select the ID3v2.2 and earlier frames that match. Four character frame names select the ID3v2.3 and ID3v2.4 frame explicitly.
Claimants of the ID3v2 service should enable the frames they wish to see, and disable them when they no longer require them.
R0 | = | flags :
| ||||||||||||
R1 | = | Operation to apply:
| ||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R1 | = | old transience flag |
This SWI is used to read or write the transiency flag for an instance. Transiency has no meaning for the base instance, but for created instances, it means that when playback completes, the instance will be destroyed automatically.
R0 | = | flags :
| ||||||||||||
R1 | = | Operation to apply:
| ||||||||||||
R2 | = | new decimation threshold | ||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R1 | = | current decimation threshold |
This SWI is used to read or write the 'decimation threshold'. AMPlayer will normally decode data at full accuracy. If the 'decimation threshold' frequency is met or exceeded, the module will apply automatic decimation to the output.
The initial decimation value is based on the version of the module in use (for AMPlayer, this is 1000000, for AMPlayerFP, it is 22050, and for AMPlayer6 it is 0). This can be overridden by setting the AMPlayer$DecimationThreshold variable to a number before starting the module. Setting the decimation threshold of the base instance will set the variable to the same value.
On builds that do not support decimation, the calls are ignored, and reading the decimation always returns 1000000.
R0 | = | flags :
| |||||||||
R1 | = | reason code :
| |||||||||
R2 | = | private word to pass in R0 | |||||||||
R3 | = | pointer to pre-processor (pre-DCT), or 0 for none | |||||||||
R4 | = | pointer to post-processor (post-DCT), or 0 for none | |||||||||
R5 | = | pointer to static Plugin Information Block | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
This SWI is used to register or deregister plugins.
R0 | = | flags for requested information, or 0 to return
size of buffers :
| ||||||||||||||||||
R1 | = | pointer to filename | ||||||||||||||||||
R2 | = | pointer to buffer for File Information Block | ||||||||||||||||||
R3 | = | pointer to buffer for Frame Information Block | ||||||||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R2 | = | required size of the File Information Buffer, if reading size of buffer |
R3 | = | required size of the Frame Information Buffer, if reading size of buffer |
This SWI attempts to return useful information about the file given. The more bits you set in R0, the slower it gets, as it requires more of the file to be read. In particular, requesting the ID3 tag information means seeking to the end of the file, which may be very slow on some filing systems (like DATFS).
Therefore, it sometimes makes sense to make 3 calls:
- With R0=&000, to get the size of the buffers.
- With R0=&001, to read the quick things and determine whether the file is interesting at all.
- With R0=&004, to read only the ID3 tag fields.
Remember to read the buffer sizes first. These information blocks will no doubt be extended, and if you assume the old size, your program will stop working when a new AMPlayer module comes out. Just read the size, and your program will continue to work for eternity. You don't need to supply a frame info pointer in R3 unless bit 0 is set.
R0 | = | flags :
| ||||||||||||||||||||||||
R1 | = | pointer to stream name (for information) | ||||||||||||||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R0 | = | stream handle, or 0 if failed to start |
This SWI is used to start streamed input, ready for playback.
Called by a streaming application to get a Stream Handle. Most streamers will start the stream paused and feed data in until the buffer full flag (see SWI AMPlayer_StreamInfo) is set.
Note: The combination of Queue and Start Paused may not work.
R0 | = | flags :
| |||||||||
R1 | = | stream handle | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
This SWI is used to inform the AMPlayer module that no more data will be supplied to the stream. This does NOT release outstanding buffers that have been passed to AMPlayer. If you need to get these back, call AMPlayer_StreamClose, then SWI AMPlayer_Stop.
R0 | = | flags :
| |||||||||
R1 | = | stream handle | |||||||||
R2 | = | pointer to streaming data block :
| |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
Called by a streamer application to pass a block of data to AMPlayer. All but the first word may be considered read-only and must be in interrupt sharable space (i.e. in a dynamic area, module area, sprite pool etc, NOT in the application). By calling this SWI, the application must guarantee that it will keep the buffer around (and unchanged) at least until AMPlayer sets the usage word to zero.
The streamer application should monitor the first word of the buffers it has previously passed in to see when it gets set to 0 to allow reuse. Buffers will be released strictly in the same order they were passed in.
The metadata list blocks must be kept intact for the same length of time as the data blocks, and can be considered 'released' by AMPlayer when their corresponding data blocks are.
Metadata blocks are in the following format:
Offset | Contents |
---|---|
0 | Pointer to next metadata block, or 0 for the last entry |
4 | Pointer to a 0-terminated 'Key name' field |
8 | Pointer to a value field (often a 0-terminated string, but may be binary data) |
12 | Length of value buffer in bytes |
It is envisaged that there will be a SWI added later to allow metadata to be supplied for non-streaming sources.
R0 | = | flags :
| |||||||||
R1 | = | stream handle | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R0 | = | flags word :
|
This SWI is called by a streaming application to monitor the state of the decoder. Typically a streamer will start a stream up paused and feed it data. The streamer application will then wait until the stream becomes active, and until either the output buffer becomes full, or until it runs out of buffer space itself. Then it can unpause the stream knowing that the maximum amount of buffering is in use.
R0 | = | flags :
| |||||||||
R1 | = | opaque unique value, guaranteed to change to a new unique value when any metadata items change. | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
This SWI is called by streaming applications to discover when meta-data provided by the application has been 'passed' by the decoder and is now active.
R0 | = | flags :
| |||||||||
R1 | = | pointer to key field to match | |||||||||
R2 | = | pointer to buffer for result (or NULL to read length) | |||||||||
R3 | = | length of buffer, or 0 to read required length | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R0 | preserved | |
R1 | = | buffer, filled with data to length given |
R2 | = | length of buffer required, including terminator |
This SWI is called by applications to read meta-data passed to the AMPlayer module. Every element of meta-data is tagged with a 'key' which is used to return its value.
R0 | = | flags :
| ||||||||||||||
R1 | = | Operation type :
| ||||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R0 | = | Bit mask of avialable sound systems :
| |||||||||||||||
R1 | = | Last sound system in use (as on input) |
This SWI is used to determine what sound systems are available on the current machine, and to select a different sound system. Its most common use is to select the User sound system for streaming output data.
R0 | = | flags :
| |||||||||
R1 | = | Unused | |||||||||
R2 | = | pointer to next byte of data to read, or 0 for first call | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R2 | = | pointer to first byte of data to read, or 0 if none available |
R3 | = | number of bytes of data available |
R4 | = | frequency of data |
This SWI is used to take data from the 'user' sound system. Initially, users would call with R2 = 0, to determine where to read data from. They then take use from this address up to the limit supplied. Subsequently, the call this SWI again to inform AMPlayer how much data has been read. AMPlayer will only remove data after it has been informed that it has been read.
Decoding will continue in the background. It may be necessary to delay processing if no data is ready. Data can only be generated on callbacks. It may, therefore, be necessary to wait for a moment or so for the decode to function.
VU-bars are inactive when use user sound state is in use.
Callers should note that only complete frames fed in will produce any output - not all the input stream may be used.
R0 | = | flags :
| ||||||||||||
R1 | = | Reason code :
| ||||||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R0 - R7 | = | dependant on reason code |
This SWI is used control instances of AMPlayer. You should use it in preference to directly creating instances of the AMPlayer module yourself. Consult the reason code descriptions for more details.
R0 | = | flags :
| |||||||||
R1 | = | 0 (reason code) | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R0 | = | instance handle |
This SWI is used return the instance handle of the current instance of AMPlayer. This may be used to discover the handle of the preferred instance such that the preferred instance may be changed to allow fading from one track to another. It is not expected that this call be used often.
R0 | = | flags :
| |||||||||
R1 | = | 1 (reason code) | |||||||||
R2 | = | pointer to zero terminated suffix for the instance name. Ideally you should keep this to < 16 characters. | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R0 | = | instance handle of new instance |
This SWI is used create a new instance of the AMPlayer module. This instance may be used in exactly the same manner as any other, if SWIs are directed at it. Set bit 31 of any SWIs flags to direct the call to the instance whose handle is in R8.
R0 | = | flags :
| |||||||||
R1 | = | 2 (reason code) | |||||||||
R2 | = | instance handle to destroy | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
This SWI is used destroy an instance of the AMPlayer module. You should destroy instances when you have no further use for them, to free up resources and processing time.
This SWI call is for internal use only. You must not use it in your own code.
R0 | = | flags :
| |||||||||
R1 | = | 4 (reason code) | |||||||||
R2 | = | last instance handle, or -1 to start enumerating | |||||||||
R3 | = | pointer to buffer to write name into | |||||||||
R4 | = | length of buffer | |||||||||
R8 | = | if bit 31 of R0 set: instance handle to direct at, or 0 for the base |
R2 | = | instance handle, or -1 if no more |
R4 | = | length written to buffer, or -ve length if failed to write |
This SWI is used to enumerate the instances currently in use by AMPlayer. A 'visualisation' application might use this call to select what source to provide a representation of.
Entry points
R0 | = | private word |
R1 | = | pointer to 'out 1' buffer |
R2 | = | pointer to 'out 2' buffer |
R3 | = | pointer to 32 frequencies (16.16 format) |
R0 | = | 0 if frequencies processed 1 if DCTs done (not recommended) |
This entry is called prior to 'dct64' which decodes the frequencies into the buffer. Note that there is no way in which to identify whether the buffer is for the left or right channel.
R0 | = | private word |
R1 | = | pointer to 'out 1' buffer |
R2 | = | pointer to 'out 2' buffer |
R3 | = | pointer to samples buffer |
R0 | = | 0 if buffer processed |
This entry is called after the 'dct64' which decodes the frequencies into the buffer. Note that there is no way in which to identify whether the buffer is for the left or right channel.
*Commands
-plugins | - | Display information about the plugins currently active. |
-file <filename> | - | Display information about a file, rather than about the current playback state. |
This command is used to display information about the current playback state, or the state of the plugins.
<hours> | - | Number of hours to search for |
<minutes> | - | Number of minutes to search for |
<seconds> | - | Number of seconds to search for |
This command is used to jump to a point in the playback of the file. Use + and - to indicate a location relative to the current playback position.
-off | - | resume playback, instead of pausing |
This command is used to pause, or resume playback.
-next | - | Start playback of queued file immediately |
-queue | - | Queue this file, rather than playing it immediately |
-cue | - | Start decoding this track, but leave the player paused |
-transient | - | Start decoding this track in a new instance which will terminate when playback completes. |
This command is used to play a new file.
This command is used to stop playback.
<volume> | - | volume level (0-127) |
This command is set the playback volume. Initially, 113 is selected.