Skip to content

Instantly share code, notes, and snippets.

@mirichi
Created January 3, 2015 07:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mirichi/77968e571d01082814a9 to your computer and use it in GitHub Desktop.
Save mirichi/77968e571d01082814a9 to your computer and use it in GitHub Desktop.
OggのファイルアクセスをIOオブジェクト経由に変更
#include "ruby.h"
#include "ruby/encoding.h"
#include "vorbis/vorbisfile.h"
// RubyのSoundOggクラス
static VALUE cSoundOgg;
// Rubyの例外オブジェクト
static VALUE eSoundOggError;
// RubyのSoundOggオブジェクトが持つC構造体
struct SoundOgg {
OggVorbis_File ovf;
vorbis_info *info;
VALUE vio;
};
// プロトタイプ宣言
static void SoundOgg_mark(void *s);
static void SoundOgg_free(void *s);
static size_t SoundOgg_memsize(const void *s);
// TypedData用の型データ
const rb_data_type_t SoundOgg_data_type = {
"SoundOgg",
{
SoundOgg_mark, // マーク関数
SoundOgg_free, // 解放関数
SoundOgg_memsize, // サイズ関数
},
NULL, NULL
};
// GCのマークで呼ばれるマーク関数
static void SoundOgg_mark(void *s)
{
struct SoundOgg *so = (struct SoundOgg *)s;
// マーク
rb_gc_mark(so->vio);
}
// GCで回収されたときに呼ばれる解放関数
static void SoundOgg_free(void *s)
{
struct SoundOgg *so = (struct SoundOgg *)s;
ov_clear(&so->ovf);
so->info = NULL;
}
// ObjectSpaceからのサイズの問い合わせに応答する
static size_t SoundOgg_memsize(const void *s)
{
// ざっくり
return sizeof(struct SoundOgg);
}
// SoundOgg.newするとまずこれが呼ばれ、次にinitializeが呼ばれる
static VALUE SoundOgg_allocate(VALUE klass)
{
VALUE obj;
struct SoundOgg *so;
// RubyのTypedData型オブジェクトを生成する
obj = TypedData_Make_Struct(klass, struct SoundOgg, &SoundOgg_data_type, so);
so->info = NULL;
// 生成したSoundOggオブジェクトを返す
return obj;
}
// コールバック関数SoundOgg_read
size_t SoundOgg_read(void *buf, size_t blocksize, size_t readsize, void *f)
{
VALUE obj = (VALUE)f;
VALUE vstr;
vstr = rb_funcall(obj, rb_intern_const("read"), 1, UINT2NUM(blocksize * readsize));
Check_Type(vstr, T_STRING);
memcpy(buf, RSTRING_PTR(vstr), RSTRING_LEN(vstr));
return RSTRING_LEN(vstr);
}
// コールバック関数SoundOgg_seek
int SoundOgg_seek(void *f, ogg_int64_t offset, int whence)
{
VALUE obj = (VALUE)f;
int result;
result = NUM2INT(rb_funcall(obj, rb_intern_const("seek"), 2, LL2NUM(offset), INT2NUM(whence)));
return result;
}
// コールバック関数SoundOgg_close
int SoundOgg_close(void *f)
{
VALUE obj = (VALUE)f;
int result;
result = NUM2INT(rb_funcall(obj, rb_intern_const("close"), 0));
return result;
}
// コールバック関数SoundOgg_tell
long SoundOgg_tell(void *f)
{
VALUE obj = (VALUE)f;
long result;
result = NUM2LONG(rb_funcall(obj, rb_intern_const("tell"), 0));
return result;
}
// SoundOgg#initialize
static VALUE SoundOgg_initialize(VALUE self, VALUE vio)
{
struct SoundOgg *so = (struct SoundOgg *)RTYPEDDATA_DATA(self);
ov_callbacks callbacks = {
(size_t (*)(void *, size_t, size_t, void *)) SoundOgg_read,
(int (*)(void *, ogg_int64_t, int)) SoundOgg_seek,
(int (*)(void *)) NULL,
(long (*)(void *)) SoundOgg_tell
};
if (ov_open_callbacks((void *)vio, &so->ovf, NULL, 0, callbacks) != 0) rb_raise(eSoundOggError, "open error");
// Oggファイルの音声フォーマット情報
so->info = ov_info(&so->ovf, -1);
so->vio = vio;
return self;
}
// SoundOgg#rate
static VALUE SoundOgg_im_rate(VALUE self)
{
struct SoundOgg *so = (struct SoundOgg *)RTYPEDDATA_DATA(self);
if (!so->info) rb_raise(eSoundOggError, "disposed object");
return INT2NUM(so->info->rate);
}
// SoundOgg#channels
static VALUE SoundOgg_im_channels(VALUE self)
{
struct SoundOgg *so = (struct SoundOgg *)RTYPEDDATA_DATA(self);
if (!so->info) rb_raise(eSoundOggError, "disposed object");
return INT2NUM(so->info->channels);
}
// SoundOgg#read
static VALUE SoundOgg_im_read(VALUE self, VALUE vsize)
{
struct SoundOgg *so = (struct SoundOgg *)RTYPEDDATA_DATA(self);
char buf[4096];
int readsize;
if (!so->info) rb_raise(eSoundOggError, "disposed object");
readsize = ov_read(&so->ovf, buf, NUM2INT(vsize) > 4096 ? 4096 : NUM2INT(vsize), 0, 2, 1, NULL);
if (readsize < 0) rb_raise(eSoundOggError, "file read error");
return rb_str_new(buf, readsize);
}
void Init_soundogg(void)
{
// 例外定義
eSoundOggError = rb_define_class( "SoundOggError", rb_eRuntimeError );
// SoundOggクラス生成
cSoundOgg = rb_define_class("SoundOgg", rb_cObject);
rb_define_private_method(cSoundOgg, "initialize", SoundOgg_initialize, 1);
rb_define_method(cSoundOgg, "rate", SoundOgg_im_rate, 0);
rb_define_method(cSoundOgg, "channels", SoundOgg_im_channels, 0);
rb_define_method(cSoundOgg, "read", SoundOgg_im_read, 1);
// SoundOggオブジェクトを生成した時にinitializeの前に呼ばれるメモリ割り当て関数登録
rb_define_alloc_func(cSoundOgg, SoundOgg_allocate);
}
// int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos); // シーク
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment