#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 #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 #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 ) }