JD2022-TU1/main/extern/Raki/Source/RakiTests/TestSourceStreaming/TestSourceStreaming.cpp

585 lines
15 KiB
C++

#include "Precompiled.h"
#include "RakiEngine/Data/MemoryBlock/MemoryBlock.h"
#include "RakiEngine/Data/WaveFile/BinWaveData/BinWaveData.h"
#include "RakiEngine/Data/WaveFile/RiffChunkManager.h"
#include "RakiEngine/Sounds/PCMStreamSource.h"
#include "RakiEngine/Sounds/StreamBufferInfo.h"
#include "RakiEngine/Sounds/SoftwareEngine/StreamSoftwareSound.h"
#include "RakiEngine/Sources/SineSource.h"
#include "RakiEngine/Sources/Synth/MonophonicSynth.h"
#include "RakiTests/Sounds/PCMDataProvider.h"
#include "RakiEngine/Utils/Calcs.h"
#if defined ( RAKI_USING_XAUDIO2 )
#include "RakiEngine/Sounds/_XAudio2/PCMStreamSoundNative.h"
#elif defined ( RAKI_PLATFORM_PS3 )
#include <cell/mstream.h>
#include "RakiEngine/Sounds/_PS3/BufferSoundNative_PS3.h"
#include "RakiEngine/Sounds/_PS3/PCMStreamSoundNative_PS3.h"
#include "RakiTests/Sounds/MP3DataProvider.h"
#elif defined ( RAKI_PLATFORM_WII )
#include <revolution/vi.h>
#include "RakiEngine/Sounds/_Wii/BufferSoundNative_Wii.h"
#include "RakiEngine/Sounds/_Wii/PCMStreamSoundNative_Wii.h"
#elif defined ( RAKI_PLATFORM_CAFE )
#include "RakiEngine/Sounds/_Cafe/PCMStreamSoundNative_Cafe.h"
#include "RakiTests/_Cafe/Memory/SimpleHeap_Cafe.h"
#endif
#if defined ( RAKI_PLATFORM_WIN32 )
#include "RakiTests/_Win32/CoInitializeInitObject.h"
#endif // ( RAKI_PLATFORM_WIN32 )
#include "RakiTests/Initializer/TestInitializer.h"
namespace raki
{
enum NoteCommand
{
noteCommand_void,
noteCommand_playNote,
noteCommand_stopNote
};
NoteCommand getNoteCommand( const u32 _beatTwentyFourth, const u32 _rhythmType )
{
NoteCommand noteCommand = noteCommand_void;
switch ( _rhythmType )
{
case 0: // one note every beat
switch( _beatTwentyFourth )
{
case 0:
noteCommand = noteCommand_playNote;
break;
}
break;
case 1: // one note every half beat
switch( _beatTwentyFourth )
{
case 0:
case 12:
noteCommand = noteCommand_playNote;
break;
}
break;
case 2: // one note every third beat
switch( _beatTwentyFourth )
{
case 0:
case 8:
case 16:
noteCommand = noteCommand_playNote;
break;
}
break;
case 3: // one note every quarter beat
switch( _beatTwentyFourth )
{
case 0:
case 6:
case 12:
case 18:
noteCommand = noteCommand_playNote;
break;
}
break;
}
return noteCommand;
}
extern void SystemAllocator_Initialize();
#define STREAMINGSOURCE_NB_CHANNELS 2
// #define STREAMINGSOURCE_MAIN_THREAD_UPDATE_PERIOD_MILLISECONDS 6
// #define STREAMINGSOURCE_BUFFER_SAMPLESIZE ( STREAMINGSOURCE_MAIN_THREAD_UPDATE_PERIOD_MILLISECONDS * RAKI_NATIVE_SAMPLING_RATE / 800 ) // should be divided by 1000 for milliseconds - multiple by a bit more than 1.2 for safety
// #define STREAMINGSOURCE_BUFFER_ALIGNED_SAMPLESIZE ( ( STREAMINGSOURCE_BUFFER_SAMPLESIZE + 63 ) - ( ( STREAMINGSOURCE_BUFFER_SAMPLESIZE + 63 ) % 64 ) ) // should be divided by 1000 for milliseconds - multiple by a bit more than 1.2 for safety
// #define STREAMINGSOURCE_BUFFER_BYTESIZE ( STREAMINGSOURCE_BUFFER_ALIGNED_SAMPLESIZE * 2 * STREAMINGSOURCE_NB_CHANNELS )
#define STREAMINGSOURCE_BUFFER_BYTESIZE ( 512 * 2 * STREAMINGSOURCE_NB_CHANNELS )
bool m_isPlaying = false;
i32 m_midiNote = -1;
MonophonicSynth * m_synth = NULL;
void setSynthParams( const bool _playNote, const f32 x, const f32 y )
{
RAKI_ASSERT( x >= 0.f && x <= 1.f );
RAKI_ASSERT( y >= 0.f && y <= 1.f );
//const i32 scale[] = { 0, 2, 3, 5, 7, 8, 10 }; // F minor7
const i32 scale[] = { 0, 3, 5, 7, 10 }; // F penta minor
const i32 notesInScale = sizeof( scale ) / sizeof( i32 );
const i32 numScales = 3;
const i32 numNotes = numScales * notesInScale + 1;
if ( _playNote )
{
const i32 noteIndex = (i32)( ( 1.f - y ) * (f32)numNotes );
const i32 octave = noteIndex / notesInScale;
const i32 midiNote = MIDI_NOTE_F1 + 12 * octave + scale[ noteIndex % notesInScale ];
if ( midiNote != m_midiNote )
{
if ( m_midiNote >= 0 )
m_synth->stopNote( m_midiNote );
m_synth->startNote( midiNote );
m_midiNote = midiNote;
}
//m_synth->setDetune( 1.f + 0.001f * x );
}
else
{
if ( m_midiNote >= 0 )
m_synth->stopNote( m_midiNote );
m_midiNote = -1;
m_isPlaying = false;
}
//m_synth->setBehaviorVolume( -45.f * ( 1.f - x ) );
}
class AudioCallback : public raki::StreamBufferInfo::AudioCallbackStreamUpdateClient
{
public:
#if defined ( RAKI_USING_SOFTWARE_ENGINE )
AudioCallback( StreamSoftwareSound * _pcmStreamSound )
#else
AudioCallback( PCMStreamSoundNative * _pcmStreamSound )
#endif
: m_pcmStreamSound( _pcmStreamSound )
{
}
virtual void audioCallbackUpdateStreamPosition( const void * /*_clientData*/, const u64 /*_samplePosition*/ )
{
POINT point;
GetCursorPos( &point );
const int screenWidth = GetSystemMetrics(SM_CXSCREEN);
if ( point.x < 0 ) point.x = 0;
if ( point.x >= screenWidth ) point.x = screenWidth - 1;
const int screenHeight = GetSystemMetrics(SM_CYSCREEN);
if ( point.y < 0 ) point.y = 0;
if ( point.y >= screenHeight ) point.y = screenHeight - 1;
const f32 frequency = 440.f * expf( 4.f * (f32) ( point.x - ( screenWidth / 2 ) ) / (f32) screenWidth );
//source.setFrequency( frequency );
const bool playing = GetAsyncKeyState( VK_LBUTTON );
//setSynthParams( playing, (f32) point.x / (f32) screenWidth, (f32) point.y / (f32) screenHeight );
static f32 m_beatInBar = 0.f;
m_beatInBar += 0.02f;
static u32 m_beatTwentyFourth = 0;
const u32 currentBeatTwentyFourth = ( (u32) ( 24.f * m_beatInBar ) ) % 24;
f32 m_x = (f32) point.x / (f32) screenWidth;
f32 m_y = (f32) point.y / (f32) screenHeight;
static f32 lastTime = 0.f;
f32 time = Time::getTime();
RAKI_OUTPUT( "currentBeatTwentyFourth %d (%.3f)", currentBeatTwentyFourth, time - lastTime );
lastTime = time;
if ( m_beatTwentyFourth != currentBeatTwentyFourth )
{
//RAKI_OUTPUT("0x%x PCMSourceInstance::audioCallbackUpdateStreamPosition currentBeatTwentyFourth %d", this, currentBeatTwentyFourth);
const i32 scale[] = { 0, 3, 5, 7, 10 }; // penta minor
const i32 notesInScale = sizeof( scale ) / sizeof( i32 );
const i32 numScales = 3;
const i32 numNotes = numScales * notesInScale + 1;
const i32 noteIndex = (i32)( ( 1.f - m_y ) * (f32)numNotes );
const i32 octave = noteIndex / notesInScale;
const i32 midiNote = MIDI_NOTE_C1 + 12 * octave + scale[ noteIndex % notesInScale ];
u32 rhythmType = 0;
if ( m_x < 0.2f )
rhythmType = 3; // one note every quarter beat
else if ( m_x < 0.4f )
rhythmType = 1; // one note every half beat
else if ( m_x < 0.6f )
rhythmType = 0; // one note every beat
else if ( m_x < 0.8f )
rhythmType = 1; // one note every half beat
else
rhythmType = 3; // one note every quarter beat
const NoteCommand noteComamnd = getNoteCommand( currentBeatTwentyFourth, rhythmType );
if ( noteComamnd == noteCommand_playNote )
{
if ( playing )
{
if ( m_midiNote >= 0 )
m_synth->stopNote( m_midiNote );
m_synth->startNote( midiNote );
m_midiNote = midiNote;
}
}
else if ( noteComamnd == noteCommand_stopNote )
{
m_synth->stopNote( m_midiNote );
m_midiNote = -1;
}
m_beatTwentyFourth = currentBeatTwentyFourth;
}
if ( !playing )
{
m_synth->stopNote( m_midiNote );
m_midiNote = -1;
}
m_pcmStreamSound->update();
}
private:
#if defined ( RAKI_USING_SOFTWARE_ENGINE )
StreamSoftwareSound * m_pcmStreamSound;
#else
PCMStreamSoundNative * m_pcmStreamSound;
#endif
};
void TestSourceStreaming();
void TestSourceStreaming()
{
bool buffersAllocated = false;
#if defined ( RAKI_PLATFORM_WIN32 )
#if defined ( RAKI_USING_SOFTWARE_ENGINE )
StreamSoftwareSound pcmStreamSound;
#else
PCMStreamSoundNative pcmStreamSound;
#endif
// pcmStreamSound.getStreamBufferInfo()->setStreamUpdateClient( &testUpdateClient );
buffersAllocated = pcmStreamSound.allocateBuffers( STREAMINGSOURCE_BUFFER_BYTESIZE );
RAKI_ASSERT( buffersAllocated );
#elif defined ( RAKI_PLATFORM_XB360 )
PCMStreamSoundNative pcmStreamSound;
buffersAllocated = pcmStreamSound.allocateBuffers( STREAMINGSOURCE_BUFFER_BYTESIZE );
RAKI_ASSERT( buffersAllocated );
#elif defined ( RAKI_PLATFORM_WII ) || defined ( RAKI_PLATFORM_CAFE )
PCMStreamSoundNative pcmStreamSound( STREAMINGSOURCE_NB_CHANNELS );
buffersAllocated = pcmStreamSound.allocateBuffers( STREAMINGSOURCE_BUFFER_BYTESIZE );
RAKI_ASSERT( buffersAllocated );
#elif defined ( RAKI_PLATFORM_PS3 )
PCMStreamSoundNative pcmStreamSound;
// mp3StreamSound.getStreamBufferInfo()->setStreamUpdateClient( &testUpdateClient );
buffersAllocated = pcmStreamSound.allocateBuffers( STREAMINGSOURCE_BUFFER_BYTESIZE );
RAKI_ASSERT( buffersAllocated );
#endif
const bool isMusic = false;
const bool isLooping = false;
SoundParams soundParams( isMusic, isLooping );
AudioCallback audioCallback( &pcmStreamSound );
pcmStreamSound.getStreamBufferInfo()->setAudioCallbackStreamUpdateClient( &audioCallback );
//SineSource source( STREAMINGSOURCE_NB_CHANNELS );
MonophonicSynth source;
m_synth = &source;
bool create = pcmStreamSound.createVoice( &source, soundParams );
RAKI_ASSERT( create );
pcmStreamSound.prepare( &source );
pcmStreamSound.updateRouting( true );
pcmStreamSound.start();
bool isPlaying = pcmStreamSound.isPlaying();
RAKI_ASSERT( isPlaying );
int count = 0;
bool playSynth = true;
for ( ;; )
{
bool isPlaying = false;
#ifdef RAKI_PLATFORM_WII
VIWaitForRetrace();
#else // RAKI_PLATFORM_WII
Thread::sleep( 25 );
#endif // RAKI_PLATFORM_WII
#if defined ( RAKI_PLATFORM_WIN32 )
/*
POINT point;
GetCursorPos( &point );
const int screenWidth = GetSystemMetrics(SM_CXSCREEN);
if ( point.x < 0 ) point.x = 0;
if ( point.x >= screenWidth ) point.x = screenWidth - 1;
const int screenHeight = GetSystemMetrics(SM_CYSCREEN);
if ( point.y < 0 ) point.y = 0;
if ( point.y >= screenHeight ) point.y = screenHeight - 1;
const f32 frequency = 440.f * expf( 4.f * (f32) ( point.x - ( screenWidth / 2 ) ) / (f32) screenWidth );
//source.setFrequency( frequency );
const bool playing = GetAsyncKeyState( VK_LBUTTON );
if ( playSynth )
setSynthParams( playing, (f32) point.x / (f32) screenWidth, (f32) point.y / (f32) screenHeight );
*/
//pcmStreamSound.update();
isPlaying |= pcmStreamSound.isPlaying();
#else
//pcmStreamSound.update();
isPlaying |= pcmStreamSound.isPlaying();
#endif
// if ( !isPlaying )
// break;
++count;
/*
if ( count == 100 )
{
RAKI_OUTPUT("stop");
pcmStreamSound.stop();
playSynth = false;
}
if ( count == 200 )
{
RAKI_OUTPUT("start");
pcmStreamSound.start();
pcmStreamSound.update();
playSynth = true;
count = 0;
}
*/
}
pcmStreamSound.stop();
// XAudio2 doc: Stop is always asynchronous, even if called within a callback
Thread::sleep( 5000 );
pcmStreamSound.destroyVoice();
Thread::sleep( 500 );
}
} // namespace raki
#if defined ( RAKI_PLATFORM_CAFE )
u32 running_core;
u32 main_core;
u32 first_subcore;
u32 second_subcore;
u32 wait_main_core;
u32 wait_first_subcore;
u32 wait_second_subcore;
OSRendezvous rendezvous;
void
SetupCoreIds(void)
{
running_core = OSGetCoreId();
main_core = OSGetMainCoreId();
first_subcore = 0;
second_subcore = 2;
wait_main_core = OS_WAIT_CORE_MAIN;
wait_first_subcore = OS_WAIT_CORE_SUB1;
wait_second_subcore = OS_WAIT_CORE_SUB2;
if (main_core == 0)
{
first_subcore = 1;
second_subcore = 2;
wait_main_core = OS_WAIT_CORE_SUB1;
wait_first_subcore = OS_WAIT_CORE_MAIN;
wait_second_subcore = OS_WAIT_CORE_SUB2;
}
else
if (main_core == 2)
{
first_subcore = 0;
second_subcore = 1;
wait_main_core = OS_WAIT_CORE_SUB2;
wait_first_subcore = OS_WAIT_CORE_SUB1;
wait_second_subcore = OS_WAIT_CORE_MAIN;
}
}
int run_demo (int intArg, void *ptrArg)
{
raki::SimpleHeap_Cafe::init();
raki::TestInitializer initializer;
raki::TestSourceStreaming();
return 0;
}
#endif
#if defined ( RAKI_USING_XAUDIO2 )
int _tmain( int /*argc*/, _TCHAR* /*argv[]*/ )
#else // RAKI_USING_XAUDIO2
int main( int /*argc*/, char * /*argv[]*/ )
#endif // RAKI_USING_XAUDIO2
{
#if defined ( RAKI_PLATFORM_WII )
DVDInit();
VIInit();
raki::SystemAllocator_Initialize();
#elif defined ( RAKI_PLATFORM_WIN32 )
raki::CoInitializeInitObject coInitializeInitObject;
#elif defined ( RAKI_PLATFORM_CAFE )
u32 gx2InitAttribs[] =
{
GX2_INIT_ATTRIB_NULL // terminates the list
};
GX2Init(gx2InitAttribs);
// launch test on Core 0 if present
if (OSGetCoreCount() == 3)
{
OSThread* defaultThread0;
SetupCoreIds();
OSReport("Running Core == %d\n", running_core);
OSReport("OS Main Core == %d\n\n", main_core);
OSInitRendezvous(&rendezvous);
//
// Restart default thread on 1st subcore, core0
//
defaultThread0 = OSGetDefaultThread(first_subcore);
OSRunThread(defaultThread0,
run_demo,
0,
(void*) 0x23232323);
OSWaitRendezvous(&rendezvous, wait_first_subcore);
}
else
{
run_demo(0, NULL);
}
GX2Shutdown();
return 0;
#endif
#if !defined ( RAKI_PLATFORM_CAFE )
raki::TestInitializer initializer;
raki::TestSourceStreaming();
return 0;
#endif // !defined ( RAKI_PLATFORM_CAFE )
}