C++で文字列コードを変換する

最近、jubeat analyzerの譜面からyubiosiの譜面への変換機を作った。
その中に、文字列コードの問題に会った。

jubeat analyzerの譜面は、Shift-JISコードのテキストファイルだ。
私の使っているOSは中国語のだ。だから読み込んだ文字列は化けになる。

ネットで何か検索したら、wfstreamにstd::localeオブジェクトを送って直接そのShift-JISのテキストファイルからUnicode型の文字列を取得できる。

std::locale jpLoc("japanese");
std::wfstream fs("c:\\nanika.txt", std::ios::in);
fs.imbue(jpLoc);

ここまで終わり?違う。もっと複雑な場合がある。

そのテキストファイルにShift-JISの文字列だけでなく、GBK(簡体字中国語用)の文字列もある。たとえ譜面に m= の部分。Shift-JISとして読み込んだら文字が化けた。

Shift-JISとGBK込んでる場合、簡単にimbueでできないんだ。

私はこう思う:C++でShift-JISのテキストファイルからwchar_tの文字列を取得できるとは、中にきっと何かのShift-JISからUCS2への変換機能がある。私はfstreamで行分けでメモリに読み込み、そして対応の文字列コードでUCS2の文字列に変換する。

じゃこの変換機能って何なんだろう。

最初私はwstringstreamでいろいろ試した。このように:

std::wstringstream wss;
wss.imbue(jpLoc);
wss << line;
std::wstring wline = wss.str();

だめだ、全然だめだ。

じゃあstd::wfstreamはShift-JISの文字列からUCS2の文字列に変換するとき、何をするんでしょうか。

私はこういうコードを書いて、デバッグモードでステップイン機能使ってそのコード変換の部分を探してみた。

std::locale jpLoc("japanese");
std::wfstream fs("c:\\nanika.txt", std::ios::in);
fs.imbue(jpLoc);
std::wstring wsline;
getline(fs, wsline);

そして、こんなところで

VS2012。コールスタックは:
std::basic_filebuf<wchar_t,std::char_traits<wchar_t> >::uflow() line 501 C++
std::basic_filebuf<wchar_t,std::char_traits<wchar_t> >::underflow() line 460 C++
std::basic_streambuf<wchar_t,std::char_traits<wchar_t> >::sgetc() line 153 C++
std::getline<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >(std::basic_istream<wchar_t,std::char_traits<wchar_t> > && _Istr, std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > & _Str, const wchar_t _Delim) line 414 C++
std::getline<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> >(std::basic_istream<wchar_t,std::char_traits<wchar_t> > & _Istr, std::basic_string<wchar_t,std::char_traits<wchar_t>,std::allocator<wchar_t> > & _Str) line 485 C++
文字列変換のコードを発見した

_Pcvt->in(_State,
&*_Str.begin(), &*_Str.begin() + _Str.size(), _Src,
&_Ch, &_Ch + 1, _Dest)
ほかのパラメーターはわりと理解しやすいが、その_State、_Src、_Destは何だ。

無論、ネットで検索。

_Stateとは、変換のステータスだ。このin関数はconst関数なので、変換状況を記録できない。その_Stateは、thisポインターのようなものとして使われる気がする。ShiftJIS漢字は2バイトなので、1バイトだけ送ったらその1バイトを保存しなければならないね。
_Srcと_Destは、変換進度を表すためパラメーターだ。もしエラーが発生したらこのポインターはエラー発生の時の変換進度だ。

逆のout関数もある。機能もその逆です。

後の問題は、_Pcvtはどこから取得できる。

_Pcvtの型は「const std::codecvt *」です。しかしstd::codecvtオブジェクトは自分で構造できないようだ。
どう見てもLocaleから取得です。本当に(ry

取得の方法もネットで検索して出る。この関数:


const std::codecvt<wchar_t, char, int>& std::use_facet< std::codecvt<wchar_t, char, int> >(const std::locale&)

試して:

#include <iostream>
#include <locale>
#include <vector>
#include <string>

using namespace std;

int main()
{
locale jpLoc("japanese");
typedef std::codecvt<wchar_t, char, std::mbstate_t> MyCodeCvt;
const MyCodeCvt& cvt = std::use_facet<MyCodeCvt>(jpLoc);

std::wstring wt(L"日本語");
std::vector<char> buf(wt.length() * 2 + 1);
const wchar_t* inpProgress;
char* outProgress;
mbstate_t state = 0;

cvt.out(state,
&wt[0], &wt[0] + wt.length(), inpProgress,
&buf[0], &buf[0] + buf.size(), outProgress);
if (inpProgress != &wt[0] + wt.length())
std::cerr << "convert failed!" << std::endl;
else {
*outProgress = 0;

std::string jpStr(&buf[0]);
std::cout << jpStr << std::endl;
}
return 0;
}

うふふ♥

追記:
1、locale jpLoc("japanese")で構造してfs.imbue(jpLoc)で使ったら、数字の出力はおかしくなった。fs << 1000ですれば"1,000"になる。文字列コードだけ使ってほかの機能は不要ならlocale jpLoc("japanese", std::locale::ctype)してください。ctypeは文字列の方って意味です。
2、C++の新標準にstd::wstring_convertがあるようだ。

STLのコンテナで自作のallocatorを使う

特に理由もなく、突然自作allocatorをSTLコンテナ、文字列で試したいです。

STLで、デフォルトのstd::allocatorがある。vectorを使う時、allocatorを指定しなかったらそれを使う。
VC2010のSTLのvectorヘーダに、こういうコードがある


template<class _Ty,
class _Ax = allocator<_Ty> >
class vector
そしてこんな構造体がある
explicit vector(const _Alloc& _Al)
じゃ、自分のallocatorを指定すると、自分でメモリ管理できる。

よくみると、xmemoryにstd::allocatorはこんなもんなんだ


#define _ALLOCATOR allocator
#define _PDFT ptrdiff_t
template<class _Ty>
class _ALLOCATOR
: public _Allocator_base<_Ty>
{ // generic allocator for objects of class _Ty
public:
typedef _Allocator_base<_Ty> _Mybase;
typedef typename _Mybase::value_type value_type;

typedef value_type _FARQ *pointer;
typedef value_type _FARQ& reference;
typedef const value_type _FARQ *const_pointer;
typedef const value_type _FARQ& const_reference;

typedef _SIZT size_type;
typedef _PDFT difference_type;

template<class _Other>
struct rebind
{ // convert this type to _ALLOCATOR<_Other>
typedef _ALLOCATOR<_Other> other;
};

pointer address(reference _Val) const
{ // return address of mutable _Val
return ((pointer) &(char&)_Val);
}

const_pointer address(const_reference _Val) const
{ // return address of nonmutable _Val
return ((const_pointer) &(char&)_Val);
}

_ALLOCATOR() _THROW0()
{ // construct default allocator (do nothing)
}

_ALLOCATOR(const _ALLOCATOR<_Ty>&) _THROW0()
{ // construct by copying (do nothing)
}

template<class _Other>
_ALLOCATOR(const _ALLOCATOR<_Other>&) _THROW0()
{ // construct from a related allocator (do nothing)
}

template<class _Other>
_ALLOCATOR<_Ty>& operator=(const _ALLOCATOR<_Other>&)
{ // assign from a related allocator (do nothing)
return (*this);
}

void deallocate(pointer _Ptr, size_type)
{ // deallocate object at _Ptr, ignore size
::operator delete(_Ptr);
}

pointer allocate(size_type _Count)
{ // allocate array of _Count elements
return (_Allocate(_Count, (pointer)0));
}

pointer allocate(size_type _Count, const void _FARQ *)
{ // allocate array of _Count elements, ignore hint
return (allocate(_Count));
}

void construct(pointer _Ptr, const _Ty& _Val)
{ // construct object at _Ptr with value _Val
_Construct(_Ptr, _Val);
}

void construct(pointer _Ptr, _Ty&& _Val)
{ // construct object at _Ptr with value _Val
::new ( (void _FARQ *)_Ptr) _Ty(_STD forward<_Ty>(_Val) );
}

template<class _Other>
void construct(pointer _Ptr, _Other&& _Val)
{ // construct object at _Ptr with value _Val
::new ( (void _FARQ *)_Ptr) _Ty(_STD forward<_Other>(_Val) );
}

void destroy(pointer _Ptr)
{ // destroy object at _Ptr
_Destroy(_Ptr);
}

_SIZT max_size() const _THROW0()
{ // estimate maximum array size
_SIZT _Count = (_SIZT)(-1) / sizeof (_Ty);
return (0 < _Count ? _Count : 1);
}
};

他のは理解しやすい。自作の時でも同じなんだ。
気になるところは:
1、allocate関数。メモリブロックはここから取り出すようだ。
2、deallocate関数。メモリブロックはここに返還する。
3、difference_typeってなに?
4、rebindの型。...なにこれ?

3のこと、ネットで「ptrdiff_t」を検索すると、このページが出る

http://www.cplusplus.com/reference/clibrary/cstddef/ptrdiff_t/

ポインタの-演算子の戻り値の型です。stddef.hにもあるんだ。放置しても大丈夫よね。

4のこと、ネットで検索するとこのページが出る

http://msdn.microsoft.com/en-us/library/5fk3e8ek(v=vs.80).aspx

なるほど、別の型用のallocatorだ。必要な時自身で作れるの。vectorの内部、T以外のオブジェクトも必要なんだ。例えば右の値の参照演算子とかなんとか

じゃ自作allocatorしたいなら、std::allocatorから継承して、allocate関数とdeallocate関数を書いて、そしてrebindの型を定義したらよさそうだ。

allocateとdeallocateは仮想関数じゃなくどうして動的な多態できるのだろう?
原因は簡単です:デフォルトのstd::stringは、std::basic_string, std::allocator >だから、今は std::basic_string, (自分のallocator) >なるので、allocatorの型は別にstd::allocatorじゃないから、仮想関数にする必要がない。

例え:

#include <memory>
#include <cstdlib>

#include <iostream>

template<class T>
class myallocator : public std::allocator<T> {
public:
myallocator() { }
myallocator(const myallocator& x) { }

template<class U>
myallocator(const myallocator<U>& x) { }

pointer allocate(size_type n, const_pointer hint = 0) {
std::cout << "allocate " << n * sizeof(T) << "bytes" << std::endl;
return (pointer) std::malloc(n * sizeof(T));
}

void deallocate(pointer ptr, size_type n) {
std::cout << "free pointer " << (void*) ptr << std::endl;
std::free(ptr);
}

template<class U>
struct rebind { typedef myallocator<U> other; };
};

#include <vector>
#include <string>

int main() {
std::basic_string<char, std::char_traits<char>, myallocator<char> > mys;
std::vector<int, myallocator<int> > v;
v.push_back(1);
std::cout << v.front() << std::endl;
v.erase(v.begin());

mys = "asdfasdfasdfasdfsadf";
std::cout << mys << std::endl;
}

実行すると、メモリの確保と解放の動作は見えるようになった。

mallocとfreeは自分の書いたメモリ管理コードに切り替えたらいろいろ試せる。

SilverLightで動画エフェクト使用

昨日退屈なのでSilverlightで何かを試しようと思った。
なんというかネットで検索して動画エフェクトのブログとかいっぱい出る。
しかし理解しにくい。XAMLによく知らない私にいきなりxxx.Resourceで動画追加とか流石に。
いろいろ探して、自分を試して、C#のコードで動画追加した。

動画エフェクトを使用するために2のオブジェクトが必要だ。
それはStoryBoardとTimelineだ。前者は動画制御用で、後者は動画本体だ。
例え、ある四辺形rect1がある。透明になる動画を四辺形に付けたいなら、コードはこうする

Storyboard storyBoard = new Storyboard();
DoubleAnimation dblAnime = new DoubleAnimation();
dblAnime.To = 0;
dblAnime.Duration = new Duration(TimeSpan.FromSeconds(2));
Storyboard.SetTarget(dblAnime, rect1);
Storyboard.SetTargetProperty(dblAnime, new PropertyPath("Opacity"));
storyBoard.Children.Add(dblAnime);
storyBoard.Begin();

DoubleAnimationはTimelineのサブクラスです。Double型のプロパティを変換させる動画エフェクトの一つ。OpacityはDouble型のプロパティなので、Opacityに使える。

(プログラミングの専門用語わからなくて表しにくいです><)

PortAudioの低遅延について

リアルタイムの要求はちょっと厳しい場合、
私はPortAudioのDirectSound HostAPIを使う
(PortAudioのコンパイル時DS以外全部禁止した)

しかしそれでも遅延が長いようだ
ネットで検索して、
http://www.portaudio.com/docs/latency.html
←これは出った。

変数PA_MIN_LATENCY_MSECについて何か書いてあるが
私のプログラムのユーザーをこの設定させるのはよくないと思う。

だから私はPortAudioのソースコードにこれに関する関数
PaWinDs_GetMinLatencySeconds
を編集して再コンパイルした。
環境変数から読み込みではなく直接に何かの値を返す。

これで、できた

アンタイトル

確かに明らかに学部生と違っている。
授業は学部生の時ほど多くない。
でも授業以外に全部は自由な時間のわけではない。
先生は何かの「プロジェクト」をしていて、
院生たちはそのプロジェクトに手伝って勉強になれる。

私もそうだ。

私の先生はLinuxシステムで何か(「他の人に内緒」って言ったんだが)を研究している。
私はあのOSにとても詳しくない。進めにくい。
計算機室の先輩と私二人で長い時間にそのプロジェクトに何の進歩も取得していなかった。
先生は待ち焦がれて…

今日夕飯の前頃、やっと少し進んでた。
よかったよかったって思って晩に計算機室に行かずに寮で休みに決まった。
結局寮で何もやらずにこんな時間になった。
自分もわかった、時間は無駄に使われたこと。

foobarのランダム再生強化プラグイン

foobarのプレイリストに曲は500以上あるのに
なんでランダム再生の時いつも少ない幾つの何曲ばかり再生してる?

友たちは「そのランダム、規律あるよ」って教えてくれた。

じゃあ自分でランダム再生支援のプラグインを作ってみよう
MT19937を使おう

そして:
http://173.224.214.51/ftp/foo_mt19937_rand.7z (link is now unavailable)

最初のバージョンのソースコード:


#include "sdk\foobar2000.h"
#include "boost\random.hpp"

DECLARE_COMPONENT_VERSION("MT19937 Randomize","0.1",
"Copyright 2011 LeiMing\n"
"http://d.hatena.ne.jp/sorayukinoyume\n"
"Powered by Boost::Random\n"
);

VALIDATE_COMPONENT_FILENAME("foo_mt19937_rand.dll");

class RandomMod : public play_callback_impl_base {
public:
boost::random::mt19937 rng;

RandomMod() : play_callback_impl_base(flag_on_playback_starting) {
rng.seed(GetTickCount());
}

unsigned get_flags() {
return flag_on_playback_starting;
}

void on_playback_starting(play_control::t_track_command p_command,bool p_paused) {
if(p_command == play_control::track_command_next) {
static_api_ptr_t pPlayList;

int nOrder = pPlayList->playback_order_get_active();
const char* strOrder = pPlayList->playback_order_get_name(nOrder);

if(strOrder != 0 && *strOrder == 'R' && strOrder[1] == 'a') {
int pl = pPlayList->get_active_playlist();
int total = pPlayList->playlist_get_item_count(pl);

pPlayList->queue_flush();
pPlayList->queue_add_item_playlist(pl, rng() % total);
}
}
}
};

RandomMod* rm;

class myinitquit : public initquit {
public:
void on_init() {
if(!rm)
rm = new RandomMod();
}
void on_quit() {
delete rm;
}
};

static initquit_factory_t g_myinitquit_factory;

英語版だけにテストした

自作PCゆびっと

この間暇々(←てまえ!本当ですか!)してるから何かを作ってみようと思って
前にXNAの本を買ったからXNAで何かを作ろう。
考えたらゆびっとのエンゲージはそんなに難しいもないので試しに作る。

Update関数とDraw関数、前者はゲームの論理で後者はゲームの画面表示。
まず、操作はキーボードの1〜9に決まって
画面に九つのボタンを表示する。
普通のボタン、押せるボタン、失敗ボタン、成功ボタン
だからボタンのクラスを作った。
Drawにボタンを表示する。

Updateに、キーボードのステータスを検査してボタンのステータスを変更する。

何時か普通のボタンはおせるボタンに変更するのは、自作スクリプトから取得すればいい。
そして、音楽の再生はportaudioを使う。
MediaPlayer.Playも使えるが、再生中の時間の取得はかなり重い。
スクリプトと同期しにくい

とりあえず二日間にこの自作ゆびっと動ける。
http://ftp.sora.info.tm/lm_jubeat.7z

メデタシメデタシ

(このブログを書きながら日本語能力はかなり不足に感じるorz)