158 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			158 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| 
								 | 
							
								#include <kinc/audio2/audio.h>
							 | 
						||
| 
								 | 
							
								#include <kinc/system.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <kinc/backend/SystemMicrosoft.h>
							 | 
						||
| 
								 | 
							
								#include <kinc/backend/Windows.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <dsound.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								#include <assert.h>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace {
							 | 
						||
| 
								 | 
							
									IDirectSound8 *dsound = nullptr;
							 | 
						||
| 
								 | 
							
									IDirectSoundBuffer *dbuffer = nullptr;
							 | 
						||
| 
								 | 
							
									const DWORD dsize = 50 * 1024;
							 | 
						||
| 
								 | 
							
									const int samplesPerSecond = 44100;
							 | 
						||
| 
								 | 
							
									const int bitsPerSample = 16;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									DWORD lastPlayPosition = 0;
							 | 
						||
| 
								 | 
							
									bool secondHalfFilled = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									const int gap = 10 * 1024;
							 | 
						||
| 
								 | 
							
									DWORD writePos = gap;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_a2_buffer_t a2_buffer;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								static bool initialized = false;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void kinc_a2_init() {
							 | 
						||
| 
								 | 
							
									if (initialized) {
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_a2_internal_init();
							 | 
						||
| 
								 | 
							
									initialized = true;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									a2_buffer.read_location = 0;
							 | 
						||
| 
								 | 
							
									a2_buffer.write_location = 0;
							 | 
						||
| 
								 | 
							
									a2_buffer.data_size = 128 * 1024;
							 | 
						||
| 
								 | 
							
									a2_buffer.channel_count = 2;
							 | 
						||
| 
								 | 
							
									a2_buffer.channels[0] = new float[a2_buffer.data_size];
							 | 
						||
| 
								 | 
							
									a2_buffer.channels[1] = new float[a2_buffer.data_size];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_microsoft_affirm(DirectSoundCreate8(nullptr, &dsound, nullptr));
							 | 
						||
| 
								 | 
							
									// TODO (DK) only for the main window?
							 | 
						||
| 
								 | 
							
									kinc_microsoft_affirm(dsound->SetCooperativeLevel(kinc_windows_window_handle(0), DSSCL_PRIORITY));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									WAVEFORMATEX waveFormat;
							 | 
						||
| 
								 | 
							
									waveFormat.wFormatTag = WAVE_FORMAT_PCM;
							 | 
						||
| 
								 | 
							
									waveFormat.nSamplesPerSec = samplesPerSecond;
							 | 
						||
| 
								 | 
							
									waveFormat.wBitsPerSample = bitsPerSample;
							 | 
						||
| 
								 | 
							
									waveFormat.nChannels = 2;
							 | 
						||
| 
								 | 
							
									waveFormat.nBlockAlign = (waveFormat.wBitsPerSample / 8) * waveFormat.nChannels;
							 | 
						||
| 
								 | 
							
									waveFormat.nAvgBytesPerSec = waveFormat.nSamplesPerSec * waveFormat.nBlockAlign;
							 | 
						||
| 
								 | 
							
									waveFormat.cbSize = 0;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									DSBUFFERDESC bufferDesc;
							 | 
						||
| 
								 | 
							
									bufferDesc.dwSize = sizeof(DSBUFFERDESC);
							 | 
						||
| 
								 | 
							
									bufferDesc.dwFlags = DSBCAPS_GLOBALFOCUS;
							 | 
						||
| 
								 | 
							
									bufferDesc.dwBufferBytes = dsize;
							 | 
						||
| 
								 | 
							
									bufferDesc.dwReserved = 0;
							 | 
						||
| 
								 | 
							
									bufferDesc.lpwfxFormat = &waveFormat;
							 | 
						||
| 
								 | 
							
									bufferDesc.guid3DAlgorithm = GUID_NULL;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_microsoft_affirm(dsound->CreateSoundBuffer(&bufferDesc, &dbuffer, nullptr));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									DWORD size1;
							 | 
						||
| 
								 | 
							
									uint8_t *buffer1 = NULL;
							 | 
						||
| 
								 | 
							
									kinc_microsoft_affirm(dbuffer->Lock(writePos, gap, (void **)&buffer1, &size1, nullptr, nullptr, 0));
							 | 
						||
| 
								 | 
							
									assert(buffer1 != NULL);
							 | 
						||
| 
								 | 
							
									for (DWORD i = 0; i < size1; ++i) {
							 | 
						||
| 
								 | 
							
										buffer1[i] = 0;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									kinc_microsoft_affirm(dbuffer->Unlock(buffer1, size1, nullptr, 0));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_microsoft_affirm(dbuffer->Play(0, 0, DSBPLAY_LOOPING));
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								uint32_t kinc_a2_samples_per_second(void) {
							 | 
						||
| 
								 | 
							
									return samplesPerSecond;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								namespace {
							 | 
						||
| 
								 | 
							
									void copySample(uint8_t *buffer, DWORD &index, bool left) {
							 | 
						||
| 
								 | 
							
										float value = *(float *)&a2_buffer.channels[left ? 0 : 1][a2_buffer.read_location];
							 | 
						||
| 
								 | 
							
										if (!left) {
							 | 
						||
| 
								 | 
							
											a2_buffer.read_location += 1;
							 | 
						||
| 
								 | 
							
											if (a2_buffer.read_location >= a2_buffer.data_size) {
							 | 
						||
| 
								 | 
							
												a2_buffer.read_location = 0;
							 | 
						||
| 
								 | 
							
											}
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										*(int16_t *)&buffer[index] = static_cast<int16_t>(value * 32767);
							 | 
						||
| 
								 | 
							
										index += 2;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void kinc_a2_update() {
							 | 
						||
| 
								 | 
							
									DWORD playPosition;
							 | 
						||
| 
								 | 
							
									DWORD writePosition;
							 | 
						||
| 
								 | 
							
									kinc_microsoft_affirm(dbuffer->GetCurrentPosition(&playPosition, &writePosition));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									int dif;
							 | 
						||
| 
								 | 
							
									if (writePos >= writePosition) {
							 | 
						||
| 
								 | 
							
										dif = writePos - writePosition;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else {
							 | 
						||
| 
								 | 
							
										dif = dsize - writePosition + writePos;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (dif < gap) {
							 | 
						||
| 
								 | 
							
										return;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if (writePos + gap >= dsize) {
							 | 
						||
| 
								 | 
							
										if (playPosition >= writePos || playPosition <= gap) {
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if (writePosition >= writePos || writePosition <= gap) {
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									else {
							 | 
						||
| 
								 | 
							
										if (playPosition >= writePos && playPosition <= writePos + gap) {
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
										if (writePosition >= writePos && writePosition <= writePos + gap) {
							 | 
						||
| 
								 | 
							
											return;
							 | 
						||
| 
								 | 
							
										}
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_a2_internal_callback(&a2_buffer, (uint32_t)(gap / 4));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									DWORD size1;
							 | 
						||
| 
								 | 
							
									uint8_t *buffer1;
							 | 
						||
| 
								 | 
							
									kinc_microsoft_affirm(dbuffer->Lock(writePos, gap, (void **)&buffer1, &size1, NULL, NULL, 0));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									for (DWORD i = 0; i < size1 - (bitsPerSample / 8 - 1);) {
							 | 
						||
| 
								 | 
							
										copySample(buffer1, i, ((writePos + i) / 2) % 2 == 0);
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									writePos += size1;
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									kinc_microsoft_affirm(dbuffer->Unlock(buffer1, size1, NULL, 0));
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
									if (writePos >= dsize) {
							 | 
						||
| 
								 | 
							
										writePos -= dsize;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								void kinc_a2_shutdown() {
							 | 
						||
| 
								 | 
							
									if (dbuffer != nullptr) {
							 | 
						||
| 
								 | 
							
										dbuffer->Release();
							 | 
						||
| 
								 | 
							
										dbuffer = nullptr;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
									if (dsound != nullptr) {
							 | 
						||
| 
								 | 
							
										dsound->Release();
							 | 
						||
| 
								 | 
							
										dsound = nullptr;
							 | 
						||
| 
								 | 
							
									}
							 | 
						||
| 
								 | 
							
								}
							 |