--background--

HISTORY

   52.14 (12.06.2025)
   - Fixed freqs > 48KHz

   52.13 (26.02.2025)
   - Fixed reentrant unsafe code in constructor (RunPlayer taglist was global).

   52.12 (27.02.2022)
   - Changed to only keep the AHI unit open while playing audio. This way
     merely creating the audio object doesn't occupy the unit unnecessarily.

   52.11 (28.10.2013)
   - Fixed broken MMA_TaskPriority attribute, which was always overridden
     with value +26. Now lower values can be set as well.

   52.10 (02.06.2013)
   - Fixed bytes per beat calculation error, where for odd sampling rates beat
     buffer size was not an even multiply of audio frame size.
   - Removed busyloop possibility when broken decoders submit 0 bytes with 0
     error code.

   52.9  (22.03.2013)
   - Implemented MMA_Sound_Mute attribute.

   52.8  (20.03.2013)
   - Stream rewind at end of stream event is now done before end signals and
     messages are sent.
   - MMA_Sound_Volume may now be applied in NewObject().

   52.7  (04.12.2012)
   - Fixed a deadlock introduced in 52.6. It could happen when MMM_Play()
     encountered error or end of data in the first two buffers (40 msec).
     PlayerEndActions() was then executed and called SetAttrs() on object
     being still in MMM_Play(). Now PlayerEndActions() in this case is
     called after the command message is replied.
   - PlayerEndActions() does not set error to owner object when this error
     is MMERR_END_OF_DATA.

   52.6  (16.11.2012)
   - Fixed MMM_SignalAtEnd() and MMM_MessageAtEnd() to return boolean value
     of success instead of 0.
   - Current error code of player is set as MMA_ErrorCode for audio.output
     object just before end of stream events are executed.
   - Main buffer refill loop redesigned to improve looping feature and error
     reporting.

   52.5  (10.10.2012)
   - MMA_ErrorCode for the object is updated with status reported by player
     after every player command that can fail.
   - If MMM_Play() command fails at initial audio buffer filling, end of
     stream events are executed, so application does not wait forever for
     message/signal.

   52.4  (12.07.2012)
   - Fixed bug with trashed sound when playback is resumed after seeking.
     Input and output byte counters are no more used for playback resume.

   52.3  (07.05.2012)
   - Command status is always cleared after replying command message.
   - Command status is always sent back to the main thread.
   - MMM_Seek() returns FALSE on failure.
   - MMM_Seek() sets object MMA_ErrorCode on failure.

   52.2  (20.02.2012)
   - The main loop was changed, now stop and pause events abort both AHI
     requests immediately. Then object no more crashes, when MMM_Play() is
     issued immediately after MMM_Stop().
   - Fixed: Race condition in player task startup handshake.

   52.1  (11.01.2011)
   - Major code rewrite.
   - Signal at end and message at end events are not generated with
     MMM_Stop().

   51.15 (24.06.2010)
   - Fixed MMM_Seek() to return FALSE in case of errors. When seek fails on
     previous object(s), current stream position is not reset to seek
     target.
   - Fixed bug with output frame counting. Now if the last buffer is
     truncated, only really sent frames are counted, not the whole buffer.
   - Implemented MMA_PlayerState.

   51.14 (14.02.2010)
   - Implemented MMM_Pause() method.

   51.13 (07.01.2010)
   - Fixed broken MMA_StreamPosFrames, which was not updated at audio buffer
     swap.

   51.12 (02.06.2009)
   - Added a workaround + log message for broken decoders returning error 0
     in end of data conditions (fixes looped play in Multiview).

   51.11 (15.05.2009)
   - Fixed crash when object initialization failed for lack of any resources
     (usually because of AHI being opened in exclusive mode by other
     application).

   51.10 (05.10.2008)
   - Added error code checking in run_player_subtask(). If subtask returns a
     non-zero error code, it is set as object error (with seterr() macro),
     then the function returns NULL subtask pointer (as it is not running).
     Fixes bugtracker entry #211.

   51.9  (08.06.2007)
   - Implemented MMA_TaskName.

   51.8  (16.04.2007)
   - MMA_Sound_LoopedPlay may be specified for OM_NEW, and set via port.
   - MMA_Sound_AhiUnit works finally.

   51.7  (03.04.2007)
   - Implemented MMA_Sound_LoopedPlay.

   51.6  (11.02.2007)
   - Implemented MMM_Sound_ReplyMsgAtEnd().

   51.5  (26.10.2006)
   - Stream end should rewind the stream, the same as MMM_Stop method
     does (of course non-seekable streams will ignore this). Fixed. Also
     stream rewinding behaviour is now documented explicitly.

   51.4  (11.07.2006)
   - Fixed debug, altered exit message for OM_NEW if no MMA_ErrorCode
     specified.

   51.3  (15.05.2006)
   - Fixed a bug reported by Thomas Igracki. Symptoms: OM_NEW waits forever
     if some application opens AHI in exclusive mode.

   51.2  (03.05.2005)
   - Requires v51 multimedia.class.
   - Sound data buffers reworked (now use MediaAllocVec()).
   - Implemented MMM_Seek, MMM_Stop tries to rewind stream.
   - Fixed lot of compiler warnings.

   51.1  (29.04.2005)
   - Well, v51 version, untested and probably buggy.

   50.14 (18.12.2004)
   - New, documented way of MMA_GetPort and MMA_SetPort forwarding.

   50.13 (16.12.2004)
   - Proper MMA_Get/SetPort forwarding.

   50.12 (22.11.2004)
   - Implemented MMA_TaskPriority (OM_NEW and OM_SET) with default value of
     2.

   50.11 (22.10.2004)
   - play buffer aligned to 16 bytes for AltiVec.

   50.10 (11.10.2004)
   - removed unused library bases in the class base.
   - added missing query support.
   - query tags are accessible via the class base.

   50.9 (05.09.2004)
   - changed according to new multimedia design.

   50.8 (16.03.2004)
   - fixed format autonegotiation with decoders.

   50.7 (09.03.2004)
   - SNDA_CurrentPos now counts also played frames of aborted (stopped)
     requests.

   50.6 (04.03.2004)
   - Bugfix: DTOM_SignalAtEnd did not work if playback limit set by
     SNDA_FrameCount was lower than 16384 frames (fit in single AHI
     request).

   50.5 (04.03.2004)
   - Added: object keeps track of number of played frames and can be
     queried about it with SNDA_CurrentPos.
   - Bugfix: DTOM_SignalAtEnd did not work if playback limit set by
     SNDA_FrameCount was multiple of 16384 frames. Fixes SoundTool problem
     with "PlayMarked" button not released after play.

   50.4 (03.01.2004)
   - Limiting frames with SNDA_FrameCount works.
   - Implemented fetching from stream object.

   50.3 (02.01.2004)
   - Implemented DTOM_SignalAtExit.

   50.2 (01.01.2004)
   - Basic functionality: Fetching from decoder object, DTOM_Play,
     DTOM_Stop.

   50.1 (29.12.2003)
   - Initial release.

DESCRIPTION

   The class is a Reggae audio output using AHI hardware abstraction layer.
   The class uses high-level (device style) AHI interface, number of used
   unit may be set by application. The audio.output has one port (input)
   number 0. This port accepts MMFC_AUDIO_INT16 format. Currently only 1 or
   2 sound channels are supported. The audio.output class is a direct
   subclass of multimedia.class.

NEW ATTRIBUTES

   Attributes applicability:
     I - may be set at creation time.
     S - may be set on an existing object.
     G - may be get from an object.
     P - may be set for an object's port.
     Q - may be queried from an object's port.

   MMA_OutputState          (V51.15) [..G.Q], LONG
   MMA_Sound_AhiUnit        (V51)    [I.G.Q], LONG
   MMA_Sound_Channels       (V50)    [..G.Q], LONG
   MMA_Sound_LoopedPlay     (V51.7)  [ISGPQ], BOOL
   MMA_Sound_SampleRate     (V50)    [..G.Q], LONG
   MMA_Sound_Volume         (V50)    [ISGPQ], LONG
   MMA_Sound_Mute           (v52.9)  [ISGPQ], BOOL
   MMA_StreamPosFrames      (V51)    [..G.Q], UQUAD*
   MMA_StreamPosTime        (V51)    [..G.Q], UQUAD*
   MMA_TaskName             (V51.9)  [I.G.Q], STRPTR
   MMA_TaskPriority         (V50.12) [I.G.Q], BYTE

NEW METHODS

   MMM_MessageAtEnd(message)              (V51.6)
   MMM_Pause()                            (V51.14)
   MMM_Play()                             (V50)
   MMM_Seek(port, type, position)         (V51)
   MMM_SignalAtEnd(task, sigbit)          (V50)
   MMM_Stop()                             (V50)

MMA_OutputState

MMA_OutputState (v52.2) [..G.Q], LONG, 0x8EDA0021

DESCRIPTION

   Returns the current state of the player, one of:
   - MMV_OutputState_Stopped
   - MMV_OutputState_Playing
   - MMV_OutputState_Paused

MMA_Sound_AhiUnit

MMA_Sound_AhiUnit (V51) [I.G.Q], LONG, 0x8EDA0131

DESCRIPTION

   AHI unit to be used by the object for playing. Default value is unit 0,
   allowed range is from 0 to 3

MMA_Sound_Channels

MMA_Sound_Channels (V50) [..G.Q], LONG, 0x8EDA012C

DESCRIPTION

   Specifies number of sound channels in the played stream. Application need
   not to specify it explicitly, as object queries it automatically from a
   previous one, when being connected. The default value of this attribute
   is one channel. It is overridden by querying the previous object (if it
   understands the attribute). Current audio.output can handle one or two
   channels. Streams with more channels won't be played

MMA_Sound_LoopedPlay

MMA_Sound_LoopedPlay (V51) [ISGPQ], BOOL, 0x8EDA0132

DESCRIPTION

   The attribute controls looped playback. When set to FALSE, a sound stream
   is played once, then stops and is rewound to its start (if seekable).
   When the attribute is set to TRUE, the sound is played in an infinite
   loop. The looping is done by seeking to the stream start, so non-seekable
   streams won't work (they will be just played once). The default value is
   FALSE, which means no looping

NOTES

   Using audio.output looping feature is not recommended for very short
   streams, streams shorter than 100 miliseconds may be very CPU intensive.
   For such streams soundloop.filter is recommended as it buffers short
   loops internally.

SEE ALSO

  • soundloop.filter

MMA_Sound_Mute

MMA_Sound_Mute (V52.9) [ISGPQ], BOOL, 0x8EDA0135

DESCRIPTION

   Mutes the sound. When set to TRUE, sound is still played, but its volume
   is temporarily set to 0. When set to FALSE, previous volume is restored

NOTES

   Audio hardware stays allocated and active when sound is muted.

   Volume changes in muted state are accepted. When sound is unmuted, volume
   is restored to the latest level set with MMA_Sound_Volume. Also reading
   MMA_Sound_Volume in muted state yields latest level, not 0.

   Setting MMA_Sound_Volume to 0 explicitly does not change MMA_Sound_Mute
   state.

   End of stream events in muted state are executed normally.

SEE ALSO

MMA_Sound_SampleRate

MMA_Sound_SampleRate (V50) [..G.Q], LONG, 0x8EDA012D

DESCRIPTION

   Specifies playback sample rate in samples per second. Application need
   not to specify it explicitly as object queries it automatically from a
   previous one, when being connected. The default value of this attribute
   is 8000 samples per second. It is overridden by querying the previous
   object (if it understands the attribute). Current audio.output supports
   playback rates from 8000 to 48000 samples per second

MMA_Sound_Volume

MMA_Sound_Volume (V50) [ISGPQ], LONG, 0x8EDA012F

DESCRIPTION

   Specifies playback volume. The range is from 0 (silence) to 65536 (full
   volume), higher values are limited to the maximum. The default volume is
   65536 (max), it may be specified in NewObject(). Then it may be
   overridden by the previous object when objects are connected (most of
   sound formats have no in-stream volume information, but if present, it
   will be used here). After that an application may set it

MMA_StreamPosFrames

MMA_StreamPosFrames (V52.2) [..G.Q], QUAD, 0x8EDA0014

DESCRIPTION

   In case of audio.output object, this attribute returns number of frames
   played by audio hardware, so it determines the playback time, ignoring
   any stream seeking. It is not cleared at neither MMM_Stop(), nor
   MMM_Pause(), so playback time may be checked after stopping or pausing
   the stream. It is cleared however on MMM_Play(), but only  after previous
   MMM_Stop

SEE ALSO

MMA_StreamPosTime

MMA_StreamPosTime (V52.2) [..G.Q], QUAD, 0x8EDA0017

DESCRIPTION

   In case of audio.output object, this attribute returns time of playback,
   which is calculated from MMA_StreamPosFrames, and current playback
   samplerate. The time is in microseconds

NOTES

   The time may be invalid if playback sampling rate has been changed
   during playback.

SEE ALSO

MMA_TaskName

MMA_TaskName (v51.9) [I.G.Q], STRPTR, 0x8EDA001D

DESCRIPTION

   Specifies the name of object subprocess. The default name is "Audio
   Output n", where 'n' is the class subprocesses counter value. The counter
   is initialized to 0, when the class is loaded to memory (at first open).
   The passed string must be null-terminated

NOTES

   The passed string is buffered, so it need not to be static.

MMA_TaskPriority

MMA_TaskPriority (v50.12) [I.G.Q], BYTE, 0x8EDA0005

DESCRIPTION

   Sets the priority of object subprocess. All Reggae objects connected to
   audio.output object input port perform data processing in context of the
   subprocess. The default priority is +26, as audio playback is a realtime
   task and should have priority higher than ordinary applications. The
   allowed priority range is <-128, +26>

MMM_MessageAtEnd

Adds a message to end of stream event.

SYNOPSIS

   DoMethod(obj, MMM_MessageAtEnd, struct Message *msg);

DESCRIPTION

   As data processing in the class is asynchronous to calling application,
   there must be a way of signalling the end of stream. This method adds a
   message to be replied to the reply port set in it when end of stream
   event happens.

   End of stream event can occur in two cases:
   - Real end of data stream.
   - Data pulling or writing to the audio hardware failed.
   These cases can be distinguished by checking MMA_ErrorCode attribute. It
   will be MMERR_END_OF_DATA for end of stream, other error code in case of
   fail.

   The message is put into an internal message port. If there are more
   calls to this method, messages passed are queued in the port. When end
   of stream event occurs, all queued messages are replied to their
   respective reply ports.

   Unlike MMM_SignalAtEnd(), this is an "one shot" attribute, as a message
   can be replied once only. Then it has to be reinitialized and sent
   again with this method. On the other hand only one signal to one process
   may be sent at end of stream, while number of messages replied is not
   limited

INPUTS

   - msg, a message to be sent. It must be a properly initialized system
     message, it means mn_Node.ln_Type, mn_Length and mn_ReplyPort fields
     must be valid

RESULT

   Boolean value of success. The method can fail for following reasons:
   - temporary message port used to communicate with the subprocess cannot
     be created, MMA_ErrorCode is MMERR_RESOURCE_MISSING.
   - NULL message pointer, MMA_ErrorCode is MMERR_WRONG_ARGUMENTS

NOTES

   Execution of MMM_Stop() or MMM_Pause(), as well as object disposing do
   not trigger the end of stream event.

SEE ALSO

MMM_Pause

MMM_Pause (V51.14)

SYNOPSIS

   DoMethod(obj, MMM_Pause);

DESCRIPTION

   The method stops sound playback immediately. Then the stream stays at the
   current position, so following MMM_Play() will continue from the paused
   position. Calling this method is effective only on playing object.
   Performing the method on already paused or stopped stream has no effect.

   The method is designed to be single frame accurate, so following
   MMM_Play() will start from the next audio frame after pause. This is not
   the case for live streams, which cannot be paused (for example radio
   streams or streams coming from hardware audio input

INPUTS

   None

RESULT

   None

SEE ALSO

MMM_Play

MMM_Play (V50)

SYNOPSIS

   success = DoMethod(obj, MMM_Play);

DESCRIPTION

   The method instruct player process to start playback. It is asynchronous,
   so it returns to the caller immediately. Player process fills playback
   buffers with stream data, opens AHI unit and sends playback requests to
   it. Player process pulls data incrementally as sound is played. Playback
   is stopped automatically if data pull returns an error (MMERR_END_OF_DATA
   typically). MMM_Play() issued while audio.output is still playing, is
   ignored

INPUTS

   None

RESULT

   TRUE if playback started, FALSE otherwise, check MMA_ErrorCode for
   additional information

SEE ALSO

MMM_Seek

MMM_Seek (V51)

SYNOPSIS

   success = DoMethod(obj, MMM_Seek, ULONG port, ULONG type, QUAD* pos);

DESCRIPTION

   Performs seek in the played audio stream. The method propagates itself to
   all the previous objects first. If the object is playing, new data are
   pulled to one of playback buffers, playback is stopped and restarted
   immediately with the new data. When time seek is requested, frame number
   is calculated based on current playback samplerate

INPUTS

   - obj, object to perform the method on.
   - port, number of port is always 0.
   - type, seek type (MMM_SEEK_FRAMES, MMM_SEEK_TIME).
   - pos, new, absolute position in the stream. For frame seek it is in
     frames, for time seek in microseconds. It is 64-bit parameter passed by
     a pointer to the value

RESULT

   TRUE if success, FALSE otherwise. Check MMA_ErrorCode for detailed
   information

NOTES

   It is synchronous call. Application waits until seek is performed.
   This method always returned TRUE until v51.15.

SEE ALSO

MMM_SignalAtEnd

Sets a signal for end of stream event.

SYNOPSIS

   DoMethod(obj, MMM_SignalAtEnd, *struct Process process, ULONG sigbit);

DESCRIPTION

   As data processing in the class is asynchronous to calling application,
   there must be a way of signalling the end of stream. This method sets a
   signal to be sent to a process specified when end of stream event
   happens.

   End of stream event can occur in two cases:
   - Real end of data stream.
   - Data pulling or sending to the audio hardware failed.
   These cases can be distinguished by checking MMA_ErrorCode attribute. It
   will be MMERR_END_OF_DATA for end of stream, other error code in case of
   fail.

   The signalling request remains active after end of stream event. The
   signal is sent at every such event until the object is disposed. To clear
   the signalling request call this method with NULL process pointer. Only
   one signal to one process may be sent. If in need of multiple processes
   signalling, one should use MMM_MessageAtEnd() method, or implement signal
   retransmission

INPUTS

   - process, the process to be signalled, or NULL to cancel the signalling.
   - sigbit, the signal number (not mask!) to be used, must be in (0, 31)
     range, the call will be ignored otherwise and error code set to
     MMERR_WRONG_ARGUMENTS for the object

RESULT

   Boolean value of success. The method can fail for following reasons:
   - temporary message port used to communicate with the subprocess cannot
     be created, MMA_ErrorCode is MMERR_RESOURCE_MISSING.
   - signal number out of range, MMA_ErrorCode is MMERR_WRONG_ARGUMENTS

NOTES

   When using a private signal (not one of SIGBREAKB_CTRL_(C|D|E|F)), the
   signal must be allocated by the process to be signalled with
   AllocSignal().

   Execution of MMM_Stop() or MMM_Pause(), as well as object disposing do
   not trigger the end of stream event.

SEE ALSO

MMM_Stop

MMM_Stop (V50)

SYNOPSIS

   DoMethod(obj, MMM_Stop);

DESCRIPTION

   The method stops sound playback immediately, flushes playback buffers and
   performs MMM_Seek on the stream to absolute 0 position

INPUTS

   None

RESULT

   None

NOTES

   If source is not seekable, seeking to 0 has no effect. This method does
   not free AHI unit. To free AHI unit the object has to be disposed.

SEE ALSO