【備忘録】Linux上でC言語を使って音楽CDを再生する
作成日:2024-12-01 22:34:06
最新更新日:2024-12-06 04:52:03
はじめに
多分もっといいやり方有ると思います、ChatGPTに聞きながら頑張りました。。。
あと、私のコードは個性が強いです、なので使うときはあなた達の個性に合わせて変換してください。
結論
(このためにコードを手直ししてます)
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/cdrom.h>
#include <sys/ioctl.h>
#include <alsa/asoundlib.h>
//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だけど