RSS ログイン
Date==== Time==== Update==== Time==== Title==== [[W]WRITE [RET]READ [?]HELP]
2024-12-01 22:34:06 2024-12-06 04:52:03 【備忘録】Linux上でC言語を使って音楽CDを再生する
TEXT FILE (   5KiB ) を受信しますか? [Y]/[N] > Y

Linux C言語 Linux CD

はじめに

多分もっといいやり方有ると思います、ChatGPTに聞きながら頑張りました。。。
あと、私のコードは個性が強いです、なので使うときはあなた達の個性に合わせて変換してください。

結論

(このためにコードを手直ししてます)
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//CDのデバイスファイル
#define CDROM_DEVICE "/dev/cdrom"
//1フレームあたりのバイト数
#define FRAME_SIZE 2352
//CDの標準サンプルレート
#define SAMPLE_RATE 44100
//チャンネル数(2でステレオ、1でモノラル、大体2)
#define CHANNELS 2

int main() {
	int FD = open(CDROM_DEVICE, O_RDONLY);
	if (FD == -1) {
		perror("CDを開けませんでした");
		return 1;
	}

	struct cdrom_tochdr tochdr;
	if (ioctl(FD, CDROMREADTOCHDR, &tochdr) == -1) {
		perror("TOCを読み込めませんでした");
		close(FD);
		return 1;
	}

	printf("トラック数%d〜%d\n", tochdr.cdth_trk0, tochdr.cdth_trk1);

	//読み込みたいトラック番号
	int TRACK = 1;
	if (TRACK < tochdr.cdth_trk0 || TRACK > tochdr.cdth_trk1) {
		fprintf(stderr, "トラック番号が不正です: %d\n", TRACK);
		close(FD);
		return 1;
	}

	//トラック情報を取得
	struct cdrom_tocentry tocentry_start, tocentry_end;
	tocentry_start.cdte_track = TRACK;
	tocentry_start.cdte_format = CDROM_LBA;

	tocentry_end.cdte_track = TRACK + 1;
	tocentry_end.cdte_format = CDROM_LBA;

	if (ioctl(FD, CDROMREADTOCENTRY, &tocentry_start) == -1 ||
		ioctl(FD, CDROMREADTOCENTRY, &tocentry_end) == -1) {
		perror("TOCのエントリーを読み込めませんでした");
		close(FD);
		return 1;
	}

	int START_LBA = tocentry_start.cdte_addr.lba;
	int END_LBA = tocentry_end.cdte_addr.lba;

	printf("トラック:%d: LBA%dから%d\n", TRACK, START_LBA, END_LBA - 1);

	//ALSAを初期化
	snd_pcm_t *PCM_HANDLE;
	snd_pcm_hw_params_t *PARAM;
	int ERR;

	if ((ERR = snd_pcm_open(&PCM_HANDLE, "default", SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
		fprintf(stderr, "PCMデバイスを開けませんでした: %s\n", snd_strerror(ERR));
		close(FD);
		return 1;
	}

	snd_pcm_hw_params_malloc(&PARAM);
	snd_pcm_hw_params_any(PCM_HANDLE, PARAM);
	snd_pcm_hw_params_set_access(PCM_HANDLE, PARAM, SND_PCM_ACCESS_RW_INTERLEAVED);
	snd_pcm_hw_params_set_format(PCM_HANDLE, PARAM, SND_PCM_FORMAT_S16_LE);
	snd_pcm_hw_params_set_channels(PCM_HANDLE, PARAM, CHANNELS);
	snd_pcm_hw_params_set_rate(PCM_HANDLE, PARAM, SAMPLE_RATE, 0);

	if ((ERR = snd_pcm_hw_params(PCM_HANDLE, PARAM)) < 0) {
		fprintf(stderr, "死: %s\n", snd_strerror(ERR));
		snd_pcm_close(PCM_HANDLE);
		close(FD);
		return 1;
	}

	snd_pcm_hw_params_free(PARAM);

	//トラックを読み取る
	int nFLAME = 10;
	char BUFFER[FRAME_SIZE * nFLAME];
	struct cdrom_read_audio audio_data;

	audio_data.addr_format = CDROM_LBA;
	audio_data.nframes = nFLAME;
	audio_data.buf = BUFFER;

	for (int lba = START_LBA; lba < END_LBA; lba += nFLAME) {
		audio_data.addr.lba = lba;

		if (ioctl(FD, CDROMREADAUDIO, &audio_data) == -1) {
			perror("オーディオデータを読めませんでした");
			break;
		}

		printf("%dから%dを読み込みました\n", lba, lba + nFLAME - 1 > END_LBA ? END_LBA : lba + nFLAME - 1);

		//ALSAに流し込む
		if ((ERR = snd_pcm_writei(PCM_HANDLE, BUFFER, nFLAME * (FRAME_SIZE / 4))) < 0) {
			fprintf(stderr, "Playback error: %s\n", snd_strerror(ERR));
			snd_pcm_prepare(PCM_HANDLE);
		}
	}

	//終了処理
	snd_pcm_drain(PCM_HANDLE);
	snd_pcm_close(PCM_HANDLE);
	close(FD);
	return 0;
}

実演

Youtubeに再生動画上げました↓
https://youtu.be/0W8t_TxYlfg
もしかしたら消えてる可能性有るので一応此処にも

説明欄
うちのMisskey鯖が雑魚すぎてでかい動画は無理なので、Youtubeに、、、
いつかブログに書く予定です、書いたらここに載せますね!

倫理的に音質をひどいぐらい劣化させてます、カセットテープ理論です、
カセットテープ理論っていうのは、昔は曲をダビングして友達に渡すのは合法だったんですよ、なぜならカセットテープはコピーすれば劣化するので、、、
その理論をデジタル社会の今に使ったわけです、どうです?ひどいほど劣化してるでしょう

終わり

あとは矢印キーでの操作でも搭載すればいい感じだと思います、、、
Python + ラズパイで、ボタン操作とかも実装してもいいかもしれない、私はそうする
Pythonではないけど、Javaだけど