ページ 1 / 1
ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 16:15
by KEYONN_
最近、ビットフィールドというものを知ったので、
ファミコンに使われる7bitPCMに使えるかも?
と思い、ファイル書き込みをやったのですが、うまくいきません。
具体的には、ビットフィールドのアドレスを得ようとしました。と表示され、
コンパイルエラーが起きてしまいます。
どうすれば、ビットフィールドを使いつつ、ファイルに書き込めるでしょうか?
コード:
#include<stdio.h>
char *m;
struct {
unsigned bit7 : 7;
}b;
void Write(int size)
{
FILE *fp;
fp=fopen("bit7.pcm","wb");
for(int i=0;i<size;i++)
{
b.bit7=m[i];
fwrite(b.bit7,b.bit7,1,fp);
}
fclose(fp);
}
void Load(char fn[],int *size)
{
FILE *fp;
fp=fopen(fn,"rb");
fseek(fp,0x28,SEEK_SET);
fseek(fp,0x28,SEEK_END);
*size=ftell(fp);
fseek(fp,0x28,SEEK_SET);
m=new char[*size];
fread(m,*size,1,fp);
printf("sizeは、%dです。\n",size);
fclose(fp);
}
int main(void)
{
char fn[128];
int size;
printf("ファイル名を入力してください。->");
scanf("%s",fn);
Load(fn,&size);
Write(size);
delete []m;
return 0;
}
Re: ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 17:34
by beatle
bの中のbit7をファイルに書きだすのではなくて,b全体をファイルに書き出すようにすれば良いと思いますよ.
Re: ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 18:24
by non
教えてほしいのですが、
コード:
fseek(fp,0x28,SEEK_SET);
fseek(fp,0x28,SEEK_END);
*size=ftell(fp);
これで、*sizeにはいくらがはいるのですか?
7bitPCMってのを知らないもので・・・
Re: ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 18:45
by KEYONN_
non さんが書きました:教えてほしいのですが、
コード:
fseek(fp,0x28,SEEK_SET);
fseek(fp,0x28,SEEK_END);
*size=ftell(fp);
これで、*sizeにはいくらがはいるのですか?
7bitPCMってのを知らないもので・・・
Wavファイルを読み込んで、先頭0x28バイト(ヘッダ)を消して、7ビットにすれば
いいと思うのですが、b.bit7から&bにかえて、fwriteしたら、
それの10倍くらいの1Mバイトくらいになってしまいました。
本来なら、元のwavファイルの7/8サイズになるはずなのですが…。
Re: ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 18:53
by beatle
一つ注意があります.fwriteは1バイト単位(大抵は1バイトは8ビットです)でしか書き込めません.
ファイルシステムも8ビット単位になっている場合がほとんどです.
7/8にサイズを縮めようと思うなら,自分でchar型配列に1ビットずつずらしながら書き込んでおいて,それを一気にfwriteするとか,そういう工夫が必要です.
Re: ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 19:15
by KEYONN_
beatle さんが書きました:一つ注意があります.fwriteは1バイト単位(大抵は1バイトは8ビットです)でしか書き込めません.
ファイルシステムも8ビット単位になっている場合がほとんどです.
7/8にサイズを縮めようと思うなら,自分でchar型配列に1ビットずつずらしながら書き込んでおいて,それを一気にfwriteするとか,そういう工夫が必要です.
1ビットずつずらすというのは、やはりシフト演算でしょうか?
それか、2倍するとか、2で割るという手もありますね。
ローテートというか、シフトして最上位ビットから、あふれた数値はどうやって取得するのか
分かりません。
Re: ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 19:27
by KEYONN_
コード:
for(int j=1;j<size*7/8+1;j++)
{
m[j-1] <<= 1;
char tmp=m[j]&128;
m[j-1]=m[j-1]|tmp;
}
とりあえず、ビット演算は苦手なので、こんな感じになりましたが、大丈夫でしょうか?
Re: ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 19:44
by beatle
ビットフィールドなどという難しい機能に挑戦するよりも先に,勉強すべきことがいっぱいあるみたいですね.
最低限,以下の質問に答えられる必要があるかと思います
- 128を2進数表現するとどうなるか
- ビット積演算とはなにか
- ビット和演算とはなにか
配列mに具体的に数値を当てはめてみて,手計算してみるのも効果的です.
Re: ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 19:59
by non
KEYONN_ さんが書きました:non さんが書きました:教えてほしいのですが、
コード:
fseek(fp,0x28,SEEK_SET);
fseek(fp,0x28,SEEK_END);
*size=ftell(fp);
これで、*sizeにはいくらがはいるのですか?
7bitPCMってのを知らないもので・・・
Wavファイルを読み込んで、先頭0x28バイト(ヘッダ)を消して、7ビットにすれば
いいと思うのですが、b.bit7から&bにかえて、fwriteしたら、
それの10倍くらいの1Mバイトくらいになってしまいました。
本来なら、元のwavファイルの7/8サイズになるはずなのですが…。
fseek(fp,0x28,SEEK_END);なんて書き方、保障されてましたっけ?
表示するようにして確認した方がいいですよ。
Re: ビットフィールドと7bitPCM
Posted: 2012年1月03日(火) 20:12
by KEYONN_
beatle さんが書きました:ビットフィールドなどという難しい機能に挑戦するよりも先に,勉強すべきことがいっぱいあるみたいですね.
最低限,以下の質問に答えられる必要があるかと思います
- 128を2進数表現するとどうなるか
- ビット積演算とはなにか
- ビット和演算とはなにか
配列mに具体的に数値を当てはめてみて,手計算してみるのも効果的です.
コード:
#include<stdio.h>
int main()
{
unsigned char number=128;
int i;
int tmp[8]={0};
for(i=0;i<8;i++)
{
tmp[7-i]=number%2;
number/=2;
}
for(i=0;i<8;i++)
{
printf("%d",tmp[i]);
}
printf("\n");
return 0;
}
変数numberをcharのままだったら、-10000000になりました。
unsignedにしたところ、10000000になりました。
最上位ビットが1ということは、マイナスになりえるんですね。
ビット積演算は、任意の桁を0にする演算
ビット和演算は、任意の桁を1にする演算
でしょうか?。。。
Re: ビットフィールドと7bitPCM
Posted: 2012年1月04日(水) 10:12
by softya(ソフト屋)
KEYONN_ さんが書きました:ビット積演算は、任意の桁を0にする演算
ビット和演算は、任意の桁を1にする演算
それはそれぞれの演算子の一側面でしかありませんね。
変数同士を演算する場合は別の役割が出てきますよ。
それとビットを扱うときに%d では無く%08xを使いましょう。
Re: ビットフィールドと7bitPCM
Posted: 2012年1月05日(木) 18:06
by KEYONN_
softya(ソフト屋) さんが書きました:KEYONN_ さんが書きました:ビット積演算は、任意の桁を0にする演算
ビット和演算は、任意の桁を1にする演算
それはそれぞれの演算子の一側面でしかありませんね。
変数同士を演算する場合は別の役割が出てきますよ。
それとビットを扱うときに%d では無く%08xを使いましょう。
アドバイスありがとうございます。ソフト屋さん
1010 0101 ビット積変数b1
0100 1111 & ビット積変数b2
--------------
0000 0101 ビット積変数b3
つまり、ビット積変数b2が0なら全て0,1なら値を取り出す事が出来るという事ですね。
1010 0101 ビット和変数b1
0000 1111 | ビット和変数b2
-----------------
1010 1111 ビット和変数b3
つまり、ビット和変数b2が0ならビットを取り出す事ができ、1なら全て1になるという事ですね。
Re: ビットフィールドと7bitPCM
Posted: 2012年1月05日(木) 18:16
by KEYONN_
non さんが書きました:KEYONN_ さんが書きました:non さんが書きました:教えてほしいのですが、
コード:
fseek(fp,0x28,SEEK_SET);
fseek(fp,0x28,SEEK_END);
*size=ftell(fp);
これで、*sizeにはいくらがはいるのですか?
7bitPCMってのを知らないもので・・・
Wavファイルを読み込んで、先頭0x28バイト(ヘッダ)を消して、7ビットにすれば
いいと思うのですが、b.bit7から&bにかえて、fwriteしたら、
それの10倍くらいの1Mバイトくらいになってしまいました。
本来なら、元のwavファイルの7/8サイズになるはずなのですが…。
fseek(fp,0x28,SEEK_END);なんて書き方、保障されてましたっけ?
表示するようにして確認した方がいいですよ。
nonさんへ
コード:
printf("サイズは%dです。",*size);
でサイズを確認しました。
そしたら、24740byteあったwavファイルが
サイズは24780です。になってました。増えてます。おかしいです。
Re: ビットフィールドと7bitPCM
Posted: 2012年1月05日(木) 18:25
by softya(ソフト屋)
KEYONN_ さんが書きました:softya(ソフト屋) さんが書きました:KEYONN_ さんが書きました:ビット積演算は、任意の桁を0にする演算
ビット和演算は、任意の桁を1にする演算
それはそれぞれの演算子の一側面でしかありませんね。
変数同士を演算する場合は別の役割が出てきますよ。
それとビットを扱うときに%d では無く%08xを使いましょう。
アドバイスありがとうございます。ソフト屋さん
1010 0101 ビット積変数b1
0100 1111 & ビット積変数b2
--------------
0000 0101 ビット積変数b3
つまり、ビット積変数b2が0なら全て0,1なら値を取り出す事が出来るという事ですね。
1010 0101 ビット和変数b1
0000 1111 | ビット和変数b2
-----------------
1010 1111 ビット和変数b3
つまり、ビット和変数b2が0ならビットを取り出す事ができ、1なら全て1になるという事ですね。
この2つを上手く使えば特定のビットの値だけを取り出したり、前の特定のビット情報を消して任意の値に置き換える事ができます。これが重要です。
Re: ビットフィールドと7bitPCM
Posted: 2012年1月05日(木) 18:54
by softya(ソフト屋)
ファミコンの仕様を調べて見ましたが、わざわざ7bitのビットストリームに縮める必要があるのでしょうか?
そのまま8bitのデータ(ただし量子化は7bit)で問題ない気がしますが・・・。再生ソフトがわざわざデータ圧縮のために、展開処理を組んであると言う話なんでしょうかね?
Re: ビットフィールドと7bitPCM
Posted: 2012年1月05日(木) 20:53
by beatle
練習がてら組んでみました
コード:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#define SRC_LENGTH (16u)
uint8_t read7bits(const uint8_t *buf, size_t pos_in_bits)
{
uint16_t tmp = buf[pos_in_bits / 8] | (buf[pos_in_bits / 8 + 1] << 8);
return (uint8_t)((tmp >> (pos_in_bits % 8)) & 0x007fu);
}
void write7bits(uint8_t *buf, size_t pos_in_bits, uint8_t val)
{
const unsigned int shift_width = (pos_in_bits % 8);
uint16_t tmp = buf[pos_in_bits / 8] | (buf[pos_in_bits / 8 + 1] << 8);
tmp &= ~(0x7fu << shift_width);
tmp |= (val << shift_width);
buf[pos_in_bits / 8] = (tmp & 0xffu);
buf[pos_in_bits / 8 + 1] = ((tmp >> 8) & 0xffu);
}
/* return the number of written bits. */
size_t compress(uint8_t *dst, const uint8_t *src, size_t len)
{
size_t si, di_in_bits = 0;
for (si = 0; si < len; ++si)
{
write7bits(dst, di_in_bits, src[si]);
di_in_bits += 7;
}
return di_in_bits;
}
/* return the number of written bytes. */
size_t decompress(uint8_t *dst, const uint8_t *src, size_t len)
{
size_t si_in_bits, di = 0;
for (si_in_bits = 0; si_in_bits + 7 - 1 < len * 8; si_in_bits += 7)
{
dst[di] = read7bits(src, si_in_bits);
di++;
}
return di;
}
void print_binary(unsigned char *buf, size_t len)
{
size_t i;
for (i = 0; i < len; ++i)
{
printf("%02x", buf[i]);
if (i < len - 1)
{
printf(" ");
}
}
}
int main(void)
{
uint8_t src[SRC_LENGTH];
uint8_t buf[(SRC_LENGTH * 7 + 7) / 8];
int i;
size_t buf_len/*, src_len*/;
/* set to src */
for (i = 0; i < sizeof(src); ++i)
{
src[i] = 0x10 + i;
}
printf("compressing src -> buf\n");
buf_len = compress(buf, src, sizeof(src)) / 8;
printf("src: ");
print_binary(src, sizeof(src));
printf("\nbuf: ");
print_binary(buf, buf_len);
printf("\n");
/* src_len = decompress(src, buf, buf_len); */
return 0;
}
Re: ビットフィールドと7bitPCM
Posted: 2012年1月06日(金) 03:02
by ISLe
質問者さんは、ビットフィールドを使えば7ビットずつファイルから読み込んだりファイルに書き出したりできるとお考えなのでしょうけど、そういうふうには使えません。
コード:
struct {
unsigned bit7 : 7;
}b;
この(↑)コードは、bの中の7ビットをbit7という名前で読み書きできるようにする、という意味です。
ビットフィールドを使ってできるのは、bの一部分に対する読み書きだけ、です。