From c85b9f372976213500ea077f238425319cc7971a Mon Sep 17 00:00:00 2001
From: Byurrer <byurrer@mail.ru>
Date: Wed, 3 Jun 2020 22:06:47 +0300
Subject: [PATCH] Fixed coding in ogg-vorbis

---
 source/oggplugin/AudioCodecOgg.cpp  | 125 +++++++++++++++-------------
 source/wavplugin/AudioCodecWave.cpp |   2 +-
 source/xEngine/Engine.cpp           |  53 +++++++-----
 source/xSound/AudioConverter.h      |   5 ++
 source/xSound/SoundSystem.cpp       |  24 +++++-
 5 files changed, 125 insertions(+), 84 deletions(-)

diff --git a/source/oggplugin/AudioCodecOgg.cpp b/source/oggplugin/AudioCodecOgg.cpp
index 45d980cc9..3e90c267d 100644
--- a/source/oggplugin/AudioCodecOgg.cpp
+++ b/source/oggplugin/AudioCodecOgg.cpp
@@ -101,7 +101,7 @@ bool XMETHODCALLTYPE CAudioCodecOgg::open(const char *szFile, const char *szArg,
 {
 	IFile *pFile = m_pFileSystem->openFile(szFile, (forSave ? FILE_MODE_WRITE : FILE_MODE_READ));
 
-	if (!pFile || !ppTarget)
+	if (!pFile || !ppTarget || (forSave && (!szArg && strcasecmp(szArg, getFormat()) != 0)))
 		return false;
 
 	OggVorbis_File *pVoFile = NULL;
@@ -284,16 +284,14 @@ bool XMETHODCALLTYPE CAudioCodecTargetOgg::encode(IXBuffer *pBufferPCM, AudioRaw
 
 	//инициализация кодировщика (статических данных) с переменным битрейтом (variable bitrate)
 	vorbis_info_init(&oVoInfo);
-	iRetCode = vorbis_encode_init_vbr(&oVoInfo, pOutDesc->u8Channels, pOutDesc->uSampleRate, 0.1);
+	if ((iRetCode = vorbis_encode_init_vbr(&oVoInfo, pOutDesc->u8Channels, pOutDesc->uSampleRate, 0.2)))
+		return false;
 
 	/* можно заюзать усредненный битрейт (average bitrate):
-	iRetCode = vorbis_encode_init(&vi,pOutDesc->u8Channels, pOutDesc->uSampleRate,-1,128000,-1);
-	 * но в данной реализации пусть кодировщик сам разбирается :)
+		iRetCode = vorbis_encode_init(&vi,pOutDesc->u8Channels, pOutDesc->uSampleRate,-1,128000,-1);
+		но в данной реализации пусть кодировщик сам разбирается :)
 	*/
 
-	if(iRetCode)
-		return false;
-
 	//инициализируем комментарий
 	vorbis_comment_init(&oVoComment);
 	vorbis_comment_add_tag(&oVoComment, "ENCODER", "SkyXEngine plugin [class 'codec_ogg']");
@@ -315,11 +313,8 @@ bool XMETHODCALLTYPE CAudioCodecTargetOgg::encode(IXBuffer *pBufferPCM, AudioRaw
 	//**************************************************
 	//сброс заголовков в логический поток данных
 
-	while(!iEndOfStream)
+	while (ogg_stream_flush(&oOggStream, &oOggPage))
 	{
-		iRetCode = ogg_stream_flush(&oOggStream, &oOggPage);
-		if(iRetCode == 0)
-			break;
 		m_pFile->writeBin(oOggPage.header, oOggPage.header_len);
 		m_pFile->writeBin(oOggPage.body, oOggPage.body_len);
 	}
@@ -341,88 +336,100 @@ bool XMETHODCALLTYPE CAudioCodecTargetOgg::encode(IXBuffer *pBufferPCM, AudioRaw
 		но так делать не надо, потому что внутри vorbis_analysis_wrote выделяется память на стеке по общему количеству блоков
 		это может привести к переполнению стека
 	*/
+	/* но разделять на блоки и передавать таким образом данные тоже нельзя
+	*/
 	/* получаем выделенный массив (по количеству каналов) массивов (по количеству семплов)
 		aaBuffer[iChannel][iSample]
 	*/
 	/*float **aaBuffer = vorbis_analysis_buffer(&oVoMainState, iCountBlocks);
+	int iCurrSample = 0;
 
 	//заполняем выделенный float массив нормализованными данными [-1.0, 1.0]
 	for(int i = 0; i < iCountBlocks ; ++i)
 	{
 		for(int iChannels = 0; iChannels<pOutDesc->u8Channels; ++iChannels)
 		{
-			int16_t i16Sample = ((int16_t*)pData)[i];
-			aaBuffer[iChannels][i]=float(i16Sample)/32768.f;
+			iCurrSample = i * pOutDesc->u8Channels + iChannels;
+			int16_t i16Sample = ((int16_t*)pData)[iCurrSample];
+			aaBuffer[iChannels][i] = float(i16Sample) / 32768.f;
 		}
 	}
 
 	//сообщаем кодировщику что поступили данные для записи
 	vorbis_analysis_wrote(&oVoMainState, iCountBlocks);*/
 
-	//циклом (частями) передаем данные кодировщику
-	while (iCountReadedBlocks < iCountBlocks)
+	//**************************************************
+	// запись семплов
+
+	//если еще не дошли до конца битового потока, тогда продолжаем запись
+	while(!iEndOfStream)
 	{
-		//количество уже прочитанных сэмплов
+		//количество прочитанных семплов
 		uint32_t uCountReadedSamples = (iCountReadedBlocks*pOutDesc->u8Channels);
-		
 		//количество блоков для текущей итерации
 		int iCurrBlocks = iPartBlocks;
 		if (iCountBlocks - iCountReadedBlocks < iPartBlocks)
 			iCurrBlocks = iCountBlocks - iCountReadedBlocks;
 
-		float **aaBuffer = vorbis_analysis_buffer(&oVoMainState, iCurrBlocks);
-
-		for (int i = 0; i < iCurrBlocks; ++i)
+		//если есть блоки для записи
+		if (iCurrBlocks > 0)
 		{
-			for (int iChannels = 0; iChannels<pOutDesc->u8Channels; ++iChannels)
+			/* получаем выделенный массив (по количеству каналов) массивов (по количеству семплов)
+				aaBuffer[iChannel][iSample]
+			*/
+			float **aaBuffer = vorbis_analysis_buffer(&oVoMainState, iCurrBlocks);
+			int iCurrSample = 0;
+
+			//запись блоков
+			for (int i = 0; i < iCurrBlocks; ++i)
 			{
-				int16_t i16Sample = ((int16_t*)pData)[uCountReadedSamples + i];
-				aaBuffer[iChannels][i] = float(i16Sample) / 32768.f;
+				for (int iChannels = 0; iChannels < pOutDesc->u8Channels; ++iChannels)
+				{
+					iCurrSample = uCountReadedSamples + i * pOutDesc->u8Channels + iChannels;
+					int16_t i16Sample = ((int16_t*)pData)[iCurrSample];
+					aaBuffer[iChannels][i] = float(i16Sample) / 32768.f;
+				}
 			}
-		}
 
-		vorbis_analysis_wrote(&oVoMainState, iCurrBlocks);
-		iCountReadedBlocks += iCurrBlocks;
-	}
-
-
-	//**************************************************
-	// запись семплов
-
-	//если еще не дошли до конца битового потока, тогда продолжаем запись
-	while(!iEndOfStream)
-	{
-		/*разбивка несжатых данных на блоки, если не удалось, тогда сообщаем что данных больше не будет
-		 если не сообщить об этом, то не все данные будут записаны, не получится дойти до конца битового потока, потому что запись идет постраничная и последняя неполня страница не будет записана
-		*/
-		if (vorbis_analysis_blockout(&oVoMainState, &oVoDataBlock) != 1)
+			//сообщаем кодировщику что поступили данные для записи
+			vorbis_analysis_wrote(&oVoMainState, iCurrBlocks);
+			iCountReadedBlocks += iCurrBlocks;
+		}
+		else
 		{
+			/* сообщаем что данных больше не будет
+				если не сообщить об этом, то не все данные будут записаны, не получится дойти до конца битового потока, 
+				потому что запись идет постраничная и последняя неполная страница не будет записана
+		 */
 			vorbis_analysis_wrote(&oVoMainState, 0);
 		}
 
-		//поиск режима кодирования и отправка блока на кодировку
-		vorbis_analysis(&oVoDataBlock, NULL);
-		vorbis_bitrate_addblock(&oVoDataBlock);
-
-		//получение следующего доступного пакета
-		while(vorbis_bitrate_flushpacket(&oVoMainState, &oOggPacket))
+		while (vorbis_analysis_blockout(&oVoMainState, &oVoDataBlock) == 1)
 		{
-			//отправка пакета в битовый поток
-			ogg_stream_packetin(&oOggStream, &oOggPacket);
+			//поиск режима кодирования и отправка блока на кодировку
+			vorbis_analysis(&oVoDataBlock, NULL);
+			vorbis_bitrate_addblock(&oVoDataBlock);
 
-			while(!iEndOfStream)
+			//получение следующего доступного пакета
+			while (vorbis_bitrate_flushpacket(&oVoMainState, &oOggPacket))
 			{
-				//формирование пакетов в страницы и отправка в битовый поток
-				int result=ogg_stream_pageout(&oOggStream, &oOggPage);
-				if(result==0)
-					break;
-
-				m_pFile->writeBin(oOggPage.header, oOggPage.header_len);
-				m_pFile->writeBin(oOggPage.body, oOggPage.body_len);
-
-				//если все записано (находимся в конце битового потока), сообщаем о завершении
-				if(ogg_page_eos(&oOggPage))
-					iEndOfStream=1;
+				//отправка пакета в битовый поток
+				ogg_stream_packetin(&oOggStream, &oOggPacket);
+
+				while (!iEndOfStream)
+				{
+					//формирование пакетов в страницы и отправка в битовый поток
+					int result = ogg_stream_pageout(&oOggStream, &oOggPage);
+					if (result == 0)
+						break;
+
+					m_pFile->writeBin(oOggPage.header, oOggPage.header_len);
+					m_pFile->writeBin(oOggPage.body, oOggPage.body_len);
+
+					//если все записано (находимся в конце битового потока), сообщаем о завершении
+					if (ogg_page_eos(&oOggPage))
+						iEndOfStream = 1;
+				}
 			}
 		}
 	}
diff --git a/source/wavplugin/AudioCodecWave.cpp b/source/wavplugin/AudioCodecWave.cpp
index 07360e982..3f4330601 100644
--- a/source/wavplugin/AudioCodecWave.cpp
+++ b/source/wavplugin/AudioCodecWave.cpp
@@ -13,7 +13,7 @@ bool XMETHODCALLTYPE CAudioCodecWave::open(const char *szFile, const char *szArg
 {
 	IFile *pFile = m_pFileSystem->openFile(szFile, (forSave ? FILE_MODE_WRITE : FILE_MODE_READ));
 
-	if (!pFile || !ppTarget)
+	if (!pFile || !ppTarget && (forSave && (!szArg && strcasecmp(szArg, getFormat()) != 0)))
 		return false;
 
 	AudioRawDesc oDesc;
diff --git a/source/xEngine/Engine.cpp b/source/xEngine/Engine.cpp
index bbd626b7d..3c31cdfb5 100644
--- a/source/xEngine/Engine.cpp
+++ b/source/xEngine/Engine.cpp
@@ -161,6 +161,35 @@ bool XMETHODCALLTYPE CEngine::initGraphics(XWINDOW_OS_HANDLE hWindow, IXEngineCa
 	SSInput_0Create("sxinput", (HWND)hWindow, false);
 	LibReport(REPORT_MSG_LEVEL_NOTICE, "LIB input initialized\n");
 
+
+
+	// init sound
+	AudioRawDesc oAudioDesc;
+	oAudioDesc.u8Channels = 2;
+	oAudioDesc.fmtSample = AUDIO_SAMPLE_FMT_SINT16;
+	oAudioDesc.uSampleRate = 44100;
+	oAudioDesc.calc();
+
+	/*IXSoundSystem *pSound = (IXSoundSystem*)(m_pCore->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID));
+	IXSoundLayer *pMasterLayer = pSound->createMasterLayer(&oAudioDesc, "master");
+	pMasterLayer->play(true);
+	IXSoundPlayer *pPlayer = pMasterLayer->newSoundPlayer("sounds/guitar_10.ogg", SOUND_DTYPE_2D);
+	pPlayer->play();*/
+	/*IXSoundEmitter *pEmitter = pMasterLayer->newSoundEmitter("sounds/ak74_shoot.ogg", SOUND_DTYPE_2D);
+	pEmitter->play();*/
+
+	/*while (1)
+	{
+		if (GetAsyncKeyState('I'))
+		{
+			pEmitter->play();
+			Sleep(100);
+		}
+	}*/
+
+
+
+
 	// init graphics
 	Core_0RegisterCVarInt("r_win_width", 800, "Размер окна по горизонтали (в пикселях)", FCVAR_NOTIFY_OLD);
 	Core_0RegisterCVarInt("r_win_height", 600, "Размер окна по вертикали (в пикселях)", FCVAR_NOTIFY_OLD);
@@ -200,29 +229,7 @@ bool XMETHODCALLTYPE CEngine::initGraphics(XWINDOW_OS_HANDLE hWindow, IXEngineCa
 	LibReport(REPORT_MSG_LEVEL_NOTICE, "LIB render initialized\n");
 
 
-	// init sound
-	AudioRawDesc oAudioDesc;
-	oAudioDesc.u8Channels = 2;
-	oAudioDesc.fmtSample = AUDIO_SAMPLE_FMT_SINT16;
-	oAudioDesc.uSampleRate = 44100;
-	oAudioDesc.calc();
-
-	IXSoundSystem *pSound = dynamic_cast<IXSoundSystem*>(m_pCore->getPluginManager()->getInterface(IXSOUNDSYSTEM_GUID));
-	IXSoundLayer *pMasterLayer = pSound->createMasterLayer(&oAudioDesc, "master");
-	pMasterLayer->play(true);
-	/*IXSoundPlayer *pPlayer = pMasterLayer->newSoundPlayer("sounds/guitar_10.ogg", SOUND_DTYPE_2D);
-	pPlayer->play();*/
-	/*IXSoundEmitter *pEmitter = pMasterLayer->newSoundEmitter("sounds/ak74_shoot.ogg", SOUND_DTYPE_2D);
-	pEmitter->play();
-
-	while (1)
-	{
-		if (GetAsyncKeyState('I'))
-		{
-			pEmitter->play();
-			Sleep(100);
-		}
-	}*/
+	
 
 
 	LibReport(REPORT_MSG_LEVEL_NOTICE, "LIB sound initialized\n");
diff --git a/source/xSound/AudioConverter.h b/source/xSound/AudioConverter.h
index 195788d3e..1284fb95b 100644
--- a/source/xSound/AudioConverter.h
+++ b/source/xSound/AudioConverter.h
@@ -18,6 +18,11 @@ inline bool AudioResampling(void *pIn, AudioRawDesc *pInDesc, IXBuffer *pOut, Au
 	if (pToDesc->uSampleRate == pInDesc->uSampleRate)
 		return false;
 
+	/*pOut->alloc(pInDesc->uSize);
+	memcpy(pOut->get(), pIn, pInDesc->uSize);
+	return true;*/
+
+
 	BYTE *pSrcData = 0;
 
 	if (pOut->size() > 0)
diff --git a/source/xSound/SoundSystem.cpp b/source/xSound/SoundSystem.cpp
index a01a46a61..46fb577ca 100644
--- a/source/xSound/SoundSystem.cpp
+++ b/source/xSound/SoundSystem.cpp
@@ -45,12 +45,16 @@ CSoundSystem::~CSoundSystem()
 	mem_release(m_pMasterLayer);
 }
 
+//**************************************************************************
+
 void XMETHODCALLTYPE CSoundSystem::update(const float3 &vListenerPos, const float3 &vListenerDir, const float3 &vListenerUp)
 {
 	if(m_pMasterLayer)
 		m_pMasterLayer->update();
 }
 
+//**************************************************************************
+
 IXSoundLayer* XMETHODCALLTYPE CSoundSystem::createMasterLayer(const AudioRawDesc *pDesc, const char *szName)
 {
 	if(m_pMasterLayer)
@@ -73,11 +77,15 @@ IXSoundLayer* XMETHODCALLTYPE CSoundSystem::createMasterLayer(const AudioRawDesc
 	return pLayer;
 }
 
+//**************************************************************************
+
 IXCore* CSoundSystem::getCore() const
 {
 	return m_pXCore;
 }
 
+//**************************************************************************
+
 IXAudioCodecTarget* CSoundSystem::getCodecTarget(const char *szName)
 {
 	if(!m_pMasterLayer)
@@ -121,6 +129,7 @@ IXAudioCodecTarget* CSoundSystem::getCodecTarget(const char *szName)
 	if(oDescSnd.uSampleRate == oDescMaster.uSampleRate)
 		return pTarget;
 
+
 	//если кодек может сохранять, тогда пересохраняем файл
 	if(pCodec->canSave())
 	{
@@ -156,8 +165,11 @@ IXAudioCodecTarget* CSoundSystem::getCodecTarget(const char *szName)
 
 	//ищем первый попавшийся кодек который может записывать
 	IXAudioCodec *pFullCodec = getCodecSave();
-	if(!pFullCodec)
+	if (!pFullCodec)
+	{
+		LibReport(REPORT_MSG_LEVEL_ERROR, "Not found codec for coding, file '%s' does not match of parameters master buffer\n", szPath);
 		return NULL;
+	}
 
 	//создаем путь до файла в кэше
 	String sCachePath = String(SOUND_CACHE) + "/"+ szPath;
@@ -226,6 +238,8 @@ IXAudioCodecTarget* CSoundSystem::getCodecTarget(const char *szName)
 	return pTarget2;
 }
 
+//**************************************************************************
+
 void CSoundSystem::addCodec(const char *szFmt, IXAudioCodec *pCodec)
 {
 	if(!szFmt || !pCodec)
@@ -234,16 +248,22 @@ void CSoundSystem::addCodec(const char *szFmt, IXAudioCodec *pCodec)
 	m_mapCodecs[szFmt] = pCodec;
 }
 
+//**************************************************************************
+
 IAudioBufferEx* CSoundSystem::createMasterBuffer(AudioRawDesc *pDesc)
 {
 	return m_pAudio->createMasterBuffer(pDesc);
 }
 
+//**************************************************************************
+
 bool CSoundSystem::supportedDesc(const AudioRawDesc *pDesc, AB_TYPE type)
 {
 	return m_pAudio->supportedDesc(pDesc, type);
 }
 
+//**************************************************************************
+
 IXSoundLayer* XMETHODCALLTYPE CSoundSystem::findLayer(const char *szName)
 {
 	if(!szName)
@@ -255,6 +275,8 @@ IXSoundLayer* XMETHODCALLTYPE CSoundSystem::findLayer(const char *szName)
 	return m_pMasterLayer->findLayer(szName);
 }
 
+//**************************************************************************
+
 IXAudioCodec* CSoundSystem::getCodecSave()
 {
 	for (mapcodec::Iterator i = m_mapCodecs.begin(); i != m_mapCodecs.end(); i++)
-- 
GitLab