CRI ADX  Last Updated: 2024-07-17 10:47 p
Raw PCM Playback

Sample Directory

/CRIWARE/SDK/pc/samples/criatomex/raw_pcm_playback


Sample Description

This sample demonstrates how to output raw PCM data generated on the fly.
It uses a raw PCM voice and the seamless continuous playback feature to output a sine wave.


The following sample code outputs the generated raw PCM data.


void main()
{
/* Create a raw PCM voice pool */
rawpcm_vpconfig.identifier = RAW_PCM_VOICE_POOL_ID;
rawpcm_vpconfig.num_voices = 1;
rawpcm_vpconfig.player_config.max_channels = 1;
raw]pcm_vpconfig.player_config.max_sampling_rate = PCM_SAMPLING_RATE;
rawpcm_vpconfig.player_config.pcm_format = CRIATOM_PCM_FORMAT_SINT16;
&rawpcm_vpconfig, NULL, 0);
/* Specify the format information for the sound data to play */
criAtomExPlayer_SetSamplingRate(player, PCM_SAMPLING_RATE);
criAtomExPlayer_SetVoicePoolIdentifier(app_obj->player, RAW_PCM_VOICE_POOL_ID);
/* Specify the callback function to provide the next data */
criAtomExPlayer_SetDataRequestCallback(player, app_data_request_func, app_obj);
/* Specify the first data and play it */
memset(app_obj->pcm_buffer[0], 0, PCM_BUFFER_LENGTH * sizeof(CriSint16));
app_obj->sin_offset = 0.0f;
app_obj->pcm_buffer_current = 0;
criAtomExPlayer_SetData(app_obj->player,
app_obj->pcm_buffer[0], PCM_BUFFER_LENGTH * sizeof(CriSint16));
}
static void app_data_request_func(
void *obj, CriAtomExPlaybackId id, CriAtomPlayerHn player)
{
AppObj *app_obj = (AppObj*)obj;
CriFloat32 sin_offset = app_obj->sin_offset;
CriFloat32 sin_step = 2.0f * 3.141592f * app_obj->sin_frequency / PCM_SAMPLING_RATE;
/* Switch the buffer used */
app_obj->pcm_buffer_current++;
app_obj->pcm_buffer_current %= 2;
CriSint16 *buffer = app_obj->pcm_buffer[app_obj->pcm_buffer_current];
/* Generate the sine wave */
for (i = 0; i < PCM_BUFFER_LENGTH; i++) {
buffer[i] = (CriSint16)(sinf(sin_offset) * 32767.0f);
sin_offset += sin_step;
}
app_obj->sin_offset = fmodf(sin_offset, 2.0f * 3.141592f);
/* Set the next data to the player */
criAtomPlayer_SetData(player, buffer, PCM_BUFFER_LENGTH * sizeof(CriSint16));
}
#define CRIATOMEX_FORMAT_RAW_PCM
Definition: cri_le_atom_ex.h:1932
void criAtomExPlayer_SetVoicePoolIdentifier(CriAtomExPlayerHn player, CriAtomExVoicePoolIdentifier identifier)
Specify the Voice Pool identifier.
void criAtomExPlayer_SetData(CriAtomExPlayerHn player, void *buffer, CriSint32 size)
Set the sound data to play (specifying in-memory data)
void criAtomExPlayer_SetFormat(CriAtomExPlayerHn player, CriAtomExFormat format)
Specify the format of a sound.
CriAtomExPlaybackId criAtomExPlayer_Start(CriAtomExPlayerHn player)
Start the playback.
void criAtomExPlayer_SetDataRequestCallback(CriAtomExPlayerHn player, CriAtomExPlayerDataRequestCbFunc func, void *obj)
Register the data request callback function.
CriUint32 CriAtomExPlaybackId
Playback ID.
Definition: cri_le_atom_ex.h:3722
void criAtomExPlayer_SetNumChannels(CriAtomExPlayerHn player, CriSint32 num_channels)
Specify the number of channels of a sound.
void criAtomExPlayer_SetSamplingRate(CriAtomExPlayerHn player, CriSint32 sampling_rate)
Specify the sampling rate of a sound.
#define criAtomExVoicePool_SetDefaultConfigForRawPcmVoicePool(p_config)
Assign the default values to the configuration structure used to create a raw PCM Voice Pool.
Definition: cri_le_atom_ex.h:672
CriAtomExVoicePoolHn criAtomExVoicePool_AllocateRawPcmVoicePool(const CriAtomExRawPcmVoicePoolConfig *config, void *work, CriSint32 work_size)
Create a raw PCM Voice Pool.
struct CriAtomPlayerTag * CriAtomPlayerHn
Atom player handle.
Definition: cri_le_atom.h:2339
void criAtomPlayer_SetData(CriAtomPlayerHn player, void *buffer, CriSint32 buffer_size)
Set sound data (specify On-memory data)



About Buffer Use

After specifying the buffer with the criAtomExPlayer_SetData function, you must not destroy it until the second callback is called.
You should use at least a double buffer configuration.
When the status acquired by the ::criAtomExGetStatus function changes to CRIATOMEXPLAYER_STATUS_STOP, you can then destroy the buffer without any issue.

If the buffer size is too small, it may cause a sound break.
A buffer large enough for at least one server cycle is required. Refer to the following formula for reference:

  • One server cycle amount = Sampling rate / Server frequency
  • Buffer size = One server cycle amount + Safe margin amount
    For a sound at 48,000 Hz for example, you would need a buffer that is large enough for 1,024 samples.

Multichannel Data

For multichannel data, you must create the data in interleaved format.
Refer to the following code for how to create interleaved data.
float L_ch[1024];
float R_ch[1024];
float *buffer[1024 * 2];
buffer[0] = L_ch[0];
buffer[1] = R_ch[0];
buffer[2] = L_ch[1];
buffer[3] = R_ch[1];
buffer[4] = L_ch[2];
buffer[5] = R_ch[2];
:
:
criAtomPlayer_SetData(player, buffer, sizeof(buffer));