ビットフィールドと7bitPCM

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
KEYONN_
記事: 70
登録日時: 14年前

ビットフィールドと7bitPCM

#1

投稿記事 by KEYONN_ » 13年前

最近、ビットフィールドというものを知ったので、
ファミコンに使われる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;
}

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: ビットフィールドと7bitPCM

#2

投稿記事 by beatle » 13年前

bの中のbit7をファイルに書きだすのではなくて,b全体をファイルに書き出すようにすれば良いと思いますよ.

non
記事: 1097
登録日時: 14年前

Re: ビットフィールドと7bitPCM

#3

投稿記事 by non » 13年前

教えてほしいのですが、

コード:

fseek(fp,0x28,SEEK_SET);
fseek(fp,0x28,SEEK_END);
 *size=ftell(fp);
これで、*sizeにはいくらがはいるのですか?
7bitPCMってのを知らないもので・・・
non

アバター
KEYONN_
記事: 70
登録日時: 14年前

Re: ビットフィールドと7bitPCM

#4

投稿記事 by KEYONN_ » 13年前

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サイズになるはずなのですが…。

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: ビットフィールドと7bitPCM

#5

投稿記事 by beatle » 13年前

一つ注意があります.fwriteは1バイト単位(大抵は1バイトは8ビットです)でしか書き込めません.
ファイルシステムも8ビット単位になっている場合がほとんどです.

7/8にサイズを縮めようと思うなら,自分でchar型配列に1ビットずつずらしながら書き込んでおいて,それを一気にfwriteするとか,そういう工夫が必要です.

アバター
KEYONN_
記事: 70
登録日時: 14年前

Re: ビットフィールドと7bitPCM

#6

投稿記事 by KEYONN_ » 13年前

beatle さんが書きました:一つ注意があります.fwriteは1バイト単位(大抵は1バイトは8ビットです)でしか書き込めません.
ファイルシステムも8ビット単位になっている場合がほとんどです.

7/8にサイズを縮めようと思うなら,自分でchar型配列に1ビットずつずらしながら書き込んでおいて,それを一気にfwriteするとか,そういう工夫が必要です.
1ビットずつずらすというのは、やはりシフト演算でしょうか?
それか、2倍するとか、2で割るという手もありますね。
ローテートというか、シフトして最上位ビットから、あふれた数値はどうやって取得するのか
分かりません。

アバター
KEYONN_
記事: 70
登録日時: 14年前

Re: ビットフィールドと7bitPCM

#7

投稿記事 by KEYONN_ » 13年前

コード:

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;
}
とりあえず、ビット演算は苦手なので、こんな感じになりましたが、大丈夫でしょうか?

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: ビットフィールドと7bitPCM

#8

投稿記事 by beatle » 13年前

ビットフィールドなどという難しい機能に挑戦するよりも先に,勉強すべきことがいっぱいあるみたいですね.

最低限,以下の質問に答えられる必要があるかと思います
  • 128を2進数表現するとどうなるか
  • ビット積演算とはなにか
  • ビット和演算とはなにか
配列mに具体的に数値を当てはめてみて,手計算してみるのも効果的です.

non
記事: 1097
登録日時: 14年前

Re: ビットフィールドと7bitPCM

#9

投稿記事 by non » 13年前

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

アバター
KEYONN_
記事: 70
登録日時: 14年前

Re: ビットフィールドと7bitPCM

#10

投稿記事 by KEYONN_ » 13年前

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にする演算

でしょうか?。。。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: ビットフィールドと7bitPCM

#11

投稿記事 by softya(ソフト屋) » 13年前

KEYONN_ さんが書きました:ビット積演算は、任意の桁を0にする演算
ビット和演算は、任意の桁を1にする演算
それはそれぞれの演算子の一側面でしかありませんね。
変数同士を演算する場合は別の役割が出てきますよ。

それとビットを扱うときに%d では無く%08xを使いましょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
KEYONN_
記事: 70
登録日時: 14年前

Re: ビットフィールドと7bitPCM

#12

投稿記事 by KEYONN_ » 13年前

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になるという事ですね。

アバター
KEYONN_
記事: 70
登録日時: 14年前

Re: ビットフィールドと7bitPCM

#13

投稿記事 by KEYONN_ » 13年前

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です。になってました。増えてます。おかしいです。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: ビットフィールドと7bitPCM

#14

投稿記事 by softya(ソフト屋) » 13年前

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つを上手く使えば特定のビットの値だけを取り出したり、前の特定のビット情報を消して任意の値に置き換える事ができます。これが重要です。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 14年前
住所: 東海地方
連絡を取る:

Re: ビットフィールドと7bitPCM

#15

投稿記事 by softya(ソフト屋) » 13年前

ファミコンの仕様を調べて見ましたが、わざわざ7bitのビットストリームに縮める必要があるのでしょうか?
そのまま8bitのデータ(ただし量子化は7bit)で問題ない気がしますが・・・。再生ソフトがわざわざデータ圧縮のために、展開処理を組んであると言う話なんでしょうかね?
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

beatle
記事: 1281
登録日時: 13年前
住所: 埼玉
連絡を取る:

Re: ビットフィールドと7bitPCM

#16

投稿記事 by beatle » 13年前

練習がてら組んでみました

コード:

#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;
}

ISLe
記事: 2650
登録日時: 14年前
連絡を取る:

Re: ビットフィールドと7bitPCM

#17

投稿記事 by ISLe » 13年前

質問者さんは、ビットフィールドを使えば7ビットずつファイルから読み込んだりファイルに書き出したりできるとお考えなのでしょうけど、そういうふうには使えません。

コード:

struct {
    unsigned bit7 : 7;
}b;
この(↑)コードは、bの中の7ビットをbit7という名前で読み書きできるようにする、という意味です。
ビットフィールドを使ってできるのは、bの一部分に対する読み書きだけ、です。

閉鎖

“C言語何でも質問掲示板” へ戻る