LoginSignup
0
0

More than 5 years have passed since last update.

DebianでAudio CDにアクセス

Posted at

調べ事をするために作ったサンプルプログラムです。
DebianでAudio CDにアクセスするサンプルが少なかったのでここに置きます。
Debian 9.5にてコンパイルと動作確認を行いました。

cdrom.c
#include <stdio.h>              // printf, perror
#include <fcntl.h>              // open
#include <unistd.h>             // close, write
#include <sys/ioctl.h>          // ioctl
#include <string.h>             // memset, memcpy
#include <stdlib.h>             // malloc, free
#include <linux/cdrom.h>        //
// ----------------------------------------------------------------------------
#define LBA2MIN(l)      (__u8)((l / CD_FRAMES) / CD_SECS)
#define LBA2SEC(l)      (__u8)((l / CD_FRAMES) % CD_SECS)
#define LBA2FRAME(l)    (__u8)(l % CD_FRAMES)
#define MSF2LBA(m,s,f)  (int)((m * CD_SECS + s) * CD_FRAMES + f - CD_MSF_OFFSET)
// ----------------------------------------------------------------------------
int cdrom_open(const char *pathname, int flags, mode_t mode)
{
    int fd;

    if ((fd = open(pathname, flags, mode)) < 0)
        perror("cdrom_open: open");

    return fd;
}

// ----------------------------------------------------------------------------
int cdrom_close(int *fd)
{
    int ret;

    if ((ret = close(*fd)) < 0)
        perror("cdrom_close: close");

    return ret;
}

// ----------------------------------------------------------------------------
off_t cdrom_lseek(int *fd, off_t offset, int whence)
{
    off_t ret;

    if ((ret = lseek(*fd, offset, whence)) < 0)
        perror("cdrom_lseek: lseek");

    return ret;
}

// ----------------------------------------------------------------------------
ssize_t cdrom_read(int *fd, void *buf, size_t count)
{
    ssize_t ret;

    if ((ret = read(*fd, buf, count)) < 0)
        perror("cdrom_read: read");

    return ret;
}

// ----------------------------------------------------------------------------
ssize_t cdrom_write(int *fd, const void *buf, size_t count)
{
    ssize_t ret;

    if ((ret = write(*fd, buf, count)) < 0)
        perror("cdrom_write: write");

    return ret;
}

// ----------------------------------------------------------------------------
int cdrom_ioctl(int *fd, unsigned long request, void *argp)
{
    int ret;

    if ((ret = ioctl(*fd, request, argp)) < 0)
        perror("cdrom_ioctl: ioctl");

    return ret;
}

// ----------------------------------------------------------------------------
int cdrom_read_tochdr(int *fd, struct cdrom_tochdr *header)
{
    int ret;

    memset(header, 0, sizeof(struct cdrom_tochdr));
    if ((ret = ioctl(*fd, CDROMREADTOCHDR, header)) < 0)
        perror("cdrom_read_tochdr: ioctl");

    return ret;
}

// ----------------------------------------------------------------------------
int cdrom_read_tocentry(int *fd, struct cdrom_tocentry *entry)
{
    int ret;
    struct cdrom_tocentry p;

    memset(&p, 0, sizeof(struct cdrom_tocentry));
    p.cdte_format = entry->cdte_format;
    p.cdte_track = entry->cdte_track;
    if ((ret = ioctl(*fd, CDROMREADTOCENTRY, &p)) < 0)
        perror("cdrom_read_tocentry: ioctl");
    memcpy(entry, &p, sizeof(struct cdrom_tocentry));

    return ret;
}

// ----------------------------------------------------------------------------
int cdrom_reset(int *fd)
{
    int ret;

    if ((ret = ioctl(*fd, CDROMRESET, 0)) < 0)
        perror("cdrom_reset: ioctl");

    return ret;
}

// ----------------------------------------------------------------------------
int cdrom_select_speed(int *fd, int speed)
{
    int ret;

    if (!speed)
        speed = 0xffff;         // set to max
    else
        speed *= 177;           // Nx to kbytes/s

    if ((ret = ioctl(*fd, CDROM_SELECT_SPEED, speed)) < 0)
        perror("cdrom_select_speed: ioctl");

    return ret;
}

// ----------------------------------------------------------------------------
int cdrom_get_mcn(int *fd, struct cdrom_mcn *mcn)
{
    int ret = 0;

    memset(mcn, 0, sizeof(struct cdrom_mcn));
    if ((ret = ioctl(*fd, CDROM_GET_MCN, mcn)) < 0)
        perror("cdrom_get_mcn: ioctl");

    return ret;
}

// ----------------------------------------------------------------------------
int cdrom_read_audio(int *fd, struct cdrom_read_audio *ra)
{
    int ret = 0;

    memset(ra->buf, 0, (ra->nframes * CD_FRAMESIZE_RAW));
    if ((ret = ioctl(*fd, CDROMREADAUDIO, ra)) < 0)
        perror("cdrom_read_audio: ioctl");

    return ret;
}

// ----------------------------------------------------------------------------
int main(int argc, char *argv[])
{
    int ret = 0;
    int ifd, ofd;
    char *ipathname = "/dev/cdrom";
    char *opathname = "./dump.bin";
    struct cdrom_tochdr header;
    struct cdrom_tocentry entry[99];
    struct cdrom_mcn mcn;
    struct cdrom_read_audio ra;
    int i, trk, lba0, lba1;
// --- cdrom_open -------------------------------------------------------------
    if ((ifd = cdrom_open(ipathname, O_RDONLY | O_NONBLOCK, 0)) < 0)
        return -1;
// --- cdrom_reset ------------------------------------------------------------
/*  if (cdrom_reset(&ifd) < 0) {
        cdrom_close(&ifd);
        return -1;
    }*/
// --- cdrom_select_speed -----------------------------------------------------
    if (cdrom_select_speed(&ifd, 0) < 0) {
        cdrom_close(&ifd);
        return -1;
    }
// --- cdrom_read_tochdr ------------------------------------------------------
    if (cdrom_read_tochdr(&ifd, &header) < 0) {
        cdrom_close(&ifd);
        return -1;
    }
// --- cdrom_get_mcn ----------------------------------------------------------
    if (cdrom_get_mcn(&ifd, &mcn) < 0) {
        cdrom_close(&ifd);
        return -1;
    }
// --- cdrom_read_tocentry ----------------------------------------------------
    for (i = 0, trk = header.cdth_trk0; trk <= header.cdth_trk1 + 1; i++, trk++) {
        if (trk >= header.cdth_trk0 && trk <= header.cdth_trk1)
            entry[i].cdte_track = trk;
        else if (trk > header.cdth_trk1)
            entry[i].cdte_track = CDROM_LEADOUT;
        entry[i].cdte_format = CDROM_LBA;
        if (cdrom_read_tocentry(&ifd, &entry[i]) < 0) {
            cdrom_close(&ifd);
            return -1;
        }
    }
// --- cdrom_read_audio -------------------------------------------------------
#if 0
    if ((ofd = cdrom_open(opathname, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR)) < 0) {
        ret = -1;
    } else {
        ra.addr_format = CDROM_LBA; // CDROM_LBA or CDROM_MSF
        ra.nframes = 50;        // number of 2352-byte-frames to read at once
        // frame buffer (size: nframes*2352 bytes)
        if ((ra.buf = malloc(ra.nframes * CD_FRAMESIZE_RAW)) == NULL) {
            perror("malloc:ra.buf");
            ret = -1;
            goto extit_loop2;
        }
        // frame address
        for (i = 0, trk = header.cdth_trk0; trk <= header.cdth_trk1; i++, trk++);
        if (entry[0].cdte_format == CDROM_LBA) {
            lba0 = entry[0].cdte_addr.lba;
            lba1 = entry[i].cdte_addr.lba;
        } else {
            lba0 = MSF2LBA(entry[0].cdte_addr.msf.minute, entry[0].cdte_addr.msf.second, entry[0].cdte_addr.msf.frame);
            lba1 = MSF2LBA(entry[i].cdte_addr.msf.minute, entry[i].cdte_addr.msf.second, entry[i].cdte_addr.msf.frame);
        }
        for (ra.addr.lba = lba0; (ra.addr.lba + ra.nframes) < lba1; ra.addr.lba += ra.nframes) {
            printf("lba = %6d\r", ra.addr.lba);
            if (cdrom_read_audio(&ifd, &ra) < 0) {
                ret = -1;
                goto extit_loop1;
            }
            if (cdrom_write(&ofd, ra.buf, ra.nframes * CD_FRAMESIZE_RAW) < 0) {
                ret = -1;
                goto extit_loop1;
            }
        }
        ra.nframes = 1;
        for (; ra.addr.lba < lba1; ra.addr.lba += ra.nframes) {
            printf("lba = %6d\r", ra.addr.lba);
            if (cdrom_read_audio(&ifd, &ra) < 0) {
                ret = -1;
                goto extit_loop1;
            }
            if (cdrom_write(&ofd, ra.buf, ra.nframes * CD_FRAMESIZE_RAW) < 0) {
                ret = -1;
                goto extit_loop1;
            }
        }
      extit_loop1:
        printf("lba = %6d\n", ra.addr.lba);
        free(ra.buf);
      extit_loop2:
        if ((cdrom_close(&ofd)) < 0)
            ret = -1;
    }
#endif
// --- cdrom_close ------------------------------------------------------------
    if (cdrom_close(&ifd) < 0)
        ret = -1;
// --- debug print ------------------------------------------------------------
    printf("start track=%02u\n", header.cdth_trk0); // start track
    printf("end track  =%02u\n", header.cdth_trk1); // end track
    printf("\n");
    for (i = 0; i < sizeof(mcn.medium_catalog_number); i++)
        printf("mcn[%02d]    =%02x\n", i, mcn.medium_catalog_number[i]);
    printf("\n");
    for (i = 0, trk = header.cdth_trk0; trk <= header.cdth_trk1 + 1; i++, trk++) {
        printf("track      =%02u\n", entry[i].cdte_track);
        printf("adr        =%02x\n", entry[i].cdte_adr);
        printf("ctrl       =%02x\n", entry[i].cdte_ctrl);
        printf("format     =%02x\n", entry[i].cdte_format);
        if (entry[i].cdte_format == CDROM_LBA) {    // CDROM_LBA
            printf("addr lba   =%d\n", entry[i].cdte_addr.lba);
            printf("addr m     =%02u\n", LBA2MIN(entry[i].cdte_addr.lba));
            printf("addr s     =%02u\n", LBA2SEC(entry[i].cdte_addr.lba));
            printf("addr f     =%02u\n", LBA2FRAME(entry[i].cdte_addr.lba));
        } else {                // CDROM_MSF
            printf("addr lba   =%d\n", MSF2LBA(entry[i].cdte_addr.msf.minute, entry[i].cdte_addr.msf.second, entry[i].cdte_addr.msf.frame));
            printf("addr m     =%02u\n", entry[i].cdte_addr.msf.minute);
            printf("addr s     =%02u\n", entry[i].cdte_addr.msf.second);
            printf("addr f     =%02u\n", entry[i].cdte_addr.msf.frame);
        }
        printf("datamode   =%02x\n", entry[i].cdte_datamode);
        printf("\n");
    }
//  printf("%s: %d\n", __FUNCTION__, __LINE__);
// ----------------------------------------------------------------------------
    return ret;
}
Makefile
PROGRAM     =   cdrom
OBJS        =   cdrom.o
CFLAGS      =   -Os -Wall

all         :   $(PROGRAM)

clean       :;  rm -f *.o *~ $(PROGRAM)

$(PROGRAM)  :   $(OBJS)
                $(CC) $(OBJS) $(LDFLAGS) $(LIBS) -o $(PROGRAM)
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0