コミュファはうんこ

今回、コミュファからフレッツのGMOとくとくBBに移行したわけですが、
コミュファを切るときに、違約金は発生しないという連絡で終わりました。

本日、電話がかかってきて、機材撤去に17000円かかる。とのこと。
なくせんのか、と言ったら
「初めてです。なくせるのかといわれたの」
と言われました。

ぜったい、みんな言ってるって。
契約者が少なくなったからとるようになったんじゃないの?
私はコミュファができたときにすぐ入ったわけですが、
今では固定IPもないですし、何もかもシステムが変わっているわけですよ、これ。
でもって、コミュファ網では自宅サーバ建て禁止ときたもんだ。
利用規約に載ってますのでの一点張り。
「早急にほかに移ってください」と言われる始末。
追い出しておいて、17000円とられる。
うーむ。なっとくいかん。

プロバイダ変えました

コミュファ光から、フレッツ光・隼(GMOとくとくBB)へ変えました。
変えた理由として、コミュファが自宅サーバ建てをNGとしたことです。

ルーターが心配だったのですが、既存のYAMAHA RTX810が使用できました。
設置した一体型ルータのLAN1をWANスルーかけて、LAN1からRTX810のWANに指してます。

速度的に、あまり落ちずいい感じかな。
固定IPなので、自宅サーバも安定。

簡易プレイヤその2

alac対応出来ました!

Kb Media Player作者のKobarinさん多謝。

少し変数と受け渡し値が間違っていたようです。
新仕様と旧仕様を見比べて分かりました。

こちらで16bit、24bit、32bitは確認とれました。(シークも問題ないようです)
一応64bitまで対応はしてますが、64bitのalac作ってない物でわかりません。

https://ppp.oohara.jp/ogg.html

追記

今度はflacのシークで問題が。。。。
16bitのflacは正常にシーク出来るのに、24bitのflacでシーク出来ない状態になってます。
何か渡すのがおかしいんだと思うのですが、現在調査中

2019.01.13 11:58 新しいものに入れ替えを行いました。
m4a部分の修正と、flacの調査(24bitのシークのみ出来ません、再生は問題無く出来ます)

https://ppp.oohara.jp/ogg.html

追記2

前バージョンに戻してもだめなので、VS2015を再インストールしてみる。
VCしか使わないから不要な物は入れないことにする。
実は最近VC2015がおかしくなって再インストールしたのでそのせいかもしれないので、念のため。

追記3
VS2015アンインストールしたらインストールできなくなった。

原因をgoogle先生で10時間くらい格闘したけど、治らなかったのでVS2017入れ始めてる。

追記4
VS2017も同じエラーとなった。
どうやら、どっかおかしいっぽい。
10時間くらい調べて、なんとかなりましたので書いておきます。
問題のあるパッケージをlogから見つけます。ここではVC_MFC.source.msiで説明します。
そのままダブルクリックすると、

to install this product please run setup.exe. for other installation options"

と出ますので、
msiexec命令を使って、

msiexec /i VC_MFC.source.msi ADDEPLOY=1

として、問題のパッケージの競合を強引に消していきます。
消せたら普通にインストール出来ます。

簡易プレイヤ

ys8に対応したのはいいのですが、久々に普通のoggを再生したところ、途中で止まって強制終了指定しまいました。

原因つきとめるのにかなり掛かりましたが修正したものを置きました。

まだalacには対応出来てません。
-50エラーだすので、なかなか理由わかんないし。

追記 2019.01.11
-50エラーは取れました。
単に、受け取るバッファサイズが大きかったようです。4096くらいにしたら取れました。
m_pAlacDecoder->mConfig.frameLength

ただ、再生すると、少しのノイズが乗り、
44100Hz/16bitのalacだとテンポが若干速くなり、ノイズが載るので、テンポさえなんとかすればたぶん正常になりそう。
192000Hz/24bitのalacだとテンポめちゃくちゃ遅くなり、ノイズがかなり載るので、
まだ設定忘れているところ有りそう。

元ソースはkb media pleyerの新仕様のkpiソース全部を使っています。

alac側

BOOL __fastcall KbAlacDecoder::Open(const _TCHAR *cszFileName, SOUNDINFO *pInfo)
{
	ZeroMemory(pInfo, sizeof(SOUNDINFO));
	FILE *fp;
#if UNICODE	
	fp = _wfopen(cszFileName, L"rb");
#else
	fp = fopen(cszFileName, _T("rb"));
#endif	
	if (!fp) {
		return FALSE;
	}

	buffer = NULL;
	buffer_size=0;


	m_callback.user_data = fp;
	m_pMp4ff = mp4ff_open_read(&m_callback);
	if (!m_pMp4ff) {
		m_callback.user_data = NULL;
		return 0;
	}
	if (mp4ff_get_decoder_config(m_pMp4ff, 0, &buffer, &buffer_size) != 0) {
		mp4ff_close(m_pMp4ff);
		m_callback.user_data = NULL;
		return 0;
	}
	m_pAlacDecoder = new ALACDecoder;
	if (m_pAlacDecoder->Init(buffer, buffer_size) != 0) {
		delete m_pAlacDecoder;
		free(buffer);
		mp4ff_close(m_pMp4ff);
		m_callback.user_data = NULL;
		return 0;
	}
	free(buffer);
	m_qwLastSample = mp4ff_get_track_duration(m_pMp4ff, 0);
	m_MediaInfo.dwSampleRate = m_pAlacDecoder->mConfig.sampleRate;
	m_MediaInfo.dwChannels = m_pAlacDecoder->mConfig.numChannels;
	m_MediaInfo.nBitsPerSample = m_pAlacDecoder->mConfig.bitDepth;
	m_MediaInfo.qwLength = kpi_SampleTo100ns(m_qwLastSample, m_MediaInfo.dwSampleRate);
	m_MediaInfo.dwSeekableFlags = KPI_MEDIAINFO::SEEK_FLAGS_SAMPLE;
	m_MediaInfo.dwUnitSample = m_pAlacDecoder->mConfig.frameLength;
	m_MediaInfo.dwCount = 1;
	m_MediaInfo.dwNumber = 1;

	pInfo->dwSamplesPerSec = m_pAlacDecoder->mConfig.sampleRate;
	pInfo->dwChannels = m_pAlacDecoder->mConfig.numChannels;
	pInfo->dwBitsPerSample = m_pAlacDecoder->mConfig.bitDepth;
	pInfo->dwLength = kpi_SampleTo100ns(m_qwLastSample, m_MediaInfo.dwSampleRate);
	pInfo->dwSeekable = 1;
	pInfo->dwUnitRender = (m_pAlacDecoder->mConfig.frameLength) / 2;
	
	m_nTrack = 0;
	m_nNumSampleId = mp4ff_num_samples(m_pMp4ff, 0);
	buffer = NULL;
	buffer_size = 0;
	m_BitBuffer.cur = NULL;
	return 1;
}
//////////////////////////////////////////////////////////////////////////////
void __fastcall KbAlacDecoder::Close(void)
{
	delete m_pAlacDecoder; m_pAlacDecoder = NULL;
	if (m_pMp4ff) {
		mp4ff_close(m_pMp4ff);
		m_pMp4ff = NULL;
	}

	if (m_callback.user_data) {
		FILE *fp = (FILE*)m_callback.user_data;
		fclose(fp);
		m_callback.user_data = NULL;
	}
	m_pSample = NULL;
	m_dwLastSample = 0;
	m_dwCurrentSample = 0;
	m_dwRemain = 0;
	m_dwSampleRate = 0;
	m_dwChannels = 0;
	m_nNumSampleId = 0;
	m_nCurrentSampleId = 0;
	m_nTrack = 0;

	m_callback.user_data = NULL;
	m_nNumSampleId = 0;
	m_nCurrentSampleId = 0;
	m_nTrack = 0;
}
//////////////////////////////////////////////////////////////////////////
DWORD __fastcall KbAlacDecoder::Render(BYTE *pBuffer, DWORD dwSizeSample)
{
	DWORD dwRetSample = 0;
	if (m_nCurrentSampleId < m_nNumSampleId) {
		BYTE *buffer = NULL;
		UINT buffer_size = 0;
		int rc = mp4ff_read_sample(m_pMp4ff, m_nTrack, m_nCurrentSampleId, &buffer, &buffer_size);
		m_nCurrentSampleId++;
		BitBufferInit(&m_BitBuffer, buffer, buffer_size);
	}
	return dwRetSample;
}

DWORD __fastcall KbAlacDecoder::Render2(BYTE *pBuffer, DWORD dwSizeSample, DWORD cnt)
{
	DWORD dwRetSample = 0;
	if (m_nCurrentSampleId < m_nNumSampleId) {
		DWORD dwSample = 0;
		//BitBufferInit(&m_BitBuffer, buffer, buffer_size);
		int ret = m_pAlacDecoder->Decode(&m_BitBuffer, pBuffer+cnt, dwSizeSample, m_MediaInfo.dwChannels, (uint32_t*)&dwSample);
		dwRetSample = dwSample;
	}
	return dwRetSample;
}


int __fastcall KbAlacDecoder::SetPosition(DWORD dwPos)
{
	if (dwPos == 0 && m_nCurrentSampleId == 0) {//既に先頭位置にある
												//なくても問題ないが、無駄なので
		return 0;
	}
	int64_t i64PosSample = MulDiv(dwPos, m_dwSampleRate, 1000);
	//↑目的の位置をサンプル単位にしたもの

	int nStartId = 0;
	int nEndId = m_nNumSampleId;
	int64_t i64CurPos;
	while (1) {
		//2分探索で目的の位置を探す(一発で見つける方法が分からないので)
		//mp4ff_find_sample を使えば一発で行けそうだけど使い方が分からない
		int nId = nStartId + (nEndId - nStartId) / 2;
		i64CurPos = mp4ff_get_sample_position(m_pMp4ff, m_nTrack, nId);
		if (i64CurPos == i64PosSample) {//滅多に成立しない
			nStartId = nEndId = nId;
		}
		else if (i64CurPos > i64PosSample) {
			nEndId = nId - 1;
		}
		else {
			nStartId = nId + 1;
		}
		if (nEndId <= nStartId) {
			break;
		}
	}
	m_nCurrentSampleId = nEndId - 1;//1つ手前にシークする
	if (m_nCurrentSampleId >= m_nNumSampleId) {
		m_nCurrentSampleId = m_nNumSampleId - 1;
	}
	if (m_nCurrentSampleId < 0) {
		m_nCurrentSampleId = 0;
	}
	m_pSample = NULL;
	m_dwRemain = 0;
	//足りない分を最大1秒だけ空読み
	//KbMedia Player 本体が必要に応じてやるので実際は不要
	m_dwCurrentSample = mp4ff_get_sample_position(m_pMp4ff, m_nTrack, m_nCurrentSampleId);
	DWORD dwCurPosMS = MulDiv(m_dwCurrentSample, 1000, m_dwSampleRate);
	DWORD dwDeltaMS = dwPos - dwCurPosMS;
	if (dwDeltaMS > 1000) {
		dwDeltaMS = 1000;
	}
	DWORD dwDeltaSample = MulDiv(dwDeltaMS, m_dwSampleRate, 1000);
	DWORD dwDeltaBytes = dwDeltaSample * 2 * m_dwChannels;
	if (dwDeltaBytes) {
		BYTE *pBuffer = (BYTE*)malloc(dwDeltaBytes);
		dwDeltaBytes = Render(pBuffer, dwDeltaBytes);
		dwDeltaMS = MulDiv(dwDeltaBytes / 2 / m_dwChannels, 1000, m_dwSampleRate);
		dwPos = dwCurPosMS + dwDeltaMS;
		free(pBuffer);
	}
	return dwPos;
}

//MP4ファイル読み込みコールバック関数
uint32_t _read_callback(void *user_data, void *buffer, uint32_t length)
{
	return ((CFile*)user_data)->Read(buffer, length);
}

//MP4ファイルシークコールバック関数
uint32_t _seek_callback(void *user_data, uint64_t position)
{
	return (uint32_t)((CFile*)user_data)->Seek(position, CFile::begin);
}

class m4a
{
public:
	static HKMP WINAPI Open(const _TCHAR *cszFileName, SOUNDINFO *pInfo)
	{//MP4 コンテナに格納されていれば KbMp4AacDecoder
	 //MP4 コンテナに格納されなければ KbAacDecoder
	 //を作成し、そのポインタを返す
		FILE *fp;
#if UNICODE	
		fp = _wfopen(cszFileName, _T("rb"));
#else
		fp = fopen(cszFileName, _T("rb"));
#endif	
		if (!fp) {
			return FALSE;
		}

		IKbAacDecoder *pAAC;
		mp4ff_callback_t callback = { 0 };
		callback.read = read_callback;
		callback.seek = seek_callback;
		callback.user_data = fp;
		mp4ff_t *pMp4ff = mp4ff_open_read(&callback);
		if (!pMp4ff) {
			KbAacDecoder *pAacDecoder = new KbAacDecoder;
			DWORD dwCount = pAacDecoder->Open(cszFileName, pInfo);
			if (dwCount) {
				pAAC = pAacDecoder;
				return pAAC;
			}
			else {
				pAacDecoder->Close();
			}
		}
		else
		 {
			if (mp4ff_total_tracks(pMp4ff) > 0) {
				fseek(fp,0, SEEK_SET);
				char a[0x400];
				char b;
				CString str;
				int flag = 0;
				fread(a,0x400,1,fp);
				//if (strstr(a,"alac")==0) {
				//	flag = 1;
				//}
				//if (flag == 0){ //TRACK_AUDIO){
				//	pAAC = new KbMp4AacDecoder;
				//}
				//else if (flag == 1) {//TRACK_AUDIO_ALAC
				//	pAAC = new KbAlacDecoder;
				//}
				if (mp4ff_total_tracks(pMp4ff) > 0) {
					int type = mp4ff_get_track_type(pMp4ff, 0);
					if (type == 1) {//TRACK_AUDIO)
						pAAC = new KbMp4AacDecoder;
					}
					else if (type == 4) {//TRACK_AUDIO_ALAC
						pAAC = new KbAlacDecoder;
					}
				}
			}
		}
		fclose(fp);

		if (pAAC->Open(cszFileName, pInfo)) {
			return pAAC;
		}
		delete pAAC;
		return NULL;
	}

	static void WINAPI Close(HKMP hKMP)
	{
		if (hKMP) {
			IKbAacDecoder *pAAC = (IKbAacDecoder*)hKMP;
			delete pAAC;
			hKMP = NULL;
		}
	}

	static DWORD WINAPI Render(HKMP hKMP, BYTE* Buffer, DWORD dwSize)
	{
		if (!hKMP)return 0;
		IKbAacDecoder *pAAC = (IKbAacDecoder*)hKMP;
		return pAAC->Render(Buffer, dwSize);
	}

	static DWORD WINAPI Render2(HKMP hKMP, BYTE* Buffer, DWORD dwSize,DWORD cnt3)
	{
		if (!hKMP)return 0;
		IKbAacDecoder *pAAC = (IKbAacDecoder*)hKMP;
		return pAAC->Render2(Buffer, dwSize,cnt3);
	}

	static BYTE* WINAPI Buf(HKMP hKMP)
	{
		if (!hKMP)return 0;
		IKbAacDecoder *pAAC = (IKbAacDecoder*)hKMP;
		return pAAC->buffer;
	}

	static DWORD WINAPI SetPosition(HKMP hKMP, DWORD dwPos)
	{
		if (!hKMP)return 0;
		IKbAacDecoder *pAAC = (IKbAacDecoder*)hKMP;
		return pAAC->SetPosition(dwPos);
	}
};

読み込み側

int playwavm4a(BYTE* bw, int old, int l1, int l2)
{
	//データ読み込み
	int rrr = readm4a(bw + old, l1);
	playb += (l1 + l2) / ((wavch == 1 || wavch == 2) ? 4 : (wavch * 2));
//	if (oggsize / ((wavch == 1) ? 1 : 1) - 44100 < = playb * 4) {
	//	if (savedata.saveloop == FALSE) {
		//	l1 = rrr;  fade1 = 1;
//			return l1;
	//	}
	//}
	if (l1 != rrr) {
		if (endf == 1) {
			l1 = rrr; fade1 = 1;
		}
		else {
			loopcnt++;
			playb = loop1;
			m4a_.SetPosition(og->kmp, 0);
			readm4a(bw + old + rrr, l1 - rrr);
		}
	}
	if (l2) {
		rrr = readm4a(bw, l2);
		if (l2 != rrr) {
			if (endf == 1) {
				l2 = rrr; fade1 = 1;
			}
			else {
				loopcnt++;
				playb = loop1;
				m4a_.SetPosition(og->kmp, 0);
				readm4a(bw + rrr, (int)l2 - rrr);
			}
		}
	}
	return l1 + l2;
}

int readm4a(BYTE*bw, int cnt)
{
	_set_se_translator(trans_func);
	DWORD cnt1 = og->sikpi.dwUnitRender * 2, cnt2 = (DWORD)cnt, cnt4; if (cnt1 == 0) cnt1 = 1024;
	m4a_.Render(og->kmp, (BYTE*)bufkpi, cnt1);
	DWORD r = 0;
	 {
		for (;;) {
			if (cnt2 < = cnt3) { r = 1; break; }
			r = m4a_.Render2(og->kmp, (BYTE*)bufkpi, cnt1,cnt3);
			if (r == 0) break;
			cnt3 += r;
		}
		if (m4a_.Buf(og->kmp) != NULL) {
			free(m4a_.Buf(og->kmp));
		}
		cnt4 = cnt3;
		if (r == 0) cnt = 0;
		memcpy(bufkpi2, bufkpi, cnt);
		unsigned short *bf1, *bf2; bf1 = (unsigned short*)bw; bf2 = (unsigned short*)bufkpi2;
		//		int fw = playb % (wavch);
		//		bf2 += fw;
		int cnt1 = cnt / 2;
		switch (wavch)
		{
		case 1:
		case 2:
			memcpy(bw, bufkpi, cnt);
			break;
		case 3: // 2.1   
			for (int sample = 0; sample < cnt1; sample += wavch)
			{
				int ChannelMap[3] = { 2,3,1 };
				for (int ch = 0; ch < wavch; ch++)
				{
					*bf1++ = bf2[ChannelMap[ch] - 1];
				}
				bf2 += wavch;
			}
			break;
		case 4: // Quad   
			for (int sample = 0; sample < cnt1; sample += wavch)
			{
				int ChannelMap[4] = { 2,3,1,4 };
				for (int ch = 0; ch < wavch; ch++)
				{
					*bf1++ = bf2[ChannelMap[ch] - 1];
				}
				bf2 += wavch;
			}
			break;
		case 5: // Surround   
			for (int sample = 0; sample < cnt1; sample += wavch)
			{
				int ChannelMap[5] = { 2,3,1,4,5 };
				for (int ch = 0; ch < wavch; ch++)
				{
					*bf1++ = bf2[ChannelMap[ch] - 1];
				}
				bf2 += wavch;
			}
			break;
		case 6: // 5.1   
			for (int sample = 0; sample < cnt1; sample += wavch)
			{
				int ChannelMap[6] = { 2,3,1,6,4,5 };
				for (int ch = 0; ch < wavch; ch++)
				{
					*bf1++ = bf2[ChannelMap[ch] - 1];
				}
				bf2 += wavch;
			}
			break;
		}
		if (cnt2 <= cnt3) {
			cnt3 -= cnt2;
			if (cnt3 != 0)	memcpy(bufkpi, bufkpi + cnt2, cnt3);
		}
		Int24 *b24c;
		b24c = (Int24*)bw;
		short *b, c;
		b = (short*)bw;
		if (wavsam == 24) {
			for (int i = 0; i < cnt / 3; i++) {
				int c4 = b24c[i];
				c4 = (int)((float)c4 * ((float)savedata.kakuVal / 100.0f));
				b24c[i] = c4;
			}
		}
		else {
			for (int i = 0; i < cnt / 2; i++) {
				int c = (int)b[i];
				c = (int)((float)c * ((float)savedata.kakuVal / 100.0f));
				b[i] = (short)c;
			}
		}
		if (wavsam == 24) {
			for (int i = 0; i < cnt / 3; i++) {
				int c4 = b24c[i];
				if (savedata.mp3 == 2)	c4 = (int)((float)c4 * 2.0f);
				else if (savedata.mp3 == 4) c4 = (int)((float)c4 * 3.0f);
				else if (savedata.mp3 == 8) c4 = (int)((float)c4 * 4.0f);
				else if (savedata.mp3 == 16) c4 = (int)((float)c4 * 5.0f);
				if (c4 >  8388607)c4 = 8388607;
				if (c4 < -8388608)c4 = -8388608;
				b24c[i] = c4;
			}
		}
		else {
			for (int i = 0; i < cnt / 2; i++) {
				int c = (int)b[i];
				if (savedata.mp3 == 2)	c = (int)((float)b[i] * 1.5f);
				else if (savedata.mp3 == 3) c = (int)((float)b[i] * 2.0f);
				else if (savedata.mp3 == 4) c = (int)((float)b[i] * 2.5f);
				else if (savedata.mp3 == 5) c = (int)((float)b[i] * 3.0f);
				if (c >= 32768)c = 32767;
				if (c <= -32767)c = -32766;
				b[i] = (short)c;
			}
		}
		fade += fadeadd; if (fade&lt;0.0001) { fade = 0.0; fadeadd = 0; }
		//fadeを三乗して計算密度を変更
		if (wavsam == 24) {
			float c4;
			int c5;
			for (int i = 0; i < cnt / 3; i++) {
				c5 = b24c[i]; c4 = (float)c5;
				c4 = c4 * fade * fade; c5 = (int)c4;
				b24c[i] = c5;
			}
		}
		else {
			for (int i = 0; i < cnt / 2; i++) { c = b[i]; c = (short)(((float)c) * fade * fade); b[i] = c; }
		}
		if ((UINT)wl<(UINT)0x7fff0000) {
			if (cc1 == 1)	cc.Write(bw, cnt);
			wl += cnt;
		}
		lenl += cnt;
	}
	if (cnt4<cnt) cnt = cnt4;
	return cnt;
}

分かる方いましたら、返信かchacha@oohara.jpへメール下さいませm(__)m

簡易プレイヤ

SteamのYs8のoggに対応できました。
近々公開します。

まず、ys8のoggのバイナリを見て観ましょう。

これだけでは、何がどうなっているのか分からないですよね。
私もこれが何なのかoggのヘッダ部分取っ払ってデータ部分だけなのか、解析する上で全然分からず2,3日掛かりました。

で、ずっと解析を続ける中で先頭部分に注目しました。

これがys8のoggの先頭部分。


これが普通のoggの先頭部分。

なんかパターンみたいなものが見えてきました。

なにか暗号化されているみたいに見えますね。
Address 00 が 04になってます。実際は4Fです。
差分とか色々行うと以下のようになります。
まず、下位4ビットと上位4ビットが入れ替わります。
0x0fとxorを取ります。
04⇒40⇒0x0fとxor⇒4f
ぴったりですね。

他のSteamはパック化されてoggみたいに外に出てないので無理がありますが、Ys8は出来ました。
実装の際、デコードされたogg、ファイル名_dec.oggとして作成します。
内部で処理行ってメモリに置くことも考えたのですが、ファイルとして外に出して、それを再生する形を取りました。

https://ppp.oohara.jp/ogg.html
更新日付変わってませんがファイルは新しくなってます。

m4aのalacは再生しようとすると落ちますのでドロップしないように。(実装中ではありますが)