sgdk
xgm.h File Reference

XGM sound driver. More...

Go to the source code of this file.

Defines

#define DRIVER_FLAG_MANUALSYNC_XGM   (1 << 0)
#define DRIVER_FLAG_DELAYDMA_XGM   (1 << 1)
#define XGM_nextFrame()   XGM_nextXFrame(1)
 Notify the Z80 a new frame just happened (XGM music player driver).

Functions

u8 XGM_isPlaying ()
 Returns play music state (XGM music player driver).
void XGM_startPlay (const u8 *song)
 Start playing the specified XGM track (XGM music player driver).
void XGM_startPlay_FAR (const u8 *song, u32 size)
 Same as XGM_startPlay(..) except it supports music accessible through bank switch.
void XGM_stopPlay ()
 Stop playing music (XGM music player driver).
void XGM_pausePlay ()
 Pause playing music, music can be resumed by calling XGM_resumePlay (XGM music player driver).
Note that due to the nature of the music chip (FM synthesis), resume play operation will never be perfect and some notes will miss until next key-on event occurs.
void XGM_resumePlay ()
 Resume playing music after pausing with XGM_pausePlay (XGM music player driver).
Note that due to the nature of the music chip (FM synthesis), resume play operation will never be perfect and some notes will miss until next key-on event occurs.
u8 XGM_isPlayingPCM (const u16 channel_mask)
 Return play status of specified PCM channel (XGM music player driver).
void XGM_setPCM (const u8 id, const u8 *sample, const u32 len)
 Declare a new PCM sample (maximum = 255) for the XGM music player driver.
Sample id < 64 are reserved for music while others are used for SFX so if you want to declare a new SFX PCM sample use an id >= 64.
void XGM_setPCMFast (const u8 id, const u8 *sample, const u32 len)
 Same as XGM_setPCM but fast version.
This method assume that XGM driver is loaded and that 68000 has access to Z80 bus.
void XGM_startPlayPCM (const u8 id, const u8 priority, const u16 channel)
 Play a PCM sample on specified channel (XGM music player driver).
If a sample was currently playing on this channel then priority of the newer sample should be are compared then it's stopped and the new sample is played instead.
Note that music may use the first PCM channel so it's better to use channel 2 to 4 for SFX.
void XGM_stopPlayPCM (const u16 channel)
 Stop play PCM on specified channel (XGM music player driver).
No effect if no sample was currently playing on this channel.
u32 XGM_getElapsed ()
 Return the elapsed play time since the last XGM_startPlay(..) call.
The returned value is in music frame which can be 50/60 per second depending the base music play rate (NTSC/PAL).
u16 XGM_getMusicTempo ()
 Get the current music tempo (in tick per second).
Default value is 60 or 50 depending the system is NTSC or PAL.
This method is meaningful only if you use the automatic music sync mode (see XGM_setManualSync() method) which is the default mode.
Note that using specific tempo (not 60 or 50) will affect performance of DMA contention and external command parsing so it's recommended to stand with default one.
void XGM_setMusicTempo (u16 value)
 Set the music tempo (in tick per second).
Default value is 60 or 50 depending the system is NTSC or PAL. This method is meaningful only if you use the automatic music sync mode (see XGM_setManualSync() method) which is the default mode.
Note that using specific tempo (not 60 or 50) can completely distord FM instruments sound and affect performance of DMA contention and external command parsing so it's recommended to stand with default one.
u16 XGM_getManualSync ()
 Returns manual sync mode state of XGM driver (by default auto sync is used).
void XGM_setManualSync (u16 value)
 Set manual sync mode of XGM driver (by default auto sync is used).
void XGM_nextXFrame (u16 num)
 Same as XGM_nextFrame() except you can specify the numer of frame.
void XGM_setLoopNumber (s8 value)
 Set the loop number for music with loop command.
Default value is -1 for pseudo unfinite (255) loops plays. A value of 0 means single play without any loop, 1 = single play + 1 loop...
void XGM_set68KBUSProtection (u8 value)
 Set temporary 68K BUS protection from Z80 (XGM music player driver).
You should protect BUS Access during DMA and restore it after:
XGM_set68KBUSProtection(TRUE); VDP_doVRamDMA(data, 0x1000, 0x100); XGM_set68KBUSProtection(FALSE);.
u16 XGM_getForceDelayDMA ()
 Returns TRUE if DMA delay is enabled to improve PCM playback.
void XGM_setForceDelayDMA (u16 value)
 This method can be used to improve the PCM playback during XGM music play and while DMA queue is used.
Even using the BUS protection with XGM_set68KBUSProtection you may experience some altered PCM when the XGM music contains PSG data, this is because the Z80 uses the main BUS to access PSG.
By delaying a bit the DMA execution from the DMA queue we let the Z80 to execute all PSG commands and avoid any stall. The delay is about 3 scanlines so using the force delay DMA will reduce the DMA bandwidth for about 3 vblank lines.
u32 XGM_getCPULoad ()
 Returns an estimation of the Z80 CPU load (XGM driver).
The low 16 bits returns the estimated Z80 CPU load where the high 16 bits returns the part spent waiting in the DMA contention (see XGM_set68KBUSProtection method).
The method computes CPU load mean over 32 frames and so it's important to call it at each frame (on VInt for instance) to get meaningful value.
Note that it returns CPU load only for the XGM music parsing part as PCM channel mixing is always ON.
Idle usage is 40% on NTSC and 30% on PAL, 100% usage usually mean overrun and may result in music slowdown and incorrect PCM operations.

Detailed Description

XGM sound driver.

Author:
Stephane Dallongeville
Date:
08/2015

This unit provides methods to use the XGM (eXtended Genesis Music) sound driver.
This driver takes VGM (or XGM) file as input to play music.
It supports 4 PCM channels at a fixed 14 Khz and allows to play SFX through PCM with 16 level of priority.
The driver is designed to avoid DMA contention when possible (depending CPU load).


Define Documentation

#define DRIVER_FLAG_MANUALSYNC_XGM   (1 << 0)

Internal use

#define XGM_nextFrame ( )    XGM_nextXFrame(1)

Notify the Z80 a new frame just happened (XGM music player driver).

Sound synchronization was initially 100% done by Z80 itself using the V-Interrupt but if the Z80 is stopped right at V-Int time (bus request from 68000 or DMA stall) then the V-Int can be missed by the Z80 and music timing affected.
To fix that issue and also to offer more flexibility the music timing should now be handled by the 68k.
By default this method is called automatically by SGDK at V-Int time but you can decide to handle sync manually (see XGM_setManualSync(..) method).
When you are in manual sync you normally should call this method once per frame (in the V-Int callback for instance) but you are free to play with it to increase or decrease music tempo.
Note that it's better to call this method a bit before (3/4 scanlines should be fine) doing DMA operation for best main bus contention protection (see XGM_set68KBUSProtection() and XGM_setForceDelayDMA() methods).

See also:
XGM_setManualSync(..)
XGM_nextXFrame(..)
XGM_set68KBUSProtection(..)
XGM_setForceDelayDMA(..)

Function Documentation

u32 XGM_getElapsed ( )

Return the elapsed play time since the last XGM_startPlay(..) call.
The returned value is in music frame which can be 50/60 per second depending the base music play rate (NTSC/PAL).

See also:
XGM_startPlay(..)
XGM_setMusicTempo()
u16 XGM_getForceDelayDMA ( )

Returns TRUE if DMA delay is enabled to improve PCM playback.

See also:
XGM_setForceDelayDMA()
u16 XGM_getManualSync ( )

Returns manual sync mode state of XGM driver (by default auto sync is used).

See also:
XGM_setManualSync()
u16 XGM_getMusicTempo ( )

Get the current music tempo (in tick per second).
Default value is 60 or 50 depending the system is NTSC or PAL.
This method is meaningful only if you use the automatic music sync mode (see XGM_setManualSync() method) which is the default mode.
Note that using specific tempo (not 60 or 50) will affect performance of DMA contention and external command parsing so it's recommended to stand with default one.

See also:
XGM_setManualSync()
XGM_setMusicTempo()
u8 XGM_isPlayingPCM ( const u16  channel_mask)

Return play status of specified PCM channel (XGM music player driver).

Parameters:
channel_maskChannel(s) we want to retrieve play state.
SOUND_PCM_CH1_MSK = channel 1
SOUND_PCM_CH2_MSK = channel 2
SOUND_PCM_CH3_MSK = channel 3
SOUND_PCM_CH4_MSK = channel 4

You can combine mask to retrieve state of severals channels at once:
isPlayingPCM(SOUND_PCM_CH1_MSK | SOUND_PCM_CH2_MSK)
will actually return play state for channel 1 and channel 2.
Returns:
Return the channel mask of current playing channel(s).
For instance it returns (SOUND_PCM_CH1_MSK | SOUND_PCM_CH3_MSK) if channels 1 and 3 are currently playing.
void XGM_nextXFrame ( u16  num)

Same as XGM_nextFrame() except you can specify the numer of frame.

See also:
XGM_nextFrame(..)
void XGM_pausePlay ( )

Pause playing music, music can be resumed by calling XGM_resumePlay (XGM music player driver).
Note that due to the nature of the music chip (FM synthesis), resume play operation will never be perfect and some notes will miss until next key-on event occurs.

See also:
XGM_resumePlay
XGM_stopPlay
void XGM_resumePlay ( )

Resume playing music after pausing with XGM_pausePlay (XGM music player driver).
Note that due to the nature of the music chip (FM synthesis), resume play operation will never be perfect and some notes will miss until next key-on event occurs.

See also:
XGM_pausePlay
XGM_nextFrame
void XGM_set68KBUSProtection ( u8  value)

Set temporary 68K BUS protection from Z80 (XGM music player driver).
You should protect BUS Access during DMA and restore it after:
XGM_set68KBUSProtection(TRUE); VDP_doVRamDMA(data, 0x1000, 0x100); XGM_set68KBUSProtection(FALSE);.

This way the XGM driver will *try* to avoid using 68K BUS during DMA to avoid execution interruption and so preserve PCM playback quality.
Note that the success of the operation is not 100% garantee and can fails in some conditions (heavy Z80 load, lot of PSG data in XGM music), you can also improve the PCM playblack by using the XGM_setForceDelayDMA() method.

See also:
XGM_setForceDelayDMA(..)
void XGM_setForceDelayDMA ( u16  value)

This method can be used to improve the PCM playback during XGM music play and while DMA queue is used.
Even using the BUS protection with XGM_set68KBUSProtection you may experience some altered PCM when the XGM music contains PSG data, this is because the Z80 uses the main BUS to access PSG.
By delaying a bit the DMA execution from the DMA queue we let the Z80 to execute all PSG commands and avoid any stall. The delay is about 3 scanlines so using the force delay DMA will reduce the DMA bandwidth for about 3 vblank lines.

Parameters:
valueTRUE or FALSE
See also:
XGM_getForceDelayDMA()
XGM_set68KBUSProtection()
void XGM_setManualSync ( u16  value)

Set manual sync mode of XGM driver (by default auto sync is used).

Parameters:
valueTRUE or FALSE
See also:
XGM_getManualSync()
XGM_nextFrame()
void XGM_setMusicTempo ( u16  value)

Set the music tempo (in tick per second).
Default value is 60 or 50 depending the system is NTSC or PAL. This method is meaningful only if you use the automatic music sync mode (see XGM_setManualSync() method) which is the default mode.
Note that using specific tempo (not 60 or 50) can completely distord FM instruments sound and affect performance of DMA contention and external command parsing so it's recommended to stand with default one.

See also:
XGM_setManualSync()
XGM_getMusicTempo()
void XGM_setPCM ( const u8  id,
const u8 sample,
const u32  len 
)

Declare a new PCM sample (maximum = 255) for the XGM music player driver.
Sample id < 64 are reserved for music while others are used for SFX so if you want to declare a new SFX PCM sample use an id >= 64.

Parameters:
idSample id:
value 0 is not allowed
values from 1 to 63 are used for music values from 64 to 255 are used for SFX
sampleSample address, should be 256 bytes boundary aligned
SGDK automatically align sample resource as needed
lenSize of sample in bytes, should be a multiple of 256
SGDK automatically adjust resource size as needed
void XGM_setPCMFast ( const u8  id,
const u8 sample,
const u32  len 
)

Same as XGM_setPCM but fast version.
This method assume that XGM driver is loaded and that 68000 has access to Z80 bus.

Parameters:
idSample id:
value 0 is not allowed
values from 1 to 63 are used for music values from 64 to 255 are used for SFX
sampleSample address, should be 256 bytes boundary aligned
SGDK automatically align sample resource as needed
lenSize of sample in bytes, should be a multiple of 256
SGDK automatically adjust resource size as needed
void XGM_startPlay ( const u8 song)

Start playing the specified XGM track (XGM music player driver).

Parameters:
songXGM track address.
See also:
XGM_stopPlay
XGM_pausePlay
XGM_nextFrame
XGM_startPlay_FAR
void XGM_startPlay_FAR ( const u8 song,
u32  size 
)

Same as XGM_startPlay(..) except it supports music accessible through bank switch.

Parameters:
songXGM track address.
sizeXGM track size (in byte)
See also:
XGM_startPlay
XGM_stopPlay
XGM_pausePlay
XGM_nextFrame
void XGM_startPlayPCM ( const u8  id,
const u8  priority,
const u16  channel 
)

Play a PCM sample on specified channel (XGM music player driver).
If a sample was currently playing on this channel then priority of the newer sample should be are compared then it's stopped and the new sample is played instead.
Note that music may use the first PCM channel so it's better to use channel 2 to 4 for SFX.

Parameters:
idSample id (use XGM_setPCM(..) method first to set id)
priorityValue should go from 0 to 15 where 0 is lowest priority and 15 the highest one.
If the channel was already playing the priority is used to determine if the new SFX should replace the current one (new priority >= old priority).
channelChannel where we want to play sample.
SOUND_PCM_CH1 = channel 1 (usually used by music)
SOUND_PCM_CH2 = channel 2
SOUND_PCM_CH3 = channel 3
SOUND_PCM_CH4 = channel 4
void XGM_stopPlay ( )

Stop playing music (XGM music player driver).

See also:
XGM_pausePlay
void XGM_stopPlayPCM ( const u16  channel)

Stop play PCM on specified channel (XGM music player driver).
No effect if no sample was currently playing on this channel.

Parameters:
channelChannel we want to stop.
SOUND_PCM_CH1 = channel 1
SOUND_PCM_CH2 = channel 2
SOUND_PCM_CH3 = channel 3
SOUND_PCM_CH4 = channel 4
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines