├── .gitignore ├── .travis.yml ├── COPYING ├── COPYING.LIB ├── README ├── README.fedora ├── README.md ├── VERSION ├── basictools ├── .gitignore ├── Makefile ├── himddiskid.c ├── himdformat.c ├── himdformat_scg.c ├── himdscsitest.c ├── mp3dec.c └── mp3key.c ├── build ├── common.pri ├── cross_wrapper_mingw.sh ├── get_version.sh ├── install_dependencies.sh ├── installunix.pri ├── libgcrypt.pri ├── libglib.pri ├── libid3tag.pri ├── libmad.pri ├── libmad_optimize-flags.patch ├── libtaglib.pri ├── libusb.pri ├── libz.pri ├── mingw-bundledlls ├── package_build.sh ├── toolchain-i686-w64-mingw32.cmake └── toolchain-x86_64-w64-mingw32.cmake ├── docs ├── himdcli.1 ├── internals │ ├── AVC Descriptor Mechanism 1.0.pdf │ ├── AVC Digital Interface Commands 3.0.pdf │ ├── AVC Disc Subunit 1.0.pdf │ ├── AVC MD Audio 1.0.pdf │ └── README.md ├── netmdcli.1 └── qhimdtransfer.1 ├── himdcli ├── .gitignore ├── himdcli.c └── himdcli.pro ├── libhimd ├── .gitignore ├── codecinfo.c ├── codecinfo.h ├── encryption.c ├── frag.c ├── himd.c ├── himd.h ├── himd_private.h ├── himdll.h ├── libhimd.pro ├── mdstream.c ├── mp3download.c ├── mp3tools.c ├── sony_oma.c ├── sony_oma.h ├── trackindex.c └── use_libhimd.pri ├── libnetmd ├── .cdtproject ├── .gitignore ├── .project ├── CHANGELOG ├── Doxyfile ├── LICENCE.TXT ├── common.c ├── common.h ├── const.h ├── documentation │ ├── howto.html │ ├── index.html │ ├── index_files │ │ ├── logo.html │ │ ├── openwindow.html │ │ ├── pix.html │ │ ├── showimages.html │ │ └── styleNN.html │ ├── proto.txt │ ├── protocol.html │ └── protocol2.txt ├── error.c ├── error.h ├── hotplug-netmd ├── libnetmd.c ├── libnetmd.h ├── libnetmd.pro ├── libnetmd_extended.h ├── log.c ├── log.h ├── minidisc.usermap ├── netmd_dev.c ├── netmd_dev.h ├── omgutils-patch.txt ├── playercontrol.c ├── playercontrol.h ├── secure.c ├── secure.h ├── trackinformation.c ├── trackinformation.h ├── use_libnetmd.prl ├── utilities │ ├── char-to-hex.c │ ├── cleanup.pl │ ├── diff.txt │ ├── hex-to-char.c │ └── logparse.pl ├── utils.c └── utils.h ├── md.pro ├── netmd ├── .gitignore ├── README ├── TODO ├── downloadhack.py ├── dump_md.py ├── etc │ ├── 20-netmd.fdi │ ├── README │ └── netmd.rules ├── libnetmd.py ├── libusb1.py ├── lsmd.py ├── lsusb.py ├── mdctl.py ├── upload.py └── usb1.py ├── netmdcli ├── .gitignore ├── netmdcli.c └── netmdcli.pro ├── qhimdtransfer ├── .gitignore ├── icons.qrc ├── icons │ ├── add_group.png │ ├── arrow_download.png │ ├── arrow_upload.png │ ├── connect.png │ ├── delete.png │ ├── download_to_md.png │ ├── format.png │ ├── help.png │ ├── info.png │ ├── qhimdtransfer.ico │ ├── qhimdtransfer.png │ ├── qhimdtransfer_128.png │ ├── qhimdtransfer_16.png │ ├── qhimdtransfer_24.png │ ├── qhimdtransfer_256.png │ ├── qhimdtransfer_32.png │ ├── qhimdtransfer_48.png │ ├── qhimdtransfer_512.png │ ├── qhimdtransfer_64.png │ ├── qhimdtransfer_96.png │ ├── quit.png │ ├── rename.png │ └── upload_from_md.png ├── linux │ └── etc │ │ └── udev │ │ └── 60-minidisc.rules ├── main.cpp ├── qhimdaboutdialog.cpp ├── qhimdaboutdialog.h ├── qhimdaboutdialog.ui ├── qhimddetection.cpp ├── qhimddetection.h ├── qhimddummydetection.cpp ├── qhimdformatdialog.cpp ├── qhimdformatdialog.h ├── qhimdformatdialog.ui ├── qhimdlinuxdetection.cpp ├── qhimdmacdetection.cpp ├── qhimdmainwindow.cpp ├── qhimdmainwindow.h ├── qhimdmainwindow.ui ├── qhimdtransfer.icns ├── qhimdtransfer.pro ├── qhimdtransfer.rc ├── qhimdtransfer_ar.ts ├── qhimdtransfer_br.ts ├── qhimdtransfer_cs.ts ├── qhimdtransfer_da.ts ├── qhimdtransfer_de.ts ├── qhimdtransfer_el.ts ├── qhimdtransfer_es.ts ├── qhimdtransfer_fi.ts ├── qhimdtransfer_fr.ts ├── qhimdtransfer_it.ts ├── qhimdtransfer_ja.ts ├── qhimdtransfer_nb.ts ├── qhimdtransfer_nl.ts ├── qhimdtransfer_pl.ts ├── qhimdtransfer_pt.ts ├── qhimdtransfer_ru.ts ├── qhimdtransfer_sv.ts ├── qhimdtransfer_tr.ts ├── qhimdtransfer_uk.ts ├── qhimduploaddialog.cpp ├── qhimduploaddialog.h ├── qhimduploaddialog.ui ├── qhimdwindetection.cpp ├── qmddevice.cpp ├── qmddevice.h ├── qmdmodel.cpp ├── qmdmodel.h ├── qmdtrack.cpp ├── qmdtrack.h ├── translate.pri ├── util.pri ├── wavefilewriter.cpp └── wavefilewriter.h └── testdata ├── himd ├── HI-MD.IND ├── HMDHIFI │ ├── 00010012.HMA │ ├── ATDATA07.HMA │ ├── MCLIST06.HMA │ ├── MCLIST07.HMA │ ├── TRKIDX07.HMA │ ├── _0010012.HMA │ ├── _MDHIFI.HMA │ └── _RKIDX08.HMA └── README.TXT └── netmd └── captures ├── README └── mz-n710-transfer.pcapng /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.o 3 | *.app 4 | *.swp 5 | *.xcodeproj 6 | *.sln 7 | *.vcxproj* 8 | /.qmake.stash 9 | /.dir-locals.el 10 | /.vs 11 | Info.plist 12 | Makefile* 13 | *.user 14 | qtc-gdbmacros 15 | /bin 16 | /obj 17 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | matrix: 2 | include: 3 | - os: linux 4 | dist: trusty 5 | sudo: required 6 | language: cpp 7 | compiler: clang 8 | env: BUILD_TYPE=linux-native-clang 9 | - os: linux 10 | dist: trusty 11 | sudo: required 12 | language: cpp 13 | compiler: gcc 14 | env: BUILD_TYPE=linux-native-gcc 15 | - os: linux 16 | dist: trusty 17 | sudo: required 18 | language: cpp 19 | compiler: gcc 20 | env: BUILD_TYPE=linux-cross-mingw64 CONFIGURE_COMMAND="sh build/cross_wrapper_mingw.sh qmake" COMPILE_COMMAND="sh build/cross_wrapper_mingw.sh make" 21 | - os: linux 22 | dist: trusty 23 | sudo: required 24 | language: cpp 25 | compiler: gcc 26 | env: BUILD_TYPE=linux-cross-mingw32 CONFIGURE_COMMAND="sh build/cross_wrapper_mingw.sh qmake" COMPILE_COMMAND="sh build/cross_wrapper_mingw.sh make" 27 | - os: osx 28 | osx_image: xcode7.2 29 | language: cpp 30 | compiler: clang 31 | env: BUILD_TYPE=osx-native-clang 32 | 33 | deploy: 34 | provider: releases 35 | api_key: 36 | secure: j5+2N9IDWfxg7cx7AMlubMbqIoYUks4NfIzxnjcraOcQM1i8gOhKde3JjKLfxOgTYQUAlOtX7jHsb1FciNheWsqKz7voDJd++HhsVt4xc5iK+xb3zvNjT5wwgGmti7ltI8VMq9LOCohagc2m4tZl/itEPlMK7pB/AVG3sML/y2onRf2Dzi+vcE1AWNMUciv2Vrwj6E9Wsy/aBHZztMwD/cfMSPHIh746rN2cLfH94Uqzb8gJrwhR/BEMOHGQZd9KjxaWCmYRfotEvYNak1BU4bBaSYAc0mEtg+Ie2jd8COQCf5XWb0t1vflMTJ5RI2htpfX0NoJcoCUcFv5I369fcBTWXQYMD2Emxt4tmrWaZt0yarzzoEdoECYKJ5nOty6vymdsI2R1JDyn8YOQWY94ULk2OOCl1P3OcT7ZhFFjRy8/6Ygp9Xe0/CKCGDgnctRNyQfER2dssjN3YZCHlSSoybjAJ71RU99+hCJQK9SHAqnD4zmCMoPx4bCLnxOLZFxbUHiOlJw+90h7IX2l/fncHr6kBil9Xg+bIcNUK29sQoulIjZdsEGGwNaAQg52xsI7fARlgUnD0M+NPvhoEP+2HHsLbxmG7RcKpGZ+BxZ3TEMLpiFtMa3kyp77r0e53oHb72n6d68mJp2Sao/sMkLBrDLv8S6isrxyDlYARi/cuVQ= 37 | 38 | file: dist/* 39 | file_glob: true 40 | on: 41 | tags: true 42 | skip_cleanup: true 43 | 44 | before_install: 45 | - sh build/install_dependencies.sh 46 | 47 | install: 48 | - git submodule update --init --recursive 49 | 50 | script: 51 | - ${CONFIGURE_COMMAND:-qmake} 52 | - ${COMPILE_COMMAND:-make} 53 | - ${PACKAGE_COMMAND:-sh build/package_build.sh} 54 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | PREREQUISITES 2 | 3 | qmake (you don't need the whole Qt stuff for the non-GUI parts, just qmake) 4 | glib (for the core library) 5 | mad (for MP3 transfer, can be disabled) 6 | libgcrypt (for PCM transfer, can be disabled) 7 | Qt (for the GUI) 8 | pkg-config (if on OSX/MacOS) 9 | 10 | BUILDING 11 | 12 | This project uses the qmake build system to cooperate with the Qt Creator 13 | IDE. To compile in Qt Creator, just open md.pro. To compile at the 14 | command line, run 15 | 16 | qmake 17 | make 18 | 19 | Depending on the default configuration of your system, you will find 20 | the executables in the debug subdirectory, the release subdirectories or 21 | directly in the directories qhimdtransfer and himdtest. 22 | 23 | To disable the optional features, the following keywords are recognized 24 | in the CONFIG variable: 25 | 26 | without_mad -> disables MP3 support; you wont need mad 27 | without_gcrypt -> disables PCM support; you wont need gcrypt 28 | without_gui -> disables qhimdtransfer; you wont need Qt and sox 29 | 30 | So, the minimal configuration is built by using 31 | 32 | qmake CONFIG+=without_mad CONFIG+=without_gcrypt CONFIG+=without_gui 33 | -------------------------------------------------------------------------------- /README.fedora: -------------------------------------------------------------------------------- 1 | Fedora-specific Build/Setup Instructions 2 | ======================================== 3 | 4 | Install build-dependencies: 5 | 6 | sudo dnf install \ 7 | qt5-devel libgcrypt-devel libmad-devel \ 8 | libid3tag-devel glib-devel taglib-devel 9 | 10 | Symlink translation tools: 11 | 12 | sudo ln -s /usr/bin/lupdate-qt5 /usr/bin/lupdate 13 | sudo ln -s /usr/bin/lrelease-qt5 /usr/bin/lrelease 14 | 15 | Build everything: 16 | 17 | qmake-qt5 18 | make 19 | 20 | Create plugdev group and copy udev rules: 21 | 22 | sudo groupadd plugdev 23 | # ... add your user to the plugdev group ... 24 | sudo cp netmd/etc/netmd.rules /etc/udev/rules.d/ 25 | sudo systemctl restart systemd-udevd.service 26 | # ... re-plug the NetMD and/or reboot ... 27 | 28 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 0.9.16 2 | -------------------------------------------------------------------------------- /basictools/.gitignore: -------------------------------------------------------------------------------- 1 | minikey 2 | mp3key 3 | himdformat 4 | -------------------------------------------------------------------------------- /basictools/Makefile: -------------------------------------------------------------------------------- 1 | 2 | CFLAGS=-Wall 3 | 4 | all: himddiskid mp3key himdformat 5 | 6 | clean: 7 | rm -f *.o 8 | rm -f himddiskid mp3key himdformat himdformat_scg himdscsitest -------------------------------------------------------------------------------- /basictools/himddiskid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | #define HIMD_KEY_HANDSHAKE_PKT1 0x30 /* to MD */ 9 | #define HIMD_KEY_HANDSHAKE_PKT2 0x31 /* from MD */ 10 | #define HIMD_KEY_HANDSHAKE_PKT3 0x32 /* to MD */ 11 | #define HIMD_KEY_HANDSHAKE_PKT4 0x33 /* from MD */ 12 | #define HIMD_KEY_UNIQUEID 0x39 13 | #define HIMD_KEY_LEAFID 0x3B 14 | #define HIMD_KEY_DISCID 0x3D 15 | 16 | int main(int argc, char ** argv) 17 | { 18 | int fd; 19 | int res; 20 | int i; 21 | struct sg_io_hdr sg; 22 | unsigned char command[12]; 23 | unsigned char reply[200]; 24 | unsigned char sense[16]; 25 | const unsigned int index = 0; 26 | 27 | if(argc < 2) 28 | { 29 | fputs("Please specify the path to the scsi device\n",stderr); 30 | return 1; 31 | } 32 | 33 | fd = open(argv[1],O_RDWR); 34 | if(fd < 0) 35 | { 36 | perror("Cannot open device"); 37 | return 1; 38 | } 39 | if(ioctl(fd,SG_GET_VERSION_NUM,&i) < 0) 40 | { 41 | perror("ioctl SG_GET_VERSTION_NUM failed. Missing sg support?"); 42 | return 1; 43 | } 44 | command[0] = 0xA4; /* SENSE KEYDATA (HiMD-specific) */ 45 | command[1] = 0; /* LUN 0 */ 46 | command[2] = index >> 24; /* 32 */ 47 | command[3] = index >> 16; /* bits */ 48 | command[4] = index >> 8; /* of */ 49 | command[5] = index; /* index */ 50 | command[6] = 0; 51 | command[7] = 0xBD; /* magic byte, no idea what it means */ 52 | command[8] = 0; /* high byte reply size */ 53 | command[9] = 0x12; /* low byte reply size */ 54 | command[10] = HIMD_KEY_DISCID; 55 | command[11] = 0; 56 | 57 | sg.interface_id = 'S'; 58 | sg.dxfer_direction = SG_DXFER_FROM_DEV; 59 | sg.cmd_len = 12; 60 | sg.mx_sb_len = 16; 61 | sg.iovec_count = 0; 62 | sg.dxfer_len = 0x12; 63 | sg.dxferp = reply; 64 | sg.cmdp = command; 65 | sg.sbp = sense; 66 | sg.timeout = 10000000; 67 | sg.flags = 0; 68 | sg.pack_id = 0; 69 | sg.usr_ptr = NULL; 70 | 71 | res = ioctl(fd,SG_IO,&sg); 72 | if(res < 0) 73 | { 74 | perror("performing SCSI command"); 75 | return 1; 76 | } 77 | 78 | if(sg.sb_len_wr) 79 | { 80 | printf("Getting Disc ID FAILED! Sense data: "); 81 | for(i = 0;i < sg.sb_len_wr;i++) 82 | printf("%02X ",(unsigned char)sense[i]); 83 | putchar('\n'); 84 | return 1; 85 | } 86 | 87 | printf("Disc ID: "); 88 | for(i = 0;i < 16;++i) 89 | printf("%02X",(unsigned char)reply[i+2]); 90 | putchar('\n'); 91 | 92 | close(fd); 93 | return 0; 94 | } 95 | -------------------------------------------------------------------------------- /basictools/himdformat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | int main(int argc, char ** argv) 10 | { 11 | int fd; 12 | int res; 13 | int i; 14 | struct sg_io_hdr sg; 15 | unsigned char command[12]; 16 | unsigned char reply[200]; 17 | unsigned char sense[16]; 18 | 19 | if(argc < 2) 20 | { 21 | fputs("Please specify the path to the scsi device (sgN or sdX)\n",stderr); 22 | return 1; 23 | } 24 | 25 | fd = open(argv[1],O_RDWR); 26 | if(fd < 0) 27 | { 28 | perror("Cannot open device"); 29 | return 1; 30 | } 31 | if(ioctl(fd,SG_GET_VERSION_NUM,&i) < 0) 32 | { 33 | perror("ioctl SG_GET_VERSTION_NUM failed. Missing sg support?"); 34 | return 1; 35 | } 36 | 37 | memset(command,0,12); 38 | command[0] = 0xC2; /* sony special commands */ 39 | command[3] = 0x00; /* subcommand: erase all data (0x00); format (0x01) */ 40 | command[4] = 0x03; /* control flags */ 41 | 42 | sg.interface_id = 'S'; 43 | sg.dxfer_direction = SG_DXFER_NONE; 44 | sg.cmd_len = 12; 45 | sg.mx_sb_len = 16; 46 | sg.iovec_count = 0; 47 | sg.dxfer_len = 0; 48 | sg.dxferp = reply; 49 | sg.cmdp = command; 50 | sg.sbp = sense; 51 | sg.timeout = 10000000; 52 | sg.flags = 0; 53 | sg.pack_id = 0; 54 | sg.usr_ptr = NULL; 55 | 56 | res = ioctl(fd,SG_IO,&sg); 57 | if(res < 0) 58 | { 59 | perror("performing SCSI command"); 60 | return 1; 61 | } 62 | 63 | if(sg.sb_len_wr) 64 | { 65 | printf("Formatting failed! Sense data: "); 66 | for(i = 0;i < sg.sb_len_wr;i++) 67 | printf("%02X ",(unsigned char)sense[i]); 68 | putchar('\n'); 69 | return 1; 70 | } 71 | 72 | close(fd); 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /basictools/himdformat_scg.c: -------------------------------------------------------------------------------- 1 | /* 2 | * himdformat_scg.c - format HiMDs using the generic SCSI abstraction library from cdrtools (libscg) 3 | * 4 | * - requires cdrtools to be installed 5 | * 6 | * - compile with: gcc -D__LINUX_X86_GCC32 himdscsitest.c -I/opt/schily/include -L/opt/schily/lib -lscg -lscgcmd -lschily -o himdscsitest (on 32 bit Linux with gcc) 7 | * - compile with: gcc -D__LINUX_X86_GCC64 himdscsitest.c -I/opt/schily/include -L/opt/schily/lib -lscg -lscgcmd -lschily -o himdscsitest (on 64 bit Linux with gcc) 8 | */ 9 | 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #define SONY_SPECIFIC_COMMAND 0xC2 18 | #define HIMD_ERASE 0x00 19 | #define HIMD_FORMAT 0x01 20 | 21 | #define MAX_DEVICE_LEN 256 22 | #define SCSI_TIMEOUT 20 23 | 24 | int main(int argc, char ** argv) 25 | { 26 | SCSI * scgp = NULL; 27 | char command[12]; 28 | int err = 0; 29 | int ret; 30 | char dev[MAX_DEVICE_LEN]; 31 | char errstr[80]; 32 | char cmdname[] = "himd_format"; 33 | struct scg_cmd * scmd; 34 | 35 | if(argc < 2) 36 | { 37 | fputs("Please specify the path to the scsi device or use cdrecord syntax (X,Y,Z).\n",stderr); 38 | return -1; 39 | } 40 | 41 | memset(dev, 0, MAX_DEVICE_LEN); 42 | strcpy(dev, argv[1]); 43 | 44 | // open scsi driver 45 | scgp = scg_open(dev, errstr, sizeof(errstr), 0, NULL); 46 | if(!scgp) 47 | { 48 | fputs("Cannot open scsi driver.\n", stderr); 49 | return -2; 50 | } 51 | 52 | if(scgp->addr.scsibus == -2 && scgp->addr.target == -2) // scsi device not found, search by devicename; 53 | { // this is nessessary on Windows when drive letters 54 | // are used 55 | ret = scg__open(scgp, dev); 56 | if(!ret) 57 | { 58 | fprintf(stderr, "Cannot open SCSI device for %d.\n", dev); 59 | err = -3; 60 | goto clean; 61 | } 62 | } 63 | 64 | scg_settimeout(scgp, SCSI_TIMEOUT); 65 | scgp->cmdname = cmdname; 66 | 67 | // prepare SCSI command 68 | scmd = scgp->scmd; 69 | memset(scmd, 0, sizeof(struct scg_cmd)); 70 | scmd->addr = (caddr_t)0; 71 | scmd->size = 0; 72 | scmd->cdb_len = sizeof(command); 73 | scmd->sense_len = CCS_SENSE_LEN; 74 | scmd->flags = SCG_DISRE_ENA; 75 | 76 | memset(command, 0, 12); 77 | command[0] = SONY_SPECIFIC_COMMAND; 78 | command[3] = HIMD_ERASE; /* set HIMD_ERASE or HIMD_FORMAT here */ 79 | command[4] = 0x03; /* control flags */ 80 | memcpy(scmd->cdb.cmd_cdb, command, 12); 81 | 82 | // send SCSI command 83 | if(scg_cmd(scgp) < 0) 84 | { 85 | fputs("Cannot send scsi command.\n", stderr); 86 | err = -4; 87 | goto clean; 88 | } 89 | else 90 | fprintf(stderr, "SCSI command sent successfully.\n"); 91 | 92 | clean: 93 | scg__close(scgp); 94 | 95 | return err; 96 | } 97 | -------------------------------------------------------------------------------- /basictools/mp3dec.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define ALL_FRAMES 16384 6 | int decodemp3(const unsigned char * key, const char * block, int skipframes, int maxframes, 7 | char * decoded, int * len) 8 | { 9 | struct mad_stream stream; 10 | struct mad_header header; 11 | int framecount = block[4]*256+block[5]; 12 | char xorred_frame[16304+MAD_BUFFER_GUARD]; 13 | int i; 14 | int result = 0; 15 | 16 | for(i = 0;i < 16304;i++) 17 | xorred_frame[i] = block[i+32] ^ key[i&3]; 18 | memset(xorred_frame+16304,0,MAD_BUFFER_GUARD); 19 | 20 | mad_stream_init(&stream); 21 | mad_header_init(&header); 22 | 23 | mad_stream_buffer(&stream, xorred_frame, 16304+MAD_BUFFER_GUARD); 24 | 25 | if(framecount > maxframes) 26 | framecount = maxframes; 27 | 28 | *len = 0; 29 | for(i = 0; i < framecount; i++) 30 | { 31 | if(mad_header_decode(&header, &stream) < 0 32 | && (stream.error != MAD_ERROR_LOSTSYNC || 33 | i != framecount-1)) 34 | { 35 | printf("%d\n",stream.error); 36 | result = -1; 37 | break; 38 | } 39 | if(skipframes) 40 | skipframes--; 41 | else 42 | { 43 | memcpy(decoded + *len,stream.this_frame,stream.next_frame - stream.this_frame); 44 | *len += stream.next_frame - stream.this_frame; 45 | result++; 46 | } 47 | } 48 | 49 | mad_header_finish(&header); 50 | mad_stream_finish(&stream); 51 | return result; 52 | } 53 | 54 | int main(void) 55 | { 56 | FILE * f = fopen("/media/disk/HMDHIFI/ATDATA02.HMA","rb"); 57 | const unsigned char key[] = {0x00,0x69,0xF7,0x7A}; 58 | // 00641418 59 | int firstblock = 0x60; 60 | int firstframe = 0x0; 61 | int lastblock = 0x12d; 62 | int lastframe = 0x1e; 63 | int b; 64 | int len; 65 | char block[16384]; 66 | char decoded[16384]; 67 | 68 | fseek(f,firstblock*16384L,SEEK_SET); 69 | for(b = firstblock;b <= lastblock;++b) 70 | { 71 | fread(block,1,16384,f); 72 | if(decodemp3(key,block,(b == firstblock) ? firstframe : 0, 73 | (b == lastblock) ? lastframe : ALL_FRAMES, 74 | decoded, &len) < 0) 75 | { 76 | fprintf(stderr,"decoder failed at block %d\n",b); 77 | return 1; 78 | } 79 | fwrite(decoded,1,len,stdout); 80 | } 81 | return 0; 82 | } 83 | -------------------------------------------------------------------------------- /basictools/mp3key.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | /* Test vector: 1 CAEF24F1 -> A350796F */ 4 | 5 | int main(int argc, char ** argv) 6 | { 7 | unsigned int trknum = 1; 8 | unsigned int discid; 9 | char dummy; 10 | 11 | if(argc != 3) 12 | { 13 | fprintf(stderr, "Please invoke as 'mp3key '\n" 14 | "where tracknum is a decimal track number and discid is the last 8\n" 15 | "digits (4 bytes) of the hex disc id\n"); 16 | return 1; 17 | } 18 | 19 | if(sscanf(argv[1],"%d%c",&trknum,&dummy) != 1) 20 | { 21 | fprintf(stderr, "Track number is not a decimal integer\n"); 22 | return 1; 23 | } 24 | if(sscanf(argv[2],"%x%c",&discid,&dummy) != 1) 25 | { 26 | fprintf(stderr, "Disk ID is not an 8 digit hex string\n"); 27 | return 1; 28 | } 29 | 30 | unsigned int foo = ((trknum*0x6953B2ED)+0x6BAAB1) ^ discid; 31 | 32 | printf("%08X\n", foo & 0xFFFFFFFF); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /build/common.pri: -------------------------------------------------------------------------------- 1 | # http://stackoverflow.com/a/17578151/1047040 2 | QMAKE_CXXFLAGS += $$(CXXFLAGS) 3 | QMAKE_CFLAGS += $$(CFLAGS) 4 | QMAKE_LFLAGS += $$(LDFLAGS) 5 | 6 | macx { 7 | # Dependencies from Homebrew are put here 8 | INCLUDEPATH += /usr/local/include 9 | INCLUDEPATH += /opt/homebrew/include 10 | LIBS += -L/usr/local/lib 11 | LIBS += -L/opt/homebrew/lib 12 | } 13 | -------------------------------------------------------------------------------- /build/cross_wrapper_mingw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | set -x 5 | 6 | if [ "$BUILD_TYPE" = "linux-cross-mingw32" ]; then 7 | BUILD_TYPE_HOST="i686-w64-mingw32" 8 | BUILD_TYPE_PREFIX="/opt/mingw32/" 9 | else 10 | BUILD_TYPE_HOST="x86_64-w64-mingw32" 11 | BUILD_TYPE_PREFIX="/opt/mingw64/" 12 | fi 13 | 14 | if [ ! -z "$BUILD_TYPE_PREFIX" ]; then 15 | export PATH="$BUILD_TYPE_PREFIX/bin:$PATH" 16 | export PKG_CONFIG_PATH=$BUILD_TYPE_PREFIX/lib/pkgconfig/ 17 | export LDFLAGS="$LDFLAGS -L$BUILD_TYPE_PREFIX/lib/" 18 | BUILD_TYPE_CFLAGS="-DG_OS_WIN32 -I$BUILD_TYPE_PREFIX/include/" 19 | BUILD_TYPE_CFLAGS="$BUILD_TYPE_CFLAGS -I$BUILD_TYPE_PREFIX/include/libusb-1.0/" 20 | BUILD_TYPE_CFLAGS="$BUILD_TYPE_CFLAGS -I$BUILD_TYPE_PREFIX/include/taglib/" 21 | export CFLAGS="$CFLAGS $BUILD_TYPE_CFLAGS" 22 | export CXXFLAGS="$CXXFLAGS $BUILD_TYPE_CFLAGS" 23 | fi 24 | 25 | "$@" 26 | -------------------------------------------------------------------------------- /build/get_version.sh: -------------------------------------------------------------------------------- 1 | #/bin/sh 2 | # get_version.sh - simple script to determine version number 3 | 4 | GIT_VERSION="$(git describe --always --long 2>/dev/null)" 5 | SRCDIR="$( cd "$( dirname "$0" )" && pwd )" 6 | 7 | if [ -n "$GIT_VERSION" ] ; then 8 | echo $GIT_VERSION 9 | elif [ -f "${SRCDIR}"/../VERSION ] ; then 10 | cat "${SRCDIR}"/../VERSION 11 | else 12 | echo "NO_VERSION" 13 | fi 14 | -------------------------------------------------------------------------------- /build/install_dependencies.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | set -x 5 | 6 | unset CC 7 | export CC 8 | unset CXX 9 | export CXX 10 | 11 | case "$BUILD_TYPE" in 12 | linux-cross-mingw*) 13 | if [ "$BUILD_TYPE" = "linux-cross-mingw32" ]; then 14 | BUILD_TYPE_HOST="i686-w64-mingw32" 15 | BUILD_TYPE_PREFIX="/opt/mingw32/" 16 | else 17 | BUILD_TYPE_HOST="x86_64-w64-mingw32" 18 | BUILD_TYPE_PREFIX="/opt/mingw64/" 19 | fi 20 | sudo add-apt-repository --yes ppa:tobydox/mingw-x-trusty 21 | sudo apt-get update -q || true 22 | sudo apt-get install -q -f -y mingw-w64 mingw-w64-tools \ 23 | mingw64-x-qt mingw64-x-glib2 mingw64-x-zlib mingw64-x-libusb \ 24 | mingw32-x-qt mingw32-x-glib2 mingw32-x-zlib mingw32-x-libusb 25 | 26 | for tool in uic moc rcc; do 27 | sudo ln -sf $tool /opt/mingw32/bin/i686-w64-mingw32-$tool 28 | sudo ln -sf $tool /opt/mingw64/bin/x86_64-w64-mingw32-$tool 29 | done 30 | 31 | export PKG_CONFIG_PATH="$BUILD_TYPE_PREFIX/lib/pkgconfig/" 32 | export CFLAGS="$PFLAGS -I$BUILD_TYPE_PREFIX/include/" 33 | export CPPFLAGS="$CPPFLAGS -I$BUILD_TYPE_PREFIX/include/" 34 | export CXXFLAGS="$CXXFLAGS -I$BUILD_TYPE_PREFIX/include/" 35 | export LDFLAGS="$LDFLAGS -L$BUILD_TYPE_PREFIX/lib/" 36 | export PATH="$BUILD_TYPE_PREFIX/bin:$PATH" 37 | 38 | ( 39 | mkdir -p deps && cd deps 40 | wget -N https://sourceforge.net/projects/mad/files/libmad/0.15.1b/libmad-0.15.1b.tar.gz 41 | ( 42 | tar xvf libmad-0.15.1b.tar.gz && cd libmad-0.15.1b 43 | patch -p0 < ../../build/libmad_optimize-flags.patch 44 | ./configure --host=$BUILD_TYPE_HOST --prefix=$BUILD_TYPE_PREFIX 45 | make && sudo make install 46 | ) 47 | 48 | wget -N https://sourceforge.net/projects/mad/files/libid3tag/0.15.1b/libid3tag-0.15.1b.tar.gz 49 | ( 50 | tar xvf libid3tag-0.15.1b.tar.gz && cd libid3tag-0.15.1b 51 | ./configure --host=$BUILD_TYPE_HOST --prefix=$BUILD_TYPE_PREFIX 52 | make && sudo make install 53 | ) 54 | 55 | wget -N https://gnupg.org/ftp/gcrypt/libgpg-error/libgpg-error-1.24.tar.bz2 56 | ( 57 | tar xvf libgpg-error-1.24.tar.bz2 && cd libgpg-error-1.24 58 | ./configure --host=$BUILD_TYPE_HOST --prefix=$BUILD_TYPE_PREFIX 59 | make && sudo make install 60 | ) 61 | 62 | wget -N https://gnupg.org/ftp/gcrypt/libgcrypt/libgcrypt-1.7.3.tar.bz2 63 | ( 64 | tar xvf libgcrypt-1.7.3.tar.bz2 && cd libgcrypt-1.7.3 65 | ./configure --host=$BUILD_TYPE_HOST --prefix=$BUILD_TYPE_PREFIX 66 | make && sudo make install 67 | ) 68 | 69 | wget -N https://taglib.github.io/releases/taglib-1.11.tar.gz 70 | ( 71 | tar xvf taglib-1.11.tar.gz && cd taglib-1.11 72 | mkdir build && cd build 73 | cmake \ 74 | -DCMAKE_TOOLCHAIN_FILE=$(pwd)/../../../build/toolchain-$BUILD_TYPE_HOST.cmake \ 75 | -DCMAKE_INSTALL_PREFIX=$BUILD_TYPE_PREFIX \ 76 | -DBUILD_SHARED_LIBS=ON \ 77 | -DBUILD_BINDINGS=OFF \ 78 | .. 79 | make && sudo make install 80 | ) 81 | ) 82 | ;; 83 | linux-native-*) 84 | sudo apt-get update -q 85 | sudo apt-get install -q -y libqt4-dev libglib2.0-dev libmad0-dev libgcrypt11-dev libusb-1.0-0-dev libid3tag0-dev libtag1-dev 86 | ;; 87 | osx-native-*) 88 | brew update 89 | brew install --force pkg-config qt5 mad libid3tag libtag glib libusb libusb-compat libgcrypt 90 | brew link --force qt5 91 | ;; 92 | *) 93 | echo "Unset/unknown \$BUILD_TYPE: $BUILD_TYPE" 94 | exit 1 95 | ;; 96 | esac 97 | -------------------------------------------------------------------------------- /build/installunix.pri: -------------------------------------------------------------------------------- 1 | unix:!macx { 2 | target.path = /usr/bin 3 | INSTALLS += target 4 | } 5 | -------------------------------------------------------------------------------- /build/libgcrypt.pri: -------------------------------------------------------------------------------- 1 | !without_gcrypt { 2 | LIBS += -lgcrypt 3 | DEFINES += CONFIG_WITH_GCRYPT 4 | } 5 | else: !build_pass: message(You disabled gcrypt: No PCM and ATRAC transfer will be supported) 6 | 7 | -------------------------------------------------------------------------------- /build/libglib.pri: -------------------------------------------------------------------------------- 1 | DEFINES += G_DISABLE_DEPRECATED=1 2 | PKGCONFIG += glib-2.0 3 | -------------------------------------------------------------------------------- /build/libid3tag.pri: -------------------------------------------------------------------------------- 1 | unix { 2 | PKGCONFIG += id3tag 3 | } else { 4 | LIBS += -lid3tag 5 | } 6 | -------------------------------------------------------------------------------- /build/libmad.pri: -------------------------------------------------------------------------------- 1 | !without_mad { 2 | DEFINES += CONFIG_WITH_MAD 3 | unix { 4 | PKGCONFIG += mad 5 | } else { 6 | LIBS += -lmad 7 | } 8 | } else:!build_pass { 9 | message(You disabled mad: MP3 transfer will be limited) 10 | } 11 | -------------------------------------------------------------------------------- /build/libmad_optimize-flags.patch: -------------------------------------------------------------------------------- 1 | --- configure 2004-02-05 10:34:07.000000000 +0100 2 | +++ configure.fix 2016-09-09 14:55:43.000000000 +0200 3 | @@ -19096,58 +19096,7 @@ 4 | esac 5 | fi 6 | 7 | - case "$optimize" in 8 | - -O|"-O "*) 9 | - optimize="-O" 10 | - optimize="$optimize -fforce-mem" 11 | - optimize="$optimize -fforce-addr" 12 | - : #x optimize="$optimize -finline-functions" 13 | - : #- optimize="$optimize -fstrength-reduce" 14 | - optimize="$optimize -fthread-jumps" 15 | - optimize="$optimize -fcse-follow-jumps" 16 | - optimize="$optimize -fcse-skip-blocks" 17 | - : #x optimize="$optimize -frerun-cse-after-loop" 18 | - : #x optimize="$optimize -frerun-loop-opt" 19 | - : #x optimize="$optimize -fgcse" 20 | - optimize="$optimize -fexpensive-optimizations" 21 | - optimize="$optimize -fregmove" 22 | - : #* optimize="$optimize -fdelayed-branch" 23 | - : #x optimize="$optimize -fschedule-insns" 24 | - optimize="$optimize -fschedule-insns2" 25 | - : #? optimize="$optimize -ffunction-sections" 26 | - : #? optimize="$optimize -fcaller-saves" 27 | - : #> optimize="$optimize -funroll-loops" 28 | - : #> optimize="$optimize -funroll-all-loops" 29 | - : #x optimize="$optimize -fmove-all-movables" 30 | - : #x optimize="$optimize -freduce-all-givs" 31 | - : #? optimize="$optimize -fstrict-aliasing" 32 | - : #* optimize="$optimize -fstructure-noalias" 33 | - 34 | - case "$host" in 35 | - arm*-*) 36 | - optimize="$optimize -fstrength-reduce" 37 | - ;; 38 | - mips*-*) 39 | - optimize="$optimize -fstrength-reduce" 40 | - optimize="$optimize -finline-functions" 41 | - ;; 42 | - i?86-*) 43 | - optimize="$optimize -fstrength-reduce" 44 | - ;; 45 | - powerpc-apple-*) 46 | - # this triggers an internal compiler error with gcc2 47 | - : #optimize="$optimize -fstrength-reduce" 48 | - 49 | - # this is really only beneficial with gcc3 50 | - : #optimize="$optimize -finline-functions" 51 | - ;; 52 | - *) 53 | - # this sometimes provokes bugs in gcc 2.95.2 54 | - : #optimize="$optimize -fstrength-reduce" 55 | - ;; 56 | - esac 57 | - ;; 58 | - esac 59 | + optimize="-O2" 60 | fi 61 | 62 | case "$host" in 63 | -------------------------------------------------------------------------------- /build/libtaglib.pri: -------------------------------------------------------------------------------- 1 | unix { 2 | PKGCONFIG += taglib 3 | } else { 4 | LIBS += -ltag 5 | } 6 | -------------------------------------------------------------------------------- /build/libusb.pri: -------------------------------------------------------------------------------- 1 | unix { 2 | PKGCONFIG += libusb-1.0 3 | } else { 4 | LIBS += -lusb-1.0 5 | } 6 | -------------------------------------------------------------------------------- /build/libz.pri: -------------------------------------------------------------------------------- 1 | unix:!mac { 2 | PKGCONFIG += zlib 3 | } else { 4 | LIBS += -lz 5 | } 6 | -------------------------------------------------------------------------------- /build/mingw-bundledlls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | # The MIT License (MIT) 4 | # 5 | # Copyright (c) 2015 Martin Preisler 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | 26 | import subprocess 27 | import os.path 28 | import argparse 29 | import shutil 30 | 31 | # The mingw path matches where Fedora 21 installs mingw32; this is the default 32 | # fallback if no other search path is specified in $MINGW_BUNDLEDLLS_SEARCH_PATH 33 | DEFAULT_PATH_PREFIXES = [ 34 | "", "/usr/bin", "/usr/i686-w64-mingw32/sys-root/mingw/bin", "/mingw64/bin", 35 | ] 36 | 37 | env_path_prefixes = os.environ.get('MINGW_BUNDLEDLLS_SEARCH_PATH', None) 38 | if env_path_prefixes is not None: 39 | path_prefixes = [path for path in env_path_prefixes.split(os.pathsep) if path] 40 | else: 41 | path_prefixes = DEFAULT_PATH_PREFIXES 42 | 43 | # This blacklist may need extending 44 | blacklist = [ 45 | "advapi32.dll", "kernel32.dll", "msvcrt.dll", "ole32.dll", "user32.dll", 46 | "ws2_32.dll", "comdlg32.dll", "gdi32.dll", "imm32.dll", "oleaut32.dll", 47 | "shell32.dll", "winmm.dll", "winspool.drv", "wldap32.dll", 48 | "ntdll.dll", "d3d9.dll", "mpr.dll", "crypt32.dll", "dnsapi.dll", 49 | "shlwapi.dll", "version.dll", "iphlpapi.dll", "msimg32.dll", "setupapi.dll", 50 | ] 51 | 52 | 53 | def find_full_path(filename, path_prefixes): 54 | path = None 55 | 56 | for path_prefix in path_prefixes: 57 | path_candidate = os.path.join(path_prefix, filename) 58 | 59 | if os.path.exists(path_candidate): 60 | path = path_candidate 61 | break 62 | 63 | if path is None: 64 | raise RuntimeError( 65 | "Can't find " + filename + ". If it is an inbuilt Windows DLL, " 66 | "please add it to the blacklist variable in the script and send " 67 | "a pull request!" 68 | ) 69 | 70 | return path 71 | 72 | 73 | def gather_deps(path, path_prefixes, seen): 74 | ret = [path] 75 | output = subprocess.check_output(["objdump", "-p", path]).decode( 76 | "utf-8", "replace").split("\n") 77 | for line in output: 78 | if not line.startswith("\tDLL Name: "): 79 | continue 80 | 81 | dep = line.split("DLL Name: ")[1].strip() 82 | ldep = dep.lower() 83 | 84 | if ldep in blacklist: 85 | continue 86 | 87 | if ldep in seen: 88 | continue 89 | 90 | dep_path = find_full_path(dep, path_prefixes) 91 | seen.extend([ldep]) 92 | subdeps = gather_deps(dep_path, path_prefixes, seen) 93 | ret.extend(subdeps) 94 | 95 | return ret 96 | 97 | 98 | def main(): 99 | parser = argparse.ArgumentParser() 100 | parser.add_argument( 101 | "exe_file", 102 | help="EXE or DLL file that you need to bundle dependencies for" 103 | ) 104 | parser.add_argument( 105 | "--copy", 106 | action="store_true", 107 | help="In addition to printing out the dependencies, also copy them next to the exe_file" 108 | ) 109 | parser.add_argument( 110 | "--upx", 111 | action="store_true", 112 | help="Only valid if --copy is provided. Run UPX on all the DLLs and EXE." 113 | ) 114 | args = parser.parse_args() 115 | 116 | if args.upx and not args.copy: 117 | raise RuntimeError("Can't run UPX if --copy hasn't been provided.") 118 | 119 | all_deps = set(gather_deps(args.exe_file, path_prefixes, [])) 120 | all_deps.remove(args.exe_file) 121 | 122 | print("\n".join(all_deps)) 123 | 124 | if args.copy: 125 | print("Copying enabled, will now copy all dependencies next to the exe_file.\n") 126 | 127 | parent_dir = os.path.dirname(os.path.abspath(args.exe_file)) 128 | 129 | for dep in all_deps: 130 | target = os.path.join(parent_dir, os.path.basename(dep)) 131 | 132 | try: 133 | print("Copying '%s' to '%s'" % (dep, target)) 134 | shutil.copy(dep, parent_dir) 135 | 136 | except shutil.SameFileError: 137 | print("Dependency '%s' was already in target directory, " 138 | "skipping..." % (dep)) 139 | 140 | if args.upx: 141 | subprocess.call(["upx", target]) 142 | 143 | 144 | if __name__ == "__main__": 145 | main() 146 | -------------------------------------------------------------------------------- /build/package_build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Build binary packages for upload to Github Releases 3 | # 2016-12-17 Thomas Perl 4 | 5 | set -e 6 | set -x 7 | 8 | HERE="$(pwd)" 9 | PACKAGE="qhimdtransfer" 10 | VERSION="$(sh build/get_version.sh)" 11 | 12 | case "$BUILD_TYPE" in 13 | linux-cross-mingw32) 14 | PLATFORM="win32" 15 | ARCHIVE="zip" 16 | MINGW_BUNDLEDLLS_SEARCH_PATH=/opt/mingw32/bin:/usr/lib/gcc/i686-w64-mingw32/4.8:/usr/i686-w64-mingw32/lib 17 | ;; 18 | linux-cross-mingw64) 19 | PLATFORM="win64" 20 | ARCHIVE="zip" 21 | MINGW_BUNDLEDLLS_SEARCH_PATH=/opt/mingw64/bin:/usr/lib/gcc/x86_64-w64-mingw32/4.8:/usr/x86_64-w64-mingw32/lib 22 | ;; 23 | linux-native-clang) 24 | PLATFORM="linux-clang" 25 | ARCHIVE="tar" 26 | ;; 27 | linux-native-gcc) 28 | PLATFORM="linux-gcc" 29 | ARCHIVE="tar" 30 | ;; 31 | osx-native-clang) 32 | PLATFORM="macos" 33 | ARCHIVE="zip" 34 | ;; 35 | *) 36 | echo "Unset/unknown \$BUILD_TYPE: $BUILD_TYPE" 37 | exit 1 38 | ;; 39 | esac 40 | 41 | DISTNAME="${PACKAGE}-${VERSION}-${PLATFORM}" 42 | 43 | TMP_OUT="dist-tmp/${DISTNAME}" 44 | 45 | rm -rf dist-tmp 46 | mkdir -p "$TMP_OUT" 47 | 48 | # Copy documentation and platform independent stuff 49 | cp -rpv COPYING COPYING.LIB README docs "$TMP_OUT" 50 | 51 | case "$BUILD_TYPE" in 52 | linux-cross-mingw*) 53 | export MINGW_BUNDLEDLLS_SEARCH_PATH 54 | 55 | for filename in himdcli/release/himdcli.exe netmdcli/release/netmdcli.exe qhimdtransfer/release/QHiMDTransfer.exe; do 56 | basename="$(basename "$filename")" 57 | target="$TMP_OUT/$basename" 58 | cp "$filename" "$target" 59 | python3 build/mingw-bundledlls --copy "$target" 60 | done 61 | ;; 62 | linux-native-*) 63 | mkdir -p "$TMP_OUT/bin" 64 | cp -rpv himdcli/himdcli netmdcli/netmdcli qhimdtransfer/qhimdtransfer "$TMP_OUT/bin" 65 | ;; 66 | osx-native-clang) 67 | cp -rpv qhimdtransfer/QHiMDTransfer.app "$TMP_OUT" 68 | macdeployqt "$TMP_OUT/QHiMDTransfer.app" 69 | mkdir -p "$TMP_OUT/bin" 70 | cp -rpv himdcli/himdcli netmdcli/netmdcli "$TMP_OUT/bin" 71 | ;; 72 | *) 73 | echo "Unset/unknown \$BUILD_TYPE: $BUILD_TYPE" 74 | exit 1 75 | ;; 76 | esac 77 | 78 | rm -rf dist 79 | mkdir -p dist 80 | 81 | case "$ARCHIVE" in 82 | zip) 83 | (cd dist-tmp && zip -r "${HERE}/dist/${DISTNAME}.zip" *) 84 | ;; 85 | tar) 86 | (cd dist-tmp && tar -czvf "${HERE}/dist/${DISTNAME}.tar.gz" *) 87 | ;; 88 | *) 89 | echo "Unknown archive type: '$ARCHIVE'" 90 | exit 1 91 | ;; 92 | esac 93 | 94 | rm -rf dist-tmp 95 | -------------------------------------------------------------------------------- /build/toolchain-i686-w64-mingw32.cmake: -------------------------------------------------------------------------------- 1 | SET(CMAKE_SYSTEM_NAME Windows) 2 | 3 | set(COMPILER_PREFIX "i686-w64-mingw32") 4 | 5 | find_program(CMAKE_RC_COMPILER NAMES ${COMPILER_PREFIX}-windres) 6 | find_program(CMAKE_C_COMPILER NAMES ${COMPILER_PREFIX}-gcc) 7 | find_program(CMAKE_CXX_COMPILER NAMES ${COMPILER_PREFIX}-g++) 8 | 9 | SET(CMAKE_FIND_ROOT_PATH /usr/${COMPILER_PREFIX}) 10 | 11 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 12 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 13 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 14 | -------------------------------------------------------------------------------- /build/toolchain-x86_64-w64-mingw32.cmake: -------------------------------------------------------------------------------- 1 | SET(CMAKE_SYSTEM_NAME Windows) 2 | 3 | set(COMPILER_PREFIX "x86_64-w64-mingw32") 4 | 5 | find_program(CMAKE_RC_COMPILER NAMES ${COMPILER_PREFIX}-windres) 6 | find_program(CMAKE_C_COMPILER NAMES ${COMPILER_PREFIX}-gcc) 7 | find_program(CMAKE_CXX_COMPILER NAMES ${COMPILER_PREFIX}-g++) 8 | 9 | SET(CMAKE_FIND_ROOT_PATH /usr/${COMPILER_PREFIX}) 10 | 11 | set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) 12 | set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) 13 | set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) 14 | -------------------------------------------------------------------------------- /docs/himdcli.1: -------------------------------------------------------------------------------- 1 | \" Hey, EMACS: -*- nroff -*- 2 | .TH HIMDCLI 1 "November 23, 2012" 3 | .SH NAME 4 | himdcli \- Command line interface for accessing HiMD Walkman 5 | .SH SYNOPSIS 6 | .B himdcli "\" "\" 7 | .SH DESCRIPTION 8 | \fBhimdcli\fP is a command line interface for accessing HiMD Walkman. It 9 | uses the libhimd library to read and write audio tracks from a HiMD filesystem 10 | which can be mounted directly from a physical HiMD Walkman or a previously 11 | created image file of a HiMD. The mount point of the HiMD filesystem must 12 | be provided as an argument to \fBhimdcli\fP together with the command to 13 | be performed. 14 | 15 | Currently libhimd and therefore \fBhimdcli\fP implements full read access 16 | for PCM, ATRAC-3+ and MP3 tracks as well as experimental write support 17 | for MP3 tracks (MP3 playback is supported by second and third generation 18 | of HiMD Walkman only). Non-MP3 tracks are protected by Sony's DRM 19 | software stack OpenMG, which require a sophisticated calculation of 20 | keys and access control lists. Writing of non-MP3 tracks is therefore 21 | currently not yet supported. 22 | 23 | In addition to transfer capabilities, \fBhimdcli\fP provides some commands 24 | for debugging purposes. These include \fBstrings\fP to display all strings 25 | found in the track list file (TRKIDX##.HMA), \fBtracks\fP and \fBtracks 26 | verbose\fP to display (detailed technical) track information, \fBdiscid\fP 27 | to display the disc id (comparable to the filesystem ID of FAT formatted 28 | volumes) which is used by the OpenMG encryption, \fBmp3key\fP to display 29 | the MP3 encryption key for a given MP3 track on disc as well as \fBholes\fP 30 | to display the holes in a non-contiguous ATDATA##.HMA file (a container 31 | file where all tracks are stored on a HiMD filesystem). 32 | 33 | .SH COMMANDS 34 | himdcli currently accepts the following commands: 35 | .TP 36 | .B help 37 | Show command overview list. 38 | .B strings 39 | Dumps all strings found in the tracklist file. 40 | .TP 41 | .B tracks 42 | Lists all tracks on disc. 43 | .TP 44 | .B tracks verbose 45 | Lists details of all tracks on disc. 46 | .TP 47 | .B discid 48 | Reads the disc id of the inserted medium. 49 | .TP 50 | .B holes 51 | Lists all holes on disc. 52 | .TP 53 | .B mp3key 54 | Shows the MP3 encryption key for track #. 55 | .TP 56 | .B dumptrack 57 | Dumps track #. 58 | .TP 59 | .B dumpmp3 60 | Dumps MP3 track #. 61 | .TP 62 | .B dumpnonmp3 63 | Dumps non-MP3 track #. 64 | .TP 65 | .B writemp3 66 | Writes the MP3 file to disc. 67 | .PP 68 | When invoked without any arguments, himdcli outputs a short message with usage information. 69 | .SH SEE ALSO 70 | .IR netmdcli (1), 71 | .IR qhimdtransfer (1) 72 | .br 73 | .SH AUTHOR 74 | The linux-minidisc project - . 75 | .PP 76 | This manual page was written by John Paul Adrian Glaubitz . 77 | -------------------------------------------------------------------------------- /docs/internals/AVC Descriptor Mechanism 1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/docs/internals/AVC Descriptor Mechanism 1.0.pdf -------------------------------------------------------------------------------- /docs/internals/AVC Digital Interface Commands 3.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/docs/internals/AVC Digital Interface Commands 3.0.pdf -------------------------------------------------------------------------------- /docs/internals/AVC Disc Subunit 1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/docs/internals/AVC Disc Subunit 1.0.pdf -------------------------------------------------------------------------------- /docs/internals/AVC MD Audio 1.0.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/docs/internals/AVC MD Audio 1.0.pdf -------------------------------------------------------------------------------- /docs/internals/README.md: -------------------------------------------------------------------------------- 1 | Minidisc internals documentation 2 | -------------------------------- 3 | 4 | This directory contains documents related to MD player protocol 5 | internals. 6 | 7 | **The documents in this directory may have a different license 8 | than other files in this repository.** 9 | 10 | ## AV/C standards (NetMD) 11 | 12 | The AV/C standards documents specify the protocol used to 13 | control NetMD devices, with the exception of some vendor-specific 14 | commands used to transfer audio tracks. 15 | 16 | A sample USB command packet with references to the documents in this 17 | directory to get started with investigating the protocol: 18 | 19 | ``` 20 | Track title write (excludes descriptor open/close commands): 21 | 22 | 0020 xx xx xx xx 00 18 07 02 20 18 02 00 00 30 00 0a 23 | CT SU OP Dc Ds D1 D2 D3 D4 Is It 24 | 0030 00 50 00 00 0a 00 00 00 00 6d 61 74 73 2d 31 30 25 | Ii SF L1 L2 track-name---------- 26 | 0040 73 65 63 27 | -------- 28 | 29 | xx = USB framing bytes, not relevant 30 | 31 | CT = command type (ctype): usually 0 for commands from the host (Digital Interface Commands 5.1) 32 | (this field will be the response code in messages from the devices, usually 9 for success) 33 | SU = "subunit" aka target device for this command, generally 0x18 for MD (Digital Interface Commands 5.3.3) 34 | OP = top-level opcode: WRITE INFO BLOCK (Descriptor Mechanism 9.9) 35 | 36 | The following fields describe the target of the operation viz. the 37 | text "infoblock" beloging to the "text database" (id 18 02) entry for 38 | the first track (track 0): 39 | 40 | Dc = descriptor level count (Descriptor Mechanism 8.3.1) 41 | Ds = descriptor type specifier, 0x20 = index in list (Descriptor Mechanism 8.1, 8.2.4) 42 | D1-2 (18 02) = target list id: track title descriptor list (MD Audio 8.3.1) 43 | D3-4 = index in target list (in this case the track number) 44 | Is = descriptor type specifier 2, 0x30 = info block (Descriptor Mechanism 8.4) 45 | It = info block type (two bytes): "raw text info" (MD Audio B.4 example) 46 | Ii = info block instance count 47 | 48 | Finally the details of the write operation: 49 | 50 | SF = WRITE INFO BLOCK "partial replace" subfunction (Descriptor Mechanism 9.9) 51 | L1-2 = new value length (0xa = 10 bytes) 52 | 53 | "Track name" contains the actual track name with the length as specified by 54 | L1-2 (0x000a = 10 bytes in this case). 55 | ```` 56 | -------------------------------------------------------------------------------- /docs/netmdcli.1: -------------------------------------------------------------------------------- 1 | \" Hey, EMACS: -*- nroff -*- 2 | .TH NETMDCLI 1 "November 23, 2012" 3 | .SH NAME 4 | netmdcli \- Command line interface for accessing NetMD Walkman 5 | .SH SYNOPSIS 6 | .B netmdcli [options] 7 | .SH DESCRIPTION 8 | \fBnetmdcli\fP is a command line interface for accessing NetMD Walkman. 9 | .SH OPTIONS 10 | netmdcli accepts the following options (GNU style): 11 | .TP 12 | .B \-t 13 | Increase log level to NETMD_LOG_ALL. 14 | .SH COMMANDS 15 | netmdcli accepts the following commands: 16 | .TP 17 | .B send 18 | Send track to a NetMD device. 19 | .TP 20 | .B recv 21 | Receive tracks from a NetMD device. 22 | .TP 23 | .B rename 24 | Rename tracks on a NetMD device. 25 | .TP 26 | .B move 27 | Move tracks on a NetMD device. 28 | .TP 29 | .B groupmove 30 | Move track groups on a NetMD device. 31 | .PP 32 | When invoked without any arguments, netmdcli outputs a short usage information. 33 | .SH SEE ALSO 34 | .IR himdcli (1), 35 | .IR qhimdtransfer (1) 36 | .br 37 | .SH AUTHOR 38 | The linux-minidisc project - . 39 | .PP 40 | This manual page was written by John Paul Adrian Glaubitz . 41 | -------------------------------------------------------------------------------- /docs/qhimdtransfer.1: -------------------------------------------------------------------------------- 1 | \" Hey, EMACS: -*- nroff -*- 2 | .TH QHIMDTRANSFER 1 "November 23, 2012" 3 | .SH NAME 4 | qhimdtransfer \- Transfer software for MiniDisc devices 5 | .SH SYNOPSIS 6 | .B qhimdtransfer 7 | .SH DESCRIPTION 8 | \fBqhimdtransfer\fP is a graphical user interface application for 9 | accessing HiMD Walkman. It uses the libhimd library to read and write 10 | audio tracks from a HiMD filesystem which can be mounted directly from 11 | a physical HiMD Walkman or a previously created image file of a HiMD. 12 | By choosing "Connect" in the file menu, the mount point of the HiMD 13 | filesystem is located and the track listing is consequently loaded 14 | into the application into the track list viewer on the left-hand 15 | side. 16 | 17 | To upload a track (transfer it to the PC), select the tracks to be 18 | transferred in the track list window. Then choose the destination 19 | directory in the file browser on the right-hand side and click 20 | the onto the upload button (white arrow on red background). To 21 | download tracks to the device, select the tracks to be downloaded 22 | in the file browser and click onto the download button (white 23 | arrow on green background). 24 | 25 | Currently libhimd and therefore \fBqhimdtransfer\fP implements full read access 26 | for PCM, ATRAC-3+ and MP3 tracks as well as experimental write support 27 | for MP3 tracks (MP3 playback is supported by second and third generation 28 | of HiMD Walkman only). Non-MP3 tracks are protected by Sony's DRM 29 | software stack OpenMG, which require a sophisticated calculation of 30 | keys and access control lists. Writing of non-MP3 tracks is therefore 31 | currently not yet supported. 32 | 33 | Please note that some of the functions in the graphical user interface 34 | like deleting or renaming tracks or formatting the medium are not yet 35 | implemented, but work is currently in progress to achieve that. 36 | 37 | .SH SEE ALSO 38 | .IR netmdcli (1), 39 | .IR himdcli (1) 40 | .br 41 | .SH AUTHOR 42 | The linux-minidisc project - . 43 | .PP 44 | This manual page was written by John Paul Adrian Glaubitz . 45 | -------------------------------------------------------------------------------- /himdcli/.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.Release 3 | Makefile.Debug 4 | himdcli 5 | debug 6 | release -------------------------------------------------------------------------------- /himdcli/himdcli.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | 3 | CONFIG -= qt app_bundle 4 | CONFIG += console link_pkgconfig link_prl 5 | 6 | SOURCES += himdcli.c 7 | 8 | include(../libhimd/use_libhimd.pri) 9 | include(../build/libid3tag.pri) 10 | include(../build/libmad.pri) 11 | include(../build/libz.pri) 12 | include(../build/libglib.pri) 13 | include(../build/installunix.pri) 14 | include(../build/common.pri) 15 | -------------------------------------------------------------------------------- /libhimd/.gitignore: -------------------------------------------------------------------------------- 1 | *.prl 2 | *.a 3 | Makefile 4 | Makefile.Release 5 | Makefile.Debug 6 | himdtest 7 | -------------------------------------------------------------------------------- /libhimd/codecinfo.c: -------------------------------------------------------------------------------- 1 | #include "codecinfo.h" 2 | #include 3 | #include 4 | 5 | #define MPEG_I_SAMPLES_PER_FRAME 384 6 | #define MPEG_II_III_SAMPLES_PER_FRAME (3*MPEG_I_SAMPLES_PER_FRAME) 7 | 8 | /* for MPEG, frame size may slightly vary (+4 for layer I, +1 for layer II/III) */ 9 | unsigned int sony_codecinfo_bytesperframe(const struct sony_codecinfo *ci) 10 | { 11 | g_return_val_if_fail(ci != NULL, 0); 12 | 13 | if(sony_codecinfo_is_lpcm(ci)) 14 | return SONY_VIRTUAL_LPCM_FRAMESIZE; 15 | if(sony_codecinfo_is_at3(ci)) 16 | return ci->codecinfo[2] * 8; 17 | if(sony_codecinfo_is_at3p(ci)) 18 | return ((((ci->codecinfo[1] << 8) | ci->codecinfo[2]) & 0x3ff) + 1) * 8; 19 | if(sony_codecinfo_is_mpeg(ci)) { 20 | unsigned int mask = ~0; 21 | if((ci->codecinfo[3] & 0xC0) == 0xC0) 22 | mask = ~3; /* MPEG Layer I is specified to work DWORDs, not on 23 | bytes */ 24 | return (sony_codecinfo_samplesperframe(ci) * /* samples / frame */ 25 | (sony_codecinfo_kbps(ci)*125) / /* bytes / second */ 26 | sony_codecinfo_samplerate(ci)) /* samples / second */ 27 | & mask; 28 | /* samples and seconds cancel, bytes / frame remains. 29 | Truncation is indeed as required. */ 30 | } 31 | return 0; 32 | } 33 | 34 | unsigned int sony_codecinfo_samplesperframe(const struct sony_codecinfo *ci) 35 | { 36 | g_return_val_if_fail(ci != NULL, 0); 37 | 38 | if(sony_codecinfo_is_lpcm(ci)) 39 | return SONY_VIRTUAL_LPCM_FRAMESIZE / 4; 40 | if(sony_codecinfo_is_at3(ci)) 41 | return SONY_ATRAC3_SAMPLES_PER_FRAME; 42 | if(sony_codecinfo_is_at3p(ci)) 43 | return SONY_ATRAC3P_SAMPLES_PER_FRAME; 44 | if(sony_codecinfo_is_mpeg(ci)) 45 | { 46 | if((ci->codecinfo[3] & 0x30) == 0x30) /* MPEG Layer I */ 47 | return MPEG_I_SAMPLES_PER_FRAME; 48 | else /* MPEG Layer II & III (MP3) */ 49 | return MPEG_II_III_SAMPLES_PER_FRAME; 50 | } 51 | return 0; 52 | } 53 | 54 | static const long int atracrates[8] = {32000,44100,48000,88200,96000}; 55 | static const long int mpegrates[4] = {44100,48000,32000}; 56 | 57 | unsigned long sony_codecinfo_samplerate(const struct sony_codecinfo *ci) 58 | { 59 | g_return_val_if_fail(ci != NULL, 0); 60 | 61 | if(sony_codecinfo_is_lpcm(ci)) 62 | return 44100; 63 | if(sony_codecinfo_is_at3(ci) || sony_codecinfo_is_at3p(ci)) 64 | return atracrates[ci->codecinfo[1] >> 5]; 65 | if(sony_codecinfo_is_mpeg(ci)) 66 | return mpegrates[ci->codecinfo[4] >> 6] / (4 - (ci->codecinfo[3] >> 6)); 67 | return 0; 68 | } 69 | 70 | unsigned int sony_codecinfo_kbps(const struct sony_codecinfo *ci) 71 | { 72 | g_return_val_if_fail(ci != NULL, 0); 73 | 74 | if(!sony_codecinfo_is_mpeg(ci)) 75 | /* ATRAC & LPCM: calculate kbps from frame size */ 76 | return (unsigned long)sony_codecinfo_bytesperframe(ci) * 77 | sony_codecinfo_samplerate(ci) / 78 | (125*sony_codecinfo_samplesperframe(ci)); 79 | /* 125 = bytes per kbit */ 80 | else { 81 | /* MPEG: kbps is well-defined, bytes/frame is calculated from it */ 82 | static const short v1l1[16] = {0,32,64,96,128,160,192,224,256,288,320,352,384,416,448,0}; 83 | static const short v1l2[16] = {0,32,48,56,64,80,96,112,128,160,192,224,256,320,384,0}; 84 | static const short v1l3[16] = {0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}; 85 | static const short v2l1[16] = {0,32,48,56,64,80,96,112,128,144,160,176,192,224,256,0}; 86 | static const short v2l23[16] = {0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}; 87 | static const short* vl[2][3] = {{v1l1,v1l2,v1l3},{v2l1,v2l23,v2l23}}; 88 | if((ci->codecinfo[3] & 0xC0) == 0x40 || (ci->codecinfo[3] & 0x30) == 0) 89 | return 0; /* invalid header info */ 90 | return vl[1-((ci->codecinfo[3] & 0x40) >> 6)] 91 | [3-((ci->codecinfo[3] & 0x30) >> 4)] 92 | [ci->codecinfo[3] & 0xF]; 93 | } 94 | } 95 | 96 | unsigned int sony_codecinfo_seconds(const struct sony_codecinfo *ci, unsigned int frames) 97 | { 98 | g_return_val_if_fail(ci != NULL, 0); 99 | return ((guint64)frames * sony_codecinfo_samplesperframe(ci)) / 100 | sony_codecinfo_samplerate(ci); 101 | } 102 | 103 | const char * sony_codecinfo_codecname(const struct sony_codecinfo *ci) 104 | { 105 | static char buffer[5]; 106 | 107 | g_return_val_if_fail(ci != NULL, "(nullptr)"); 108 | 109 | if(sony_codecinfo_is_lpcm(ci)) 110 | return "LPCM"; 111 | if(sony_codecinfo_is_at3(ci)) 112 | return "AT3 "; 113 | if(sony_codecinfo_is_at3p(ci)) 114 | return "AT3+"; 115 | if(sony_codecinfo_is_mpeg(ci)) 116 | return "MPEG"; 117 | /* codec_id is supposed to be an unsigned char. Adding the mask 118 | anyway to prevent a buffer overflow if someone cooses to enlarge 119 | it or compile on a machine with CHAR_BITS > 13 */ 120 | sprintf(buffer,"%4d",ci->codec_id & 0xFF); 121 | return buffer; 122 | } 123 | -------------------------------------------------------------------------------- /libhimd/codecinfo.h: -------------------------------------------------------------------------------- 1 | #ifndef ATRAC_H 2 | #define ATRAC_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | #define CODEC_ATRAC3 0x00 11 | #define CODEC_ATRAC3PLUS_OR_MPEG 0x01 12 | #define CODEC_LPCM 0x80 13 | 14 | #define SONY_VIRTUAL_LPCM_FRAMESIZE 64 15 | #define SONY_ATRAC3_SAMPLES_PER_FRAME 1024 16 | #define SONY_ATRAC3P_SAMPLES_PER_FRAME 2048 17 | 18 | #define TRACK_IS_MPEG 0 19 | struct sony_codecinfo { 20 | unsigned char codec_id; 21 | unsigned char codecinfo[5]; 22 | }; 23 | 24 | unsigned int sony_codecinfo_bytesperframe(const struct sony_codecinfo *ci); 25 | unsigned int sony_codecinfo_samplesperframe(const struct sony_codecinfo *ci); 26 | unsigned long sony_codecinfo_samplerate(const struct sony_codecinfo *ci); 27 | unsigned int sony_codecinfo_kbps(const struct sony_codecinfo *ci); 28 | unsigned int sony_codecinfo_seconds(const struct sony_codecinfo *ci, unsigned int frames); 29 | const char * sony_codecinfo_codecname(const struct sony_codecinfo *ci); 30 | #define sony_codecinfo_is_lpcm(ci) ((ci)->codec_id == CODEC_LPCM) 31 | #define sony_codecinfo_is_at3(ci) ((ci)->codec_id == CODEC_ATRAC3) 32 | #define sony_codecinfo_is_mpeg(ci) ((ci)->codec_id == CODEC_ATRAC3PLUS_OR_MPEG && \ 33 | ((ci)->codecinfo[0] & 3) == 3) 34 | #define sony_codecinfo_is_at3p(ci) ((ci)->codec_id == CODEC_ATRAC3PLUS_OR_MPEG && \ 35 | ((ci)->codecinfo[0] & 3) != 3) 36 | 37 | #ifdef __cplusplus 38 | } 39 | #endif 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /libhimd/frag.c: -------------------------------------------------------------------------------- 1 | /* 2 | * frag.c 3 | * 4 | * This file is part of libhimd, a library for accessing Sony HiMD devices. 5 | * 6 | * Copyright (C) 2009-2011 Michael Karcher 7 | * Copyright (C) 2011 Mårten Cassel 8 | * Copyright (C) 2011 Thomas Arp 9 | * 10 | * This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU Lesser General Public 12 | * License as published by the Free Software Foundation; either 13 | * version 2.1 of the License, or (at your option) any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | * Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public 21 | * License along with this library; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23 | * 24 | */ 25 | 26 | #include "himd.h" 27 | #include 28 | 29 | #define MIN_HOLE 4 30 | #define NO_SUCH_HOLE 0xffff 31 | 32 | static int search_hole(struct himd_holelist * holes, int block) 33 | { 34 | int startidx = 0; 35 | int endidx = holes->holecnt-1; 36 | while(startidx != endidx) 37 | { 38 | int mididx = (startidx + endidx)/2; 39 | if(holes->holes[mididx].lastblock < block) 40 | startidx = mididx+1; 41 | else 42 | endidx = mididx; 43 | } 44 | /* block is not in a hole */ 45 | if(holes->holes[startidx].firstblock > block) 46 | return NO_SUCH_HOLE; 47 | return startidx; 48 | } 49 | 50 | /** 51 | * Find all holes in current HiMD data and return them in himd_holelist. 52 | * This call is required prior to any write operation to HiMD data to 53 | * be able to collect necessary space to store the fragments of a track to be 54 | * written. 55 | * 56 | * @param himd Pointer to a descriptor of previously opened HiMD data 57 | * @param holes Pointer to a list of holes, is filled out by himd_find_holes 58 | * @param status Pointer to himderrinfo, returns error code after operation 59 | * 60 | * @return Returns 0 if successful, -1 otherwise 61 | */ 62 | int himd_find_holes(struct himd * himd, struct himd_holelist * holes, struct himderrinfo * status) 63 | { 64 | int i; 65 | holes->holecnt = 1; 66 | holes->holes[0].firstblock = 0; 67 | holes->holes[0].lastblock = 0xFFFF; 68 | for(i = HIMD_FIRST_FRAGMENT;i < HIMD_LAST_FRAGMENT;i++) 69 | { 70 | struct fraginfo frag; 71 | int splitidx; 72 | if(himd_get_fragment_info(himd, i, &frag, status) < 0) 73 | return -1; 74 | if(frag.firstblock == 0 && frag.lastblock == 0) 75 | continue; /* unused fragment */ 76 | splitidx = search_hole(holes, frag.firstblock); 77 | /* If splitidx == NO_SUCH_HOLE, the fragment probably is so small that 78 | the hole had been erased due to minhole */ 79 | if(splitidx == NO_SUCH_HOLE) 80 | continue; 81 | 82 | /* a fragment splits a hole into two holes (the one before and 83 | the one after the fragment). Either of these two holes might 84 | be too small to be considered, in which case these holes are 85 | discarded, or, spoken another way, the used areas are collapsed 86 | into one used area. */ 87 | if(frag.firstblock - holes->holes[splitidx].firstblock < MIN_HOLE) 88 | { 89 | /* collapse at the beginning */ 90 | holes->holes[splitidx].firstblock = frag.lastblock + 1; 91 | if(holes->holes[splitidx].lastblock < holes->holes[splitidx].firstblock || 92 | holes->holes[splitidx].lastblock - holes->holes[splitidx].firstblock < MIN_HOLE) 93 | { 94 | /* this hole has been "completely" filled by the fragment */ 95 | memmove(holes->holes + splitidx, holes->holes + splitidx + 1, 96 | (holes->holecnt - splitidx - 1) * sizeof(holes->holes[0])); 97 | holes->holecnt--; 98 | } 99 | } 100 | else 101 | { 102 | /* doesn't collapse at the beginning */ 103 | if(holes->holes[splitidx+1].firstblock - frag.lastblock < MIN_HOLE) 104 | /* but collapses at the end */ 105 | holes->holes[splitidx].lastblock = frag.firstblock - 1; 106 | else 107 | { 108 | memmove(holes->holes + splitidx + 1, holes->holes + splitidx, 109 | (holes->holecnt - splitidx) * sizeof(holes->holes[0])); 110 | holes->holecnt++; 111 | holes->holes[splitidx].lastblock = frag.firstblock - 1; 112 | holes->holes[splitidx+1].firstblock = frag.lastblock + 1; 113 | } 114 | } 115 | } 116 | return 0; 117 | } 118 | -------------------------------------------------------------------------------- /libhimd/himd_private.h: -------------------------------------------------------------------------------- 1 | static inline unsigned int beword16(const unsigned char * c) 2 | { 3 | return c[0]*256+c[1]; 4 | } 5 | 6 | static inline unsigned int beword32(const unsigned char * c) 7 | { 8 | return c[0]*16777216+c[1]*65536+c[2]*256+c[3]; 9 | } 10 | 11 | 12 | static inline void setbeword16(unsigned char * c, unsigned int val) 13 | { 14 | c[0] = val >> 8; 15 | c[1] = val & 0xFF; 16 | } 17 | 18 | static inline void setbeword32(unsigned char * c, unsigned int val) 19 | { 20 | c[0] = (val >> 24) & 0xFF; 21 | c[1] = (val >> 16) & 0xFF; 22 | c[2] = (val >> 8) & 0xFF; 23 | c[3] = val & 0xFF; 24 | } 25 | 26 | void set_status_const(struct himderrinfo * status, enum himdstatus code, const char * msg); 27 | void set_status_printf(struct himderrinfo * status, enum himdstatus code, const char * format, ...); 28 | 29 | int descrypt_open(void ** dataptr, const unsigned char * trackkey, 30 | unsigned int ekbnum, struct himderrinfo * status); 31 | int descrypt_decrypt(void * dataptr, unsigned char * block, size_t cryptlen, 32 | const unsigned char * fragkey, struct himderrinfo * status); 33 | void descrypt_close(void * dataptr); 34 | -------------------------------------------------------------------------------- /libhimd/himdll.h: -------------------------------------------------------------------------------- 1 | #include "himd.h" 2 | 3 | /* special low-level functions */ 4 | 5 | int himdll_get_track_info(struct himd * himd, unsigned int idx, struct trackinfo * t, struct himderrinfo * status); 6 | int himdll_strtype(struct himd *himd, unsigned int idx); 7 | int himdll_strlink(struct himd *himd, unsigned int idx); 8 | -------------------------------------------------------------------------------- /libhimd/libhimd.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | TARGET = himd 3 | CONFIG -= qt 4 | CONFIG += staticlib link_pkgconfig create_prl console debug_and_release_target 5 | 6 | HEADERS += codecinfo.h himd.h himd_private.h sony_oma.h 7 | SOURCES += codecinfo.c encryption.c himd.c mdstream.c trackindex.c sony_oma.c frag.c mp3tools.c mp3download.c 8 | 9 | include(../build/libmad.pri) 10 | include(../build/libgcrypt.pri) 11 | include(../build/libglib.pri) 12 | include(../build/common.pri) 13 | -------------------------------------------------------------------------------- /libhimd/mp3tools.c: -------------------------------------------------------------------------------- 1 | /* 2 | * mp3tools.c 3 | * 4 | * This file is part of libhimd, a library for accessing Sony HiMD devices. 5 | * 6 | * Copyright (C) 2009-2011 Michael Karcher 7 | * Copyright (C) 2011 Mårten Cassel 8 | * Copyright (C) 2011 Thomas Arp 9 | * 10 | * This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU Lesser General Public 12 | * License as published by the Free Software Foundation; either 13 | * version 2.1 of the License, or (at your option) any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | * Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public 21 | * License along with this library; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23 | * 24 | */ 25 | 26 | #include 27 | #include "himd.h" 28 | #include "himd_private.h" 29 | 30 | static inline char *dup_id3_first_string(union id3_field const *field) 31 | { 32 | return (char *)id3_ucs4_utf8duplicate(id3_field_getstrings(field, 0)); 33 | } 34 | 35 | /* 36 | * gets artist, title and album info from an ID3 tag. 37 | * The output strings are to be free()d. 38 | * Returns -1, if id3 informations could be extracted. 39 | */ 40 | int himd_get_songinfo(const char *filepath, char ** artist, char ** title, char **album, struct himderrinfo * status) 41 | { 42 | struct id3_file * file; 43 | struct id3_frame const *frame; 44 | struct id3_tag *tag; 45 | union id3_field const *field; 46 | 47 | file = id3_file_open(filepath, ID3_FILE_MODE_READONLY); 48 | 49 | tag = id3_file_tag(file); 50 | if(!tag) 51 | { 52 | id3_file_close(file); 53 | set_status_printf(status, HIMD_ERROR_NO_ID3_TAGS_FOUND, "no id3 tags found in file '%s'", filepath); 54 | return -1; 55 | } 56 | 57 | frame = id3_tag_findframe (tag, ID3_FRAME_ARTIST, 0); 58 | if(frame && (field = &frame->fields[1]) && 59 | id3_field_getnstrings(field) > 0) 60 | *artist = dup_id3_first_string(field); 61 | else 62 | *artist = NULL; 63 | 64 | frame = id3_tag_findframe (tag, ID3_FRAME_TITLE, 0); 65 | if(frame && (field = &frame->fields[1]) && 66 | id3_field_getnstrings(field) > 0) 67 | *title = dup_id3_first_string(field); 68 | else 69 | *title = NULL; 70 | 71 | frame = id3_tag_findframe (tag, ID3_FRAME_ALBUM, 0); 72 | if(frame && (field = &frame->fields[1]) && 73 | id3_field_getnstrings(field) > 0) 74 | *album = dup_id3_first_string(field); 75 | else 76 | *album = NULL; 77 | 78 | id3_file_close(file); 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /libhimd/sony_oma.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sony_oma.c 3 | * 4 | * This file is part of libhimd, a library for accessing Sony HiMD devices. 5 | * 6 | * Copyright (C) 2009-2011 Michael Karcher 7 | * Copyright (C) 2011 Mårten Cassel 8 | * Copyright (C) 2011 Thomas Arp 9 | * 10 | * This library is free software; you can redistribute it and/or 11 | * modify it under the terms of the GNU Lesser General Public 12 | * License as published by the Free Software Foundation; either 13 | * version 2.1 of the License, or (at your option) any later version. 14 | * 15 | * This library is distributed in the hope that it will be useful, 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 18 | * Lesser General Public License for more details. 19 | * 20 | * You should have received a copy of the GNU Lesser General Public 21 | * License along with this library; if not, write to the Free Software 22 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 23 | * 24 | */ 25 | 26 | #include "himd.h" 27 | #include "sony_oma.h" 28 | #include 29 | 30 | void make_ea3_format_header(char * header, const struct sony_codecinfo * trkinfo) 31 | { 32 | static const char ea3header[12] = 33 | {0x45, 0x41, 0x33, 0x01, 0x00, 0x60, 34 | 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; 35 | 36 | memset(header, 0, EA3_FORMAT_HEADER_SIZE); 37 | memcpy(header , ea3header,12); 38 | /* Do not set the content ID - this activates DRM stuff in Sonic Stage. 39 | A track with an unknown content ID can not be converted nor transferred. 40 | A zero content ID seems to mean "no DRM, for real!" */ 41 | /*memcpy(header+12, trkinfo->contentid,20);*/ 42 | header[32] = trkinfo->codec_id; 43 | memcpy(header+33, trkinfo->codecinfo, 3); 44 | } 45 | -------------------------------------------------------------------------------- /libhimd/sony_oma.h: -------------------------------------------------------------------------------- 1 | #ifndef INCLUDED_LIBHIMD_OMA_H 2 | #define INCLUDED_LIBHIMD_OMA_H 3 | 4 | #include "codecinfo.h" 5 | 6 | #define EA3_FORMAT_HEADER_SIZE 96 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | void make_ea3_format_header(char * header, const struct sony_codecinfo * ci); 13 | 14 | #ifdef __cplusplus 15 | } 16 | #endif 17 | 18 | #endif -------------------------------------------------------------------------------- /libhimd/use_libhimd.pri: -------------------------------------------------------------------------------- 1 | # the QMAKE_LIBDIR thing is a workaround for a bug in qmake on mingw: 2 | # it searches prl files for library dependencies only QMAKE_LIBDIR and 3 | # ignores "-L" parametes in LIBS. 4 | 5 | build_pass:CONFIG(debug,debug|release) { 6 | QMAKE_LIBDIR += ../libhimd/debug 7 | LIBS += -L../libhimd/debug 8 | } 9 | build_pass:CONFIG(release,debug|release) { 10 | QMAKE_LIBDIR += ../libhimd/release 11 | LIBS += -L../libhimd/release 12 | } 13 | 14 | # fallback if libhimd was not compiled with 15 | # CONFIG += debug_and_release debug_and_release_target 16 | # while I force debug_and_release_target, it is ignored in a 17 | # just-one-kind build without debug_and_release 18 | 19 | QMAKE_LIBDIR += ../libhimd 20 | LIBS += -L../libhimd 21 | 22 | INCLUDEPATH += ../libhimd 23 | LIBS += -lhimd 24 | -------------------------------------------------------------------------------- /libnetmd/.cdtproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /libnetmd/.gitignore: -------------------------------------------------------------------------------- 1 | documentation/html 2 | documentation/latex 3 | libnetmd.so.* 4 | libnetmd.a 5 | Makefile 6 | Makefile.Release 7 | Makefile.Debug 8 | *.prl -------------------------------------------------------------------------------- /libnetmd/.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | libnetmd 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.cdt.core.cbuilder 10 | 11 | 12 | 13 | 14 | 15 | org.eclipse.cdt.core.cnature 16 | 17 | 18 | -------------------------------------------------------------------------------- /libnetmd/CHANGELOG: -------------------------------------------------------------------------------- 1 | * June 21 - July 11th, 2004, Bertrik Sikken v.Unstable 2 | - hotplug-netmd: Added sleep 1 and handling of remove event. 3 | - netmd.c: Added 'raw' command to send a raw hex command. 4 | - moved netmd usb device function from libnetmd.c into netmd_dev.c 5 | - libnetmd.c/netmd.c: Added 'setplaymode' command. 6 | - renamed usb_dev_handle into netmd_dev_handle 7 | - updated netmd_init function. It now returns a list of supported devices. 8 | - added netmd_close function. This does the opposite of netmd_open. 9 | - updated netmd_clean function. Instead of just closing the netmd device, 10 | it cleans up the stuff left behind by netmd_init. 11 | - added netmd_trace.c file that implements simple tracing functions 12 | - added support for setting options from the command line 13 | 14 | * March 25 - April 26, 2004, Bertrik Sikken v.Unstable 15 | - Makefile: Added install-hotplug rule that installs the minidisc hotplug 16 | scripts/files into /etc/hotplug/usb. 17 | - Makefile: Added dist rule to Makefile that creates a timestamped tar.gz of 18 | the sources. 19 | - hotplug-netmd: Added check on action (should be 'add') and existence of 20 | device file. 21 | - libnetmd.c: Removed usb_set_configuration (not needed, yet was giving 22 | problems with hotplug). 23 | - libnetmd.c: Simplified function netmd_get_devname (now uses libusb function 24 | usb_get_string_simple). 25 | - libnetmd.c: Added USB IDs of Sony MZ-N710/N810 26 | 27 | * March 24, 2004, Bertrik Sikken v.Unstable 28 | - Updated netmd_exch_message function to make it compatible with the Sony 29 | MDS-JB980 with help of Chris Croughton (0x0F responses are ignored now) 30 | 31 | * March 23, 2004, Bertrik Sikken v.Unstable 32 | - Added test functions related to check-in/check-out (added libnetmd_secure.c) 33 | 34 | * March 21 2004 Bertrik Sikken v.Unstable 35 | - Removed duplicate strdup in function netmd_initialize_disc_info 36 | - Removed DEVICE_COUNT #define, now using terminating pair in netmd_devices 37 | list. 38 | - Added netmd_exch_message function that sends a command to and receives 39 | response from the player, with proper respect for the USB status indicated by 40 | the player. Replaced ad-hoc calls to usb_control_msg by simple calls to the 41 | netmd_exch_message function. 42 | - Replaced magic numbers for USB request type in usb_control_msg by proper 43 | defined values. 44 | - Updated names in list of USB ids and sorted list. 45 | - Removed unnecessary CODECS and BITRATES defines. 46 | - Applied get_devname patch. 47 | - Fixed bug that prevented parsing of titles that contain a forward slash (/). 48 | 49 | * Monday March 15 2004 Edward Mann v.Unstable. 50 | - Added {0x54c, 0xc9} /* Sony MZ-N510 */ 51 | - Created this Change log -------------------------------------------------------------------------------- /libnetmd/common.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBNETMD_COMMON_H 2 | #define LIBNETMD_COMMON_H 3 | 4 | #include 5 | 6 | /** 7 | Typedef that nearly all netmd_* functions use to identify the USB connection 8 | with the minidisc player. 9 | */ 10 | typedef libusb_device_handle *netmd_dev_handle; 11 | 12 | /** 13 | Function to exchange command/response buffer with minidisc player. 14 | 15 | @param dev device handle 16 | @param cmd buffer with the command, that should be send to the player 17 | @param cmdlen length of the command 18 | @param rsp buffer where the response should be written to 19 | @return number of bytes received if >0, or error if <0 20 | */ 21 | int netmd_exch_message(netmd_dev_handle *dev, unsigned char *cmd, 22 | const size_t cmdlen, unsigned char *rsp); 23 | 24 | /** 25 | Function to send a command to the minidisc player. 26 | 27 | @param dev device handle 28 | @param cmd buffer with the command, that should be send to the player 29 | @param cmdlen length of the command 30 | */ 31 | int netmd_send_message(netmd_dev_handle *dev, unsigned char *cmd, 32 | const size_t cmdlen); 33 | 34 | 35 | /** 36 | Function to recieve a response from the minidisc player. 37 | 38 | @param rsp buffer where the response should be written to 39 | @return number of bytes received if >0, or error if <0 40 | */ 41 | int netmd_recv_message(netmd_dev_handle *dev, unsigned char *rsp); 42 | 43 | /** 44 | Wait for the device to respond to commands. Should only be used 45 | when the device needs to be given "breathing room" and is not 46 | expected to have anything to send. 47 | 48 | @param dev device handle 49 | @return 1 if success, 0 if there was no response 50 | */ 51 | int netmd_wait_for_sync(netmd_dev_handle* dev); 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /libnetmd/const.h: -------------------------------------------------------------------------------- 1 | #ifndef CONST_H 2 | #define CONST_H 3 | 4 | /** 5 | Error codes of the USB transport layer 6 | */ 7 | #define NETMDERR_USB -1 /**< general USB error */ 8 | #define NETMDERR_NOTREADY -2 /**< player not ready for command */ 9 | #define NETMDERR_TIMEOUT -3 /**< timeout while waiting for response */ 10 | #define NETMDERR_CMD_FAILED -4 /**< minidisc responded with 08 response */ 11 | #define NETMDERR_CMD_INVALID -5 /**< minidisc responded with 0A response */ 12 | 13 | /** 14 | Playmode values to be sent to netmd_set_playmode. These can be combined by 15 | OR-ing them to do shuffle repeat for example. 16 | 17 | See also: http://article.gmane.org/gmane.comp.audio.netmd.devel/848 18 | */ 19 | #define NETMD_PLAYMODE_SINGLE 0x0040 20 | #define NETMD_PLAYMODE_REPEAT 0x0080 21 | #define NETMD_PLAYMODE_SHUFFLE 0x0100 22 | 23 | /** 24 | playback controll commands 25 | */ 26 | #define NETMD_PLAY 0x75 27 | #define NETMD_PAUSE 0x7d 28 | #define NETMD_REWIND 0x49 29 | #define NETMD_FFORWARD 0x39 30 | 31 | /** 32 | change track commands 33 | */ 34 | #define NETMD_TRACK_PREVIOUS 0x0002 35 | #define NETMD_TRACK_NEXT 0x8001 36 | #define NETMD_TRACK_RESTART 0x0001 37 | 38 | /** 39 | NetMD Protocol return status (first byte of request) 40 | */ 41 | #define NETMD_STATUS_CONTROL 0x00 42 | #define NETMD_STATUS_STATUS 0x01 43 | #define NETMD_STATUS_SPECIFIC_INQUIRY 0x02 44 | #define NETMD_STATUS_NOTIFY 0x03 45 | #define NETMD_STATUS_GENERAL_INQUIRY 0x04 46 | 47 | /** 48 | NetMD Protocol return status (first byte of response) 49 | */ 50 | #define NETMD_STATUS_NOT_IMPLEMENTED 0x08 51 | #define NETMD_STATUS_ACCEPTED 0x09 52 | #define NETMD_STATUS_REJECTED 0x0a 53 | #define NETMD_STATUS_IN_TRANSITION 0x0b 54 | #define NETMD_STATUS_IMPLEMENTED 0x0c 55 | #define NETMD_STATUS_CHANGED 0x0d 56 | #define NETMD_STATUS_INTERIM 0x0f 57 | 58 | #define NETMD_ENCODING_SP 0x90 59 | #define NETMD_ENCODING_LP2 0x92 60 | #define NETMD_ENCODING_LP4 0x93 61 | 62 | #define NETMD_CHANNELS_MONO 0x01 63 | #define NETMD_CHANNELS_STEREO 0x00 64 | 65 | #define NETMD_OPERATING_STATUS_USB_RECORDING 0x56ff 66 | #define NETMD_OPERATING_STATUS_RECORDING 0xc275 67 | #define NETMD_OPERATING_STATUS_RECORDING_PAUSED 0xc27d 68 | #define NETMD_OPERATING_STATUS_FAST_FORWARDING 0xc33f 69 | #define NETMD_OPERATING_STATUS_REWINDING 0xc34f 70 | #define NETMD_OPERATING_STATUS_PLAYING 0xc375 71 | #define NETMD_OPERATING_STATUS_PAUSED 0xc37d 72 | #define NETMD_OPERATING_STATUS_STOPPED 0xc5ff 73 | 74 | #define NETMD_TRACK_FLAG_PROTECTED 0x03 75 | 76 | #define NETMD_DISC_FLAG_WRITABLE 0x10 77 | #define NETMD_DISC_FLAG_WRITE_PROTECTED 0x40 78 | 79 | #define NETMD_DISKFORMAT_LP4 0 80 | #define NETMD_DISKFORMAT_LP2 2 81 | #define NETMD_DISKFORMAT_SP_MONO 4 82 | #define NETMD_DISKFORMAT_SP_STEREO 6 83 | 84 | #define NETMD_RIFF_FORMAT_TAG_ATRAC3 0x270 85 | #define NETMD_DATA_BLOCK_SIZE_LP2 384 86 | #define NETMD_DATA_BLOCK_SIZE_LP4 192 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /libnetmd/documentation/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The libnetmd Project :: Putting the funk in your trunk. 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |

19 |

libnetmd

20 |
21 | 22 |
  
23 |
24 | 25 | 26 |

Welcome to the libnetmd project website. libnetmd is an open source effort 27 | to provide tools for use with Sony 28 | NetMD recorders under operating systems supported by the libusb 29 | project (currently Linux, Net/Free/OpenBSD and preliminary MacOS X support).

30 |

The project is composed of libnetmd (which provides core functionality) and 31 | libnetmd (the user interface to libnetmd). Currently libnetmd is the only avalible 32 | component and development on the libnetmd interface is expected to begin soon.

33 |

While our primary development platform is Linux for i386 hardware, our current 34 | code base is also known to work under MacOS X on PowerPC. One of our primary 35 | aims is cross-platform compatibility. If you get the chance to test libnetmd 36 | on any other platforms libusb supports, please let us know the results.

37 |

Currently libnetmd supports the following operations on all currently known 38 | NetMD recorders:

39 |
    40 |
  • renaming and moving tracks (in and out of groups)
  • 41 |
  • renaming and moving groups (experimental)
  • 42 |
  • renaming disc (experimental)
  • 43 |
  • printing TOC of disc
  • 44 |
  • creating/deleteing groups
  • 45 |
  • removing tracks
  • 46 |
  • play, pause, fast forward, rewind and stop
  • 47 |
  • and probably some other stuff
  • 48 |
49 |

In the future we hope to support uploading audio to NetMD recorders and all 50 | other editing functions which are not presently implemented.

51 |

Check out the main menu to the left for downloads, documentation, news and 52 | other items of interest. If you'd like to get involved with the project, join 53 | the netmd-devel mailing list. 54 | Read up on how to access the sourcecode 55 | 56 |

57 | If you are user who has questions please see our libnetmd-users 58 | mailing list.

59 | You may also want to check out our forums. 60 |
61 | 62 | 63 | 64 |

65 |
66 |
67 | 68 | 69 | -------------------------------------------------------------------------------- /libnetmd/documentation/index_files/logo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 404 Not Found 4 | 5 |

Not Found

6 | The requested URL /images/logo.gif was not found on this server.

7 |


8 |
Apache/1.3.26 Server at opennmd.monochromatic.net Port 80
9 | 10 | -------------------------------------------------------------------------------- /libnetmd/documentation/index_files/openwindow.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 404 Not Found 4 | 5 |

Not Found

6 | The requested URL /javascript/openwindow.php was not found on this server.

7 |


8 |
Apache/1.3.26 Server at opennmd.monochromatic.net Port 80
9 | 10 | -------------------------------------------------------------------------------- /libnetmd/documentation/index_files/pix.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 404 Not Found 4 | 5 |

Not Found

6 | The requested URL /images/global/pix.gif was not found on this server.

7 |


8 |
Apache/1.3.26 Server at opennmd.monochromatic.net Port 80
9 | 10 | -------------------------------------------------------------------------------- /libnetmd/documentation/index_files/showimages.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 404 Not Found 4 | 5 |

Not Found

6 | The requested URL /javascript/showimages.php was not found on this server.

7 |


8 |
Apache/1.3.26 Server at opennmd.monochromatic.net Port 80
9 | 10 | -------------------------------------------------------------------------------- /libnetmd/documentation/index_files/styleNN.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 404 Not Found 4 | 5 |

Not Found

6 | The requested URL /themes/ExtraLite/style/styleNN.css was not found on this server.

7 |


8 |
Apache/1.3.26 Server at opennmd.monochromatic.net Port 80
9 | 10 | -------------------------------------------------------------------------------- /libnetmd/documentation/protocol2.txt: -------------------------------------------------------------------------------- 1 | This document is more a dumping ground for the command block format I think the protocol uses. 2 | 3 | To see examples of the command block format see protocol.txt and vpl-px21.pdf 4 | 5 | all numbers are in hex if i'm referencing a hex number in terms of a decimal number i will give the hex number fist and the decimal number second surounded by () 6 | the term char that I use comes from the C datatype which can hold one hex code (00-ff) 7 | 8 | IMPORTANT! -- usb_control_msg from libusb takes the direction as a part of requesttype this would normally be 0x00 for out and 0x80 for in 9 | -- Sony thinks otherwise, its 0xc1 for in and 0x41 for out. (directions from the perspective of the device, in means I'm taking input from the NetMD) 10 | 11 | //-- standard request 12 | (00/09) - 00 seems to come from the host 09 from the device, start of every binary data chunk. 13 | 14 | 18 - Peripheral index - in this case the NetMD(18) or 81 which is used for a generic reply code 15 | 16 | 06/07/43 - Read/write/move - All infomational commands seem to use 06 while data changing commands use 07 17 | - actual track movement is done w/ 43 18 | 19 | 02 20 18- these 3 chars appear in everything except when 20 18 is replaced with 10 10 20 | 02 20 10- Track time, codec and bitrate all use this, track info vs track data? 21 | 22 | (01/02) - 01 seems to deal with Disc info/Group info while 02 seems to be track info 23 | 24 | 00 xx - track number(zero based track 1 is 00) 25 | 26 | 30 00 0a/01 - appear in all disc or track based commands and replies 27 | 28 | 00 (50/ff) - 50 appears in Set(07 style) commands and ff in get(06 style) commands 29 | 30 | 00 00 0x - where x is buffer length for set functions 31 | 32 | //-- odd man out - 4 char reply from device for buffer size needed to get data 33 | 01 is used in the buffer size report 34 | 81 35 | 36 | 00 37 | 38 | -------------------------------------------------------------------------------- /libnetmd/error.c: -------------------------------------------------------------------------------- 1 | /* 2 | * error.c 3 | * 4 | * This file is part of libnetmd, a library for accessing Sony NetMD devices. 5 | * 6 | * Copyright (C) 2011 Alexander Sulfrian 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | * 22 | */ 23 | 24 | #include "error.h" 25 | 26 | struct error_description { 27 | netmd_error error; 28 | const char* const description; 29 | }; 30 | 31 | static struct error_description const descriptions[] = { 32 | {NETMD_NO_ERROR, "No error"}, 33 | {NETMD_NOT_IMPLEMENTED, "Not implemented"}, 34 | 35 | {NETMD_USB_OPEN_ERROR, "Error while opening the USB device"}, 36 | {NETMD_USB_ERROR, "Generic USB error"}, 37 | 38 | {NETMD_RESPONSE_TO_SHORT, "Response from device is shorter than expected."}, 39 | {NETMD_RESPONSE_NOT_EXPECTED, "Response from device does not match with the expected result."}, 40 | 41 | {NETMD_DES_ERROR, "Error during des caluclation."} 42 | }; 43 | 44 | static char const unknown_error[] = "Unknown Error"; 45 | 46 | const char* netmd_strerror(netmd_error error) 47 | { 48 | unsigned int i = 0; 49 | unsigned int elements; 50 | 51 | /* calculate the number of elements in the array */ 52 | elements = sizeof(descriptions) / sizeof(*descriptions); 53 | 54 | for (i = 0; i < elements; i++) { 55 | if (descriptions[i].error == error) { 56 | return descriptions[i].description; 57 | } 58 | } 59 | 60 | return unknown_error; 61 | } 62 | -------------------------------------------------------------------------------- /libnetmd/error.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBNETMD_ERROR_H 2 | #define LIBNETMD_ERROR_H 3 | 4 | /** 5 | Enum with possible error codes the netmd_* functions could return. 6 | 7 | @see netmd_strerror 8 | */ 9 | typedef enum { 10 | 11 | NETMD_NO_ERROR = 0, 12 | NETMD_NOT_IMPLEMENTED, 13 | 14 | NETMD_USB_OPEN_ERROR, 15 | NETMD_USB_ERROR, 16 | 17 | NETMD_ERROR, 18 | 19 | NETMD_RESPONSE_TO_SHORT, 20 | NETMD_RESPONSE_NOT_EXPECTED, 21 | 22 | NETMD_COMMAND_FAILED_NO_RESPONSE, 23 | NETMD_COMMAND_FAILED_NOT_IMPLEMENTED, 24 | NETMD_COMMAND_FAILED_REJECTED, 25 | NETMD_COMMAND_FAILED_UNKNOWN_ERROR, 26 | 27 | NETMD_DES_ERROR, 28 | 29 | NETMD_USE_HOTPLUG 30 | 31 | } netmd_error; 32 | 33 | /** 34 | Function that could be used to get a string describing the given error 35 | number. 36 | 37 | @param error Error number to get the description for. 38 | @return Pointer to static char buffer to the error description. (Should not 39 | be freed.) 40 | */ 41 | const char* netmd_strerror(netmd_error error); 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /libnetmd/hotplug-netmd: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # hack: wait 1 second to improve chance that /proc/bus/usb file is present during add 4 | sleep 1 5 | 6 | # handle add event 7 | if [ "${ACTION}" = "add" ] && [ -f "${DEVICE}" ] 8 | then 9 | logger -t netmd NetMD plugged in at $DEVICE 10 | chown root.usb $DEVICE 11 | chmod ug+w $DEVICE 12 | 13 | # create symbolic link to catch remove event 14 | mkdir -p `dirname $REMOVER` 15 | ln -s $0 $REMOVER 16 | fi 17 | 18 | # handle remove event 19 | if [ "${ACTION}" = "remove" ] 20 | then 21 | logger -t netmd NetMD unplugged from $DEVICE 22 | fi 23 | -------------------------------------------------------------------------------- /libnetmd/libnetmd.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = lib 2 | TARGET = netmd 3 | CONFIG -= qt 4 | CONFIG += staticlib link_pkgconfig create_prl console debug_and_release_target 5 | 6 | HEADERS += common.h const.h error.h libnetmd.h log.h netmd_dev.h playercontrol.h secure.h trackinformation.h utils.h \ 7 | libnetmd_extended.h 8 | SOURCES += common.c error.c libnetmd.c log.c netmd_dev.c playercontrol.c secure.c trackinformation.c utils.c 9 | 10 | include(../build/libgcrypt.pri) 11 | include(../build/libusb.pri) 12 | include(../build/common.pri) 13 | -------------------------------------------------------------------------------- /libnetmd/libnetmd_extended.h: -------------------------------------------------------------------------------- 1 | /* 2 | * include this header file to get access to additional libnetmd members 3 | */ 4 | 5 | #include "libnetmd.h" 6 | 7 | typedef struct { 8 | unsigned char content[255]; 9 | size_t length; 10 | size_t position; 11 | } netmd_response; 12 | 13 | /* 14 | * additional members from secure.c 15 | */ 16 | 17 | void netmd_send_secure_msg(netmd_dev_handle *dev, unsigned char cmd, unsigned char *data, size_t data_size); 18 | netmd_error netmd_recv_secure_msg(netmd_dev_handle *dev, unsigned char cmd, netmd_response *response, 19 | unsigned char expected_response_code); 20 | netmd_error netmd_secure_real_recv_track(netmd_dev_handle *dev, uint32_t length, FILE *file, size_t chunksize); 21 | void netmd_write_aea_header(char *name, uint32_t frames, unsigned char channel, FILE* f); 22 | void netmd_write_wav_header(unsigned char format, uint32_t bytes, FILE *f); 23 | 24 | /* 25 | * additional members from utils.c 26 | * XXX: do not include utils.h when using taglib, definition of min(a,b) is incomatible with definition of min(...) in taglib 27 | */ 28 | void netmd_check_response_bulk(netmd_response *response, const unsigned char* const expected, 29 | const size_t expected_length, netmd_error *error); 30 | void netmd_check_response_word(netmd_response *response, const uint16_t expected, 31 | netmd_error *error); 32 | void netmd_read_response_bulk(netmd_response *response, unsigned char* target, 33 | const size_t length, netmd_error *error); 34 | unsigned char *netmd_copy_word_to_buffer(unsigned char **buf, uint16_t value, int little_endian); 35 | unsigned char netmd_read(netmd_response *response); 36 | uint16_t netmd_read_word(netmd_response *response); 37 | uint32_t netmd_read_doubleword(netmd_response *response); 38 | -------------------------------------------------------------------------------- /libnetmd/log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * log.c 3 | * 4 | * This file is part of libnetmd, a library for accessing Sony NetMD devices. 5 | * 6 | * Copyright (C) 2004 Bertrik Sikken 7 | * Copyright (C) 2011 Alexander Sulfrian 8 | * 9 | * This library is free software; you can redistribute it and/or 10 | * modify it under the terms of the GNU Lesser General Public 11 | * License as published by the Free Software Foundation; either 12 | * version 2.1 of the License, or (at your option) any later version. 13 | * 14 | * This library is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 17 | * Lesser General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU Lesser General Public 20 | * License along with this library; if not, write to the Free Software 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 22 | * 23 | */ 24 | 25 | #include 26 | #include 27 | 28 | #include "log.h" 29 | 30 | static netmd_loglevel trace_level = 0; 31 | 32 | void netmd_set_log_level(netmd_loglevel level) 33 | { 34 | trace_level = level; 35 | } 36 | 37 | 38 | void netmd_log_hex(netmd_loglevel level, const unsigned char* const buf, const size_t len) 39 | { 40 | size_t i; 41 | size_t j = 0; 42 | int breakpoint = 0; 43 | 44 | if (level > trace_level) { 45 | return; 46 | } 47 | 48 | for (i = 0; i < len; i++) 49 | { 50 | printf("%02x ", buf[i] & 0xff); 51 | breakpoint++; 52 | if(!((i + 1)%16) && i) 53 | { 54 | printf("\t\t"); 55 | for(j = ((i+1) - 16); j < ((i+1)/16) * 16; j++) 56 | { 57 | if(buf[j] < 30) 58 | printf("."); 59 | else 60 | printf("%c", buf[j]); 61 | } 62 | printf("\n"); 63 | breakpoint = 0; 64 | } 65 | } 66 | 67 | if(breakpoint == 16) 68 | { 69 | printf("\n"); 70 | return; 71 | } 72 | 73 | for(; breakpoint < 16; breakpoint++) 74 | { 75 | printf(" "); 76 | } 77 | printf("\t\t"); 78 | 79 | for(j = len - (len%16); j < len; j++) 80 | { 81 | if(buf[j] < 30) 82 | printf("."); 83 | else 84 | printf("%c", buf[j]); 85 | } 86 | printf("\n"); 87 | } 88 | 89 | 90 | void netmd_log(netmd_loglevel level, const char* const fmt, ...) 91 | { 92 | va_list arg; 93 | 94 | if (level > trace_level) { 95 | return; 96 | } 97 | 98 | va_start(arg, fmt); 99 | vprintf(fmt, arg); 100 | va_end(arg); 101 | } 102 | -------------------------------------------------------------------------------- /libnetmd/log.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBNETMD_TRACE_H 2 | #define LIBNETMD_TRACE_H 3 | 4 | /** 5 | log level 6 | */ 7 | typedef enum { 8 | /** Not a log level. Should only be used to filter all log messages so 9 | that no messages are displayed */ 10 | NETMD_LOG_NONE, 11 | 12 | /** fatal error message */ 13 | NETMD_LOG_ERROR, 14 | 15 | /** warning messages */ 16 | NETMD_LOG_WARNING, 17 | 18 | /** debug messages */ 19 | NETMD_LOG_VERBOSE, 20 | 21 | /** messages to display */ 22 | NETMD_LOG_DEBUG, 23 | 24 | /** Not a log level. Should only be used to display all messages. Should 25 | be the level with the highest value. */ 26 | NETMD_LOG_ALL 27 | } netmd_loglevel; 28 | 29 | /** 30 | Sets the global log level. 31 | 32 | @param level The maximal log level. All messages with a higher log level are 33 | filtered out and will not be displayed. 34 | */ 35 | void netmd_set_log_level(netmd_loglevel level); 36 | 37 | /** 38 | Shows a hexdump of binary data. 39 | 40 | @param level Log level of this message. 41 | @param data Pointer to binary data to display. 42 | @param len Length of the data. 43 | */ 44 | void netmd_log_hex(netmd_loglevel level, const unsigned char* const data, const size_t len); 45 | 46 | /** 47 | Printf like log function. 48 | 49 | @param level Log level of this message. 50 | @param fmt printf-like format string 51 | */ 52 | void netmd_log(netmd_loglevel level, const char* const fmt, ...); 53 | 54 | #endif 55 | -------------------------------------------------------------------------------- /libnetmd/minidisc.usermap: -------------------------------------------------------------------------------- 1 | # usb module match_flags idVendor idProduct bcdDevice_lo bcdDevice_hi bDeviceClass bDeviceSubClass bDeviceProtocol bInterfaceClass bInterfaceSubClass bInterfaceProtocol driver_info 2 | # Aiwa AM-NX9 3 | minidisc 0x0003 0x054c 0x014c 4 | # Sony MZ-N1 5 | minidisc 0x0003 0x054c 0x0075 6 | # Sony LAM-1 7 | minidisc 0x0003 0x054c 0x0080 8 | # Sony MDS-JB980 9 | minidisc 0x0003 0x054c 0x0081 10 | # Sony MZ-N505 11 | minidisc 0x0003 0x054c 0x0084 12 | # Sony MZ-S1 13 | minidisc 0x0003 0x054c 0x0085 14 | # Sony MZ-N707 15 | minidisc 0x0003 0x054c 0x0086 16 | # Sony MZ-N10 17 | minidisc 0x0003 0x054c 0x00c6 18 | # Sony MZ-N910 19 | minidisc 0x0003 0x054c 0x00c7 20 | # Sony MZ-N710/N810 21 | minidisc 0x0003 0x054c 0x00c8 22 | # Sony MZ-N510/N610 23 | minidisc 0x0003 0x054c 0x00c9 24 | # Sony MZ-NE410 25 | minidisc 0x0003 0x054c 0x00ca 26 | # Sony MZ-NE910 27 | minidisc 0x0003 0x054c 0x00eb 28 | # Sony LAM-10 29 | minidisc 0x0003 0x054c 0x0101 30 | # Sharp IM-DR80 31 | minidisc 0x0003 0x04dd 0x9014 32 | -------------------------------------------------------------------------------- /libnetmd/netmd_dev.c: -------------------------------------------------------------------------------- 1 | /* netmd_dev.c 2 | * Copyright (C) 2004, Bertrik Sikken 3 | * Copyright (C) 2011, Adrian Glaubitz 4 | * 5 | * This file is part of libnetmd. 6 | * 7 | * libnetmd is free software; you can redistribute it and/or modify 8 | * it under the terms of the GNU General Public License as published by 9 | * the Free Software Foundation; either version 2 of the License, or 10 | * (at your option) any later version. 11 | * 12 | * Libnetmd is distributed in the hope that it will be useful, 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | * GNU General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 20 | */ 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | #include "netmd_dev.h" 28 | #include "log.h" 29 | #include "const.h" 30 | 31 | static libusb_context *ctx = NULL; 32 | 33 | /*! list of known vendor/prod id's for NetMD devices */ 34 | static struct netmd_devices const known_devices[] = 35 | { 36 | {0x54c, 0x34}, /* Sony PCLK-XX */ 37 | {0x54c, 0x36}, /* Sony (unknown model) */ 38 | {0x54c, 0x75}, /* Sony MZ-N1 */ 39 | {0x54c, 0x7c}, /* Sony (unknown model) */ 40 | {0x54c, 0x80}, /* Sony LAM-1 */ 41 | {0x54c, 0x81}, /* Sony MDS-JE780/JB980 */ 42 | {0x54c, 0x84}, /* Sony MZ-N505 */ 43 | {0x54c, 0x85}, /* Sony MZ-S1 */ 44 | {0x54c, 0x86}, /* Sony MZ-N707 */ 45 | {0x54c, 0x8e}, /* Sony CMT-C7NT */ 46 | {0x54c, 0x97}, /* Sony PCGA-MDN1 */ 47 | {0x54c, 0xad}, /* Sony CMT-L7HD */ 48 | {0x54c, 0xc6}, /* Sony MZ-N10 */ 49 | {0x54c, 0xc7}, /* Sony MZ-N910 */ 50 | {0x54c, 0xc8}, /* Sony MZ-N710/NE810/NF810 */ 51 | {0x54c, 0xc9}, /* Sony MZ-N510/NF610 */ 52 | {0x54c, 0xca}, /* Sony MZ-NE410/DN430/NF520 */ 53 | {0x54c, 0xeb}, /* Sony MZ-NE810/NE910 */ 54 | {0x54c, 0xe7}, /* Sony CMT-M333NT/M373NT */ 55 | {0x54c, 0x101}, /* Sony LAM-10 */ 56 | {0x54c, 0x113}, /* Aiwa AM-NX1 */ 57 | {0x54c, 0x14c}, /* Aiwa AM-NX9 */ 58 | {0x54c, 0x17e}, /* Sony MZ-NH1 */ 59 | {0x54c, 0x180}, /* Sony MZ-NH3D */ 60 | {0x54c, 0x182}, /* Sony MZ-NH900 */ 61 | {0x54c, 0x184}, /* Sony MZ-NH700/800 */ 62 | {0x54c, 0x186}, /* Sony MZ-NH600/600D */ 63 | {0x54c, 0x188}, /* Sony MZ-N920 */ 64 | {0x54c, 0x18a}, /* Sony LAM-3 */ 65 | {0x54c, 0x1e9}, /* Sony MZ-DH10P */ 66 | {0x54c, 0x219}, /* Sony MZ-RH10 */ 67 | {0x54c, 0x21b}, /* Sony MZ-RH910/M10 */ 68 | {0x54c, 0x21d}, /* Sony CMT-AH10 */ 69 | {0x54c, 0x22c}, /* Sony CMT-AH10 */ 70 | {0x54c, 0x23c}, /* Sony DS-HMD1 */ 71 | {0x54c, 0x286}, /* Sony MZ-RH1 */ 72 | 73 | {0x4dd, 0x7202}, /* Sharp IM-MT880H/MT899H */ 74 | {0x4dd, 0x9013}, /* Sharp IM-DR400/DR410 */ 75 | {0x4dd, 0x9014}, /* Sharp IM-DR80/DR420/DR580 and Kenwood DMC-S9NET */ 76 | 77 | {0, 0} /* terminating pair */ 78 | }; 79 | 80 | 81 | netmd_error netmd_init(netmd_device **device_list, libusb_context *hctx) 82 | { 83 | int count = 0; 84 | ssize_t usb_device_count; 85 | ssize_t i = 0; 86 | netmd_device *new_device; 87 | libusb_device **list; 88 | struct libusb_device_descriptor desc; 89 | 90 | /* skip device enumeration when using libusb hotplug feature 91 | * use libusb_context of running libusb instance from hotplug initialisation */ 92 | if(hctx) { 93 | ctx = hctx; 94 | return NETMD_USE_HOTPLUG; 95 | } 96 | 97 | libusb_init(&ctx); 98 | 99 | *device_list = NULL; 100 | 101 | usb_device_count = libusb_get_device_list(ctx, &list); 102 | 103 | for (i = 0; i < usb_device_count; i++) { 104 | libusb_get_device_descriptor(list[i], &desc); 105 | 106 | for (count = 0; known_devices[count].idVendor != 0 && known_devices[count].idProduct != 0; count++) { 107 | if(desc.idVendor == known_devices[count].idVendor && 108 | desc.idProduct == known_devices[count].idProduct) { 109 | new_device = malloc(sizeof(netmd_device)); 110 | new_device->usb_dev = list[i]; 111 | new_device->link = *device_list; 112 | *device_list = new_device; 113 | } 114 | } 115 | } 116 | 117 | return NETMD_NO_ERROR; 118 | } 119 | 120 | 121 | netmd_error netmd_open(netmd_device *dev, netmd_dev_handle **dev_handle) 122 | { 123 | int result; 124 | libusb_device_handle *dh = NULL; 125 | 126 | result = libusb_open(dev->usb_dev, &dh); 127 | if (result == 0) 128 | result = libusb_claim_interface(dh, 0); 129 | 130 | if (result == 0) { 131 | *dev_handle = (netmd_dev_handle*)dh; 132 | return NETMD_NO_ERROR; 133 | } 134 | else { 135 | *dev_handle = NULL; 136 | return NETMD_USB_OPEN_ERROR; 137 | } 138 | } 139 | 140 | netmd_error netmd_get_devname(netmd_dev_handle* devh, char *buf, size_t buffsize) 141 | { 142 | int result; 143 | 144 | result = libusb_get_string_descriptor_ascii((libusb_device_handle *)devh, 2, (unsigned char *)buf, buffsize); 145 | if (result < 0) { 146 | netmd_log(NETMD_LOG_ERROR, "libusb_get_string_descriptor_asci failed, %s (%d)\n", strerror(errno), errno); 147 | buf[0] = 0; 148 | return NETMD_USB_ERROR; 149 | } 150 | 151 | return NETMD_NO_ERROR; 152 | } 153 | 154 | netmd_error netmd_close(netmd_dev_handle* devh) 155 | { 156 | int result; 157 | libusb_device_handle *dev; 158 | 159 | dev = (libusb_device_handle *)devh; 160 | result = libusb_release_interface(dev, 0); 161 | if (result == 0) 162 | libusb_close(dev); 163 | else{ 164 | return NETMD_USB_ERROR; 165 | } 166 | 167 | return NETMD_NO_ERROR; 168 | } 169 | 170 | 171 | void netmd_clean(netmd_device **device_list) 172 | { 173 | netmd_device *tmp, *device; 174 | 175 | device = *device_list; 176 | while (device != NULL) { 177 | tmp = device->link; 178 | free(device); 179 | device = tmp; 180 | } 181 | 182 | *device_list = NULL; 183 | 184 | libusb_exit(ctx); 185 | } 186 | -------------------------------------------------------------------------------- /libnetmd/netmd_dev.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBNETMD_DEV_H 2 | #define LIBNETMD_DEV_H 3 | 4 | #include "error.h" 5 | #include "common.h" 6 | 7 | typedef struct netmd_device { 8 | struct netmd_device *link; 9 | char name[32]; 10 | struct libusb_device *usb_dev; 11 | } netmd_device; 12 | 13 | /** 14 | Struct to hold the vendor and product id's for each unit. 15 | */ 16 | struct netmd_devices { 17 | int idVendor; 18 | int idProduct; 19 | }; 20 | 21 | /** 22 | Intialises the netmd device layer, scans the USB and fills in a list of 23 | supported devices. 24 | 25 | @param device_list Linked list of netmd_device_t structures to fill. 26 | @param libusb_context of a running instance of libusb 27 | */ 28 | netmd_error netmd_init(netmd_device **device_list, libusb_context * hctx); 29 | 30 | /** 31 | Opens a NetMD device. 32 | 33 | @param dev Pointer to a device discoverd by netmd_init. 34 | @param dev_handle Pointer to variable to save the handle of the opened 35 | device used for communication in all other netmd_ 36 | functions. 37 | */ 38 | netmd_error netmd_open(netmd_device *dev, netmd_dev_handle **dev_handle); 39 | 40 | /** 41 | Get the device name stored in USB device. 42 | 43 | @param devh Pointer to device, returned by netmd_open. 44 | @param buf Buffer to hold the name. 45 | @param buffsize Available size in buf. 46 | */ 47 | netmd_error netmd_get_devname(netmd_dev_handle* devh, char *buf, size_t buffsize); 48 | 49 | /** 50 | Closes the usb descriptors. 51 | 52 | @param dev Pointer to device returned by netmd_open. 53 | */ 54 | netmd_error netmd_close(netmd_dev_handle* dev); 55 | 56 | /** 57 | Cleans structures created by netmd_init. 58 | 59 | @param device_list List of devices filled by netmd_init. 60 | */ 61 | void netmd_clean(netmd_device **device_list); 62 | 63 | 64 | #endif 65 | -------------------------------------------------------------------------------- /libnetmd/omgutils-patch.txt: -------------------------------------------------------------------------------- 1 | #info omgutils.dll patch anti debugging code (patch32 program). 2 | 3 | #seek 0x0ec31 4 | #chek 0xcc 5 | #repl 0x90 6 | 7 | #seek 0x0ec32 8 | #chek 0xc6 0x05 0xfc 0x66 0x01 0x10 0x01 9 | #repl 0xc6 0x05 0xfc 0x66 0x01 0x10 0x00 10 | 11 | -------------------------------------------------------------------------------- /libnetmd/playercontrol.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBNETMD_PLAYERCONTROL_H 2 | #define LIBNETMD_PLAYERCONTROL_H 3 | 4 | #include 5 | #include "common.h" 6 | #include "error.h" 7 | 8 | typedef struct { 9 | uint16_t hour; 10 | uint8_t minute; 11 | uint8_t second; 12 | uint8_t frame; 13 | } netmd_time; 14 | 15 | /** 16 | Structure to hold the capacity information of a disc. 17 | */ 18 | typedef struct { 19 | /** Time allready recorded on the disc. */ 20 | netmd_time recorded; 21 | 22 | /** Total time, that could be recorded on the disc. This depends on the 23 | current recording settings. */ 24 | netmd_time total; 25 | 26 | /** Time that is available on the disc. This depends on the current 27 | recording settings. */ 28 | netmd_time available; 29 | } netmd_disc_capacity; 30 | 31 | /** 32 | Starts playing the current track. If no track is selected, starts playing the 33 | first track. 34 | 35 | @param dev Handle to the open minidisc player. 36 | */ 37 | netmd_error netmd_play(netmd_dev_handle* dev); 38 | 39 | /** 40 | Pause playing. If uses netmd_play afterwards the player continues at the 41 | current position. 42 | 43 | @param dev Handle to the open minidisc player. 44 | */ 45 | netmd_error netmd_pause(netmd_dev_handle* dev); 46 | 47 | /** 48 | Spin the track fast forward. 49 | 50 | @param dev Handle to the open minidisc player. 51 | */ 52 | netmd_error netmd_fast_forward(netmd_dev_handle* dev); 53 | 54 | /** 55 | Spin the track backwards in time (aka rewind it). 56 | 57 | @param dev Handle to the open minidisc player. 58 | */ 59 | netmd_error netmd_rewind(netmd_dev_handle* dev); 60 | 61 | /** 62 | Stop playing. The current position is discarded. 63 | 64 | @param dev Handle to the open minidisc player. 65 | */ 66 | netmd_error netmd_stop(netmd_dev_handle* dev); 67 | 68 | /** 69 | Set the playmode. 70 | 71 | @param dev Handle to the open minidisc player. 72 | @param playmode Playmode to set. Could be a OR'ed combination of the 73 | corresponding defines from const.h. 74 | @see NETMD_PLAYMODE_SINGLE 75 | @see NETMD_PLAYMODE_REPEAT 76 | @see NETMD_PLAYMODE_SHUFFLE 77 | 78 | */ 79 | netmd_error netmd_set_playmode(netmd_dev_handle* dev, const uint16_t playmode); 80 | 81 | /** 82 | Jump to the given track. 83 | 84 | @param dev Handle to the open minidisc player. 85 | @param track Number of the track to jump to. 86 | */ 87 | netmd_error netmd_set_track(netmd_dev_handle* dev, const uint16_t track); 88 | 89 | /** 90 | Jump to the next track. If you currently playing the last track, nothing 91 | happens. 92 | 93 | @param dev Handle to the open minidisc player. 94 | */ 95 | netmd_error netmd_track_next(netmd_dev_handle* dev); 96 | 97 | /** 98 | Jump to the previous track. If you currently playing the first track, nothing 99 | happens. 100 | 101 | @param dev Handle to the open minidisc player. 102 | */ 103 | netmd_error netmd_track_previous(netmd_dev_handle* dev); 104 | 105 | /** 106 | Jump to the beginning of the current track. 107 | 108 | @param dev Handle to the open minidisc player. 109 | */ 110 | netmd_error netmd_track_restart(netmd_dev_handle* dev); 111 | 112 | /** 113 | Jump to a specific time of the given track. 114 | 115 | @param dev Handle to the open minidisc player. 116 | @param track Track, where to jump to the given time. 117 | @param time Time to jump to. 118 | */ 119 | netmd_error netmd_set_time(netmd_dev_handle* dev, const uint16_t track, 120 | const netmd_time* time); 121 | 122 | /** 123 | Gets the currently playing track. 124 | 125 | @param dev Handle to the open minidisc player. 126 | @param track Pointer where to save the current track. 127 | */ 128 | netmd_error netmd_get_track(netmd_dev_handle* dev, uint16_t *track); 129 | 130 | /** 131 | Gets the position within the currently playing track 132 | 133 | @param dev Handle to the open minidisc player. 134 | @param time Pointer to save the current time to. 135 | */ 136 | netmd_error netmd_get_position(netmd_dev_handle* dev, netmd_time* time); 137 | 138 | /** 139 | Gets the used, total and available disc capacity (total and available 140 | capacity depend on current recording settings) 141 | 142 | @param dev Handle to the open minidisc player. 143 | @param capacity Pointer to a netmd_disc_capacity structure to save the 144 | capacity information of the current minidisc to. 145 | */ 146 | netmd_error netmd_get_disc_capacity(netmd_dev_handle* dev, 147 | netmd_disc_capacity* capacity); 148 | 149 | #endif 150 | -------------------------------------------------------------------------------- /libnetmd/trackinformation.c: -------------------------------------------------------------------------------- 1 | /* 2 | * trackinformation.c 3 | * 4 | * This file is part of libnetmd, a library for accessing Sony NetMD devices. 5 | * 6 | * Copyright (C) 2011 Alexander Sulfrian 7 | * 8 | * This library is free software; you can redistribute it and/or 9 | * modify it under the terms of the GNU Lesser General Public 10 | * License as published by the Free Software Foundation; either 11 | * version 2.1 of the License, or (at your option) any later version. 12 | * 13 | * This library is distributed in the hope that it will be useful, 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 | * Lesser General Public License for more details. 17 | * 18 | * You should have received a copy of the GNU Lesser General Public 19 | * License along with this library; if not, write to the Free Software 20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 21 | * 22 | */ 23 | 24 | #include 25 | #include 26 | 27 | #include "trackinformation.h" 28 | #include "utils.h" 29 | #include "log.h" 30 | 31 | void netmd_get_track_information(netmd_dev_handle *dev, uint16_t track, 32 | uint16_t p1, uint16_t p2, 33 | unsigned char *data, size_t data_length) 34 | { 35 | unsigned char cmd[] = { 0x00, 0x18, 0x06, 0x02, 0x20, 0x10, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 36 | 0xff, 0x00, 0x00, 0x00, 0x00, 0x00 }; 37 | unsigned char rsp[255]; 38 | unsigned char *buf; 39 | int length; 40 | uint16_t real_data_length; 41 | size_t size; 42 | 43 | buf = cmd + 7; 44 | netmd_copy_word_to_buffer(&buf, track, 0); 45 | netmd_copy_word_to_buffer(&buf, p1, 0); 46 | netmd_copy_word_to_buffer(&buf, p2, 0); 47 | 48 | length = netmd_exch_message(dev, cmd, sizeof(cmd), rsp); 49 | if (length > 0) { 50 | uint32_t tmp = (unsigned int)data[19] << 8; 51 | real_data_length = (tmp + data[20]) & 0xffffU; 52 | if (real_data_length > data_length) { 53 | size = data_length; 54 | } 55 | else { 56 | size = real_data_length; 57 | } 58 | 59 | memcpy(data, rsp + 21, size); 60 | } 61 | } 62 | 63 | int netmd_request_track_bitrate(netmd_dev_handle*dev, const uint16_t track, 64 | unsigned char* encoding, unsigned char *channel) 65 | { 66 | unsigned char info[8] = { 0 }; 67 | 68 | netmd_get_track_information(dev, track, 0x3080, 0x0700, info, sizeof(info)); 69 | memcpy(encoding, info + 6, 1); 70 | memcpy(channel, info + 7, 1); 71 | return 2; 72 | } 73 | 74 | int netmd_request_track_flags(netmd_dev_handle*dev, const uint16_t track, unsigned char* data) 75 | { 76 | int ret = 0; 77 | unsigned char request[] = {0x00, 0x18, 0x06, 0x01, 0x20, 0x10, 78 | 0x01, 0x00, 0x00, 0xff, 0x00, 0x00, 79 | 0x01, 0x00, 0x08}; 80 | 81 | unsigned char *buf; 82 | unsigned char reply[255]; 83 | 84 | buf = request + 7; 85 | netmd_copy_word_to_buffer(&buf, track, 0); 86 | ret = netmd_exch_message(dev, request, sizeof(request), reply); 87 | *data = reply[ret - 1]; 88 | return ret; 89 | } 90 | 91 | int netmd_request_title(netmd_dev_handle* dev, const uint16_t track, char* buffer, const size_t size) 92 | { 93 | int ret = -1; 94 | size_t title_size = 0; 95 | unsigned char title_request[] = {0x00, 0x18, 0x06, 0x02, 0x20, 0x18, 96 | 0x02, 0x00, 0x00, 0x30, 0x00, 0xa, 97 | 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 98 | 0x00}; 99 | unsigned char title[255]; 100 | unsigned char *buf; 101 | 102 | buf = title_request + 7; 103 | netmd_copy_word_to_buffer(&buf, track, 0); 104 | ret = netmd_exch_message(dev, title_request, 0x13, title); 105 | if(ret < 0) 106 | { 107 | fprintf(stderr, "bad ret code, returning early\n"); 108 | return -1; 109 | } 110 | 111 | title_size = (size_t)ret; 112 | 113 | if(title_size == 0 || title_size == 0x13) 114 | return -1; /* bail early somethings wrong or no track */ 115 | 116 | int title_response_header_size = 25; 117 | const char *title_text = title + title_response_header_size; 118 | size_t required_size = title_size - title_response_header_size; 119 | 120 | if (required_size > size - 1) 121 | { 122 | printf("netmd_request_title: title too large for buffer\n"); 123 | return -1; 124 | } 125 | 126 | memset(buffer, 0, size); 127 | memcpy(buffer, title_text, required_size); 128 | 129 | return required_size; 130 | } 131 | -------------------------------------------------------------------------------- /libnetmd/trackinformation.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBNETMD_TRACKINFORMATION_H 2 | #define LIBNETMD_TRACKINFORMATION_H 3 | 4 | #include 5 | 6 | #include "common.h" 7 | 8 | /** 9 | Get the bitrate used to encode a specific track. 10 | 11 | @param dev pointer to device returned by netmd_open 12 | @param track Zero based index of track your requesting. 13 | @param data pointer to store the hex code representing the bitrate. 14 | */ 15 | int netmd_request_track_bitrate(netmd_dev_handle*dev, const uint16_t track, 16 | unsigned char* encoding, unsigned char* channel); 17 | 18 | /** 19 | Get the flags used for a specific track. 20 | 21 | @param dev pointer to device returned by netmd_open 22 | @param track Zero based index of track your requesting. 23 | @param data pointer to store the hex code representing the codec. 24 | */ 25 | int netmd_request_track_flags(netmd_dev_handle* dev, const uint16_t track, unsigned char* data); 26 | 27 | /** 28 | Get the title for a specific track. 29 | 30 | @param dev pointer to device returned by netmd_open 31 | @param track Zero based index of track your requesting. 32 | @param buffer buffer to hold the name. 33 | @param size of buf. 34 | @return Actual size of buffer, if your buffer is too small resize buffer and 35 | recall function. 36 | */ 37 | int netmd_request_title(netmd_dev_handle* dev, const uint16_t track, char* buffer, const size_t size); 38 | 39 | #endif 40 | -------------------------------------------------------------------------------- /libnetmd/use_libnetmd.prl: -------------------------------------------------------------------------------- 1 | # the QMAKE_LIBDIR thing is a workaround for a bug in qmake on mingw: 2 | # it searches prl files for library dependencies only QMAKE_LIBDIR and 3 | # ignores "-L" parametes in LIBS. 4 | 5 | build_pass:CONFIG(debug,debug|release) { 6 | QMAKE_LIBDIR += ../libnetmd/debug 7 | LIBS += -L../libnetmd/debug 8 | } 9 | build_pass:CONFIG(release,debug|release) { 10 | QMAKE_LIBDIR += ../libnetmd/release 11 | LIBS += -L../libnetmd/release 12 | } 13 | 14 | # fallback if libnetmd was not compiled with 15 | # CONFIG += debug_and_release debug_and_release_target 16 | # while I force debug_and_release_target, it is ignored in a 17 | # just-one-kind build without debug_and_release 18 | 19 | QMAKE_LIBDIR += ../libnetmd 20 | LIBS += -L../libnetmd 21 | 22 | INCLUDEPATH += ../libnetmd 23 | LIBS += -lnetmd 24 | -------------------------------------------------------------------------------- /libnetmd/utilities/char-to-hex.c: -------------------------------------------------------------------------------- 1 | /* char-to-hex.c 2 | * Copyright (C) 2002, 2003 Marc Britten 3 | * 4 | * This file is part of libnetmd. 5 | * 6 | * libnetmd is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Libnetmd is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | 21 | #include 22 | 23 | int main(int argc, char* argv[]) 24 | { 25 | int i = 0; 26 | int j = 0; 27 | int iLen = 0; 28 | 29 | if(argc < 2) 30 | return 0; 31 | 32 | 33 | for(j = 1; j < argc; j++) 34 | { 35 | iLen = strlen(argv[j]); 36 | for(i = 0; i < iLen; i++) 37 | { 38 | printf(" %c ", argv[j][i]); 39 | } 40 | 41 | printf("\n"); 42 | for(i = 0; i < iLen; i++) 43 | { 44 | printf("%02x ", argv[j][i]); 45 | } 46 | 47 | printf("\n"); 48 | } 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /libnetmd/utilities/cleanup.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | # This program takes in logs saved from DebugView.exe in windows and gets 4 | # rid of the line number and timestamp fields (tab seperated) 5 | sub trim 6 | { 7 | my @out = @_; 8 | for (@out) 9 | { 10 | s/^\s+//; 11 | s/\s+$//; 12 | } 13 | return wantarray ? @out : $out[0]; 14 | } 15 | 16 | foreach $MyFile (@ARGV) 17 | { 18 | $OutFile = $MyFile . ".clean"; 19 | print "$OutFile\n"; 20 | open(FILE, $MyFile); 21 | open(FILE2, ">$OutFile"); 22 | while () 23 | { 24 | ($junk, $junk2, $data) = split(/\t/, $_, 3); 25 | print FILE2 "$data"; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /libnetmd/utilities/diff.txt: -------------------------------------------------------------------------------- 1 | Index: logparse.pl 2 | =================================================================== 3 | RCS file: /var/cvs/libnetmd/utilities/logparse.pl,v 4 | retrieving revision 1.1 5 | diff -u -r1.1 logparse.pl 6 | --- logparse.pl 15 May 2002 21:37:14 -0000 1.1 7 | +++ logparse.pl 17 May 2002 16:13:57 -0000 8 | @@ -10,8 +10,9 @@ 9 | my $PeekFlag = 0; # Lookahead flag (ugh!) 10 | my $UrbTime = 0; # Time elapsed when this URB was sent 11 | my $LastUrbTime = 0; # Time elapsed when previous URB was sent 12 | +my $FreeStyle = 0; # Allow lines with no obvious timestamp or line tag 13 | 14 | -my $LastVendor; # Last vendor request 15 | +my $LastVendor= ''; # Last vendor request 16 | 17 | my %UrbTypeMap = ( 18 | 'URB_FUNCTION_CONTROL_TRANSFER' => 'Control Transfer', 19 | @@ -36,10 +37,10 @@ 20 | # Main loop 21 | 22 | while( PeekLine() ) { 23 | - if( $Line =~ /^>>>>>>/ ) { 24 | + if( $Line =~ /^>>>/ ) { 25 | ParseOutgoing(); 26 | } 27 | - elsif( $Line =~ /^<<<<<>>>>>> URB (\d+) going down/ ) { 37 | + if( $Line =~ />> +URB (\d+) going down/ ) { 38 | $UrbId = $1; # Save the ID number 39 | # Read and parse the URB type 40 | ReadLine() or die "Read error\n"; 41 | - if( $Line =~ /^-- (\S+):/ ) { 42 | + if( $Line =~ /^-- ?(\S+):/ ) { 43 | $UrbType = $1; 44 | } 45 | else { 46 | @@ -88,11 +89,11 @@ 47 | 48 | # Read and parse the URB direction & number header 49 | ReadLine() or die "Read error\n"; 50 | - if( $Line =~ /<<<<<<< URB (\d+) coming back/ ) { 51 | + if( $Line =~ /<< +URB (\d+) coming back/ ) { 52 | $UrbId = $1; # Save the ID number 53 | # Read and parse the URB type 54 | ReadLine() or die "Read error\n"; 55 | - if( $Line =~ /^-- (\S+):/ ) { 56 | + if( $Line =~ /^-- ?(\S+):/ ) { 57 | $UrbType = $1; 58 | } 59 | else { 60 | @@ -114,7 +115,7 @@ 61 | 62 | while( PeekLine() ) { 63 | # Handle 'key = value' lines; 64 | - if( $Line =~ /^(.*\S)\s+=\s+(.*)/ ) { 65 | + if( $Line =~ /^(.*\S)\s*=\s+(.*)/ ) { 66 | my $key = $1; 67 | my $value = $2; 68 | $Params{$key} = $value; 69 | @@ -122,6 +123,9 @@ 70 | if( $value =~ /^[0-9a-f]+ \(/ ) { 71 | $value =~ s/ .*//; 72 | } 73 | + if( $value =~ /^00+/ ) { 74 | + $value =~ s/^00+/0/; 75 | + } 76 | $TerseParams{$key} = $value; 77 | } 78 | # Handle hex data (eg transfers) 79 | @@ -176,24 +180,24 @@ 80 | print "$UrbDir $UrbId $TypeName: "; 81 | 82 | if ( $UrbType eq 'URB_FUNCTION_CONTROL_TRANSFER' ) { 83 | - print "Buflen $TerseParams{'TransferBufferLength'} "; 84 | + print "Buflen=$TerseParams{'TransferBufferLength'} "; 85 | unless( $Quiet ) { 86 | - print "Flags $TerseParams{'TransferFlags'} "; 87 | - print "Pipe $TerseParams{'PipeHandle'} "; 88 | + print "Flags=$TerseParams{'TransferFlags'} "; 89 | + print "Pipe=$TerseParams{'PipeHandle'} "; 90 | } 91 | } elsif ( $UrbType eq 'URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE' ) { 92 | - print "Index $TerseParams{'Index'} "; 93 | - print "Type $TerseParams{'DescriptorType'} "; 94 | - print "Lang $TerseParams{'LanguageId'} "; 95 | + print "Index=$TerseParams{'Index'} "; 96 | + print "Type=$TerseParams{'DescriptorType'} "; 97 | + print "Lang=$TerseParams{'LanguageId'} "; 98 | } elsif ( $UrbType eq 'URB_FUNCTION_SELECT_CONFIGURATION' ) { 99 | # Nothing here yet :) 100 | } elsif ( $UrbType eq 'URB_FUNCTION_VENDOR_INTERFACE' ) { 101 | - print "Req $TerseParams{'Request'} "; 102 | + print "Req=$TerseParams{'Request'} "; 103 | unless( $Quiet ) { 104 | - print "Value $TerseParams{'Value'} "; 105 | - print "Index $TerseParams{'Index'} "; 106 | - print "Res Bits $TerseParams{'RequestTypeReservedBits'} "; 107 | - print "Pipe $TerseParams{'PipeHandle'} " if( $Params{'PipeHandle'}); 108 | + print "Value=$TerseParams{'Value'} "; 109 | + print "Index=$TerseParams{'Index'} "; 110 | + print "Res Bits=$TerseParams{'RequestTypeReservedBits'} "; 111 | + print "Pipe=$TerseParams{'PipeHandle'} " if( $Params{'PipeHandle'}); 112 | } 113 | } 114 | print "\n"; 115 | @@ -235,20 +239,52 @@ 116 | } 117 | while( <> ) { 118 | # split out the line number and time fields 119 | - if( /^(\d+)\s+([0-9.]+)\s+(.*)$/ ) { 120 | + if( /^(\d+)\s+([0-9.]+)\s+(.*)$/ ) { # "old" usbsnoopy format 121 | $LineNo = $1; 122 | $LineTime = $2; 123 | $Line = $3; 124 | - next unless $Line; # SKIP blank lines 125 | - next if( $Line =~ /^UsbSnoop/ ); # Skip UsbSnoop internal stuff 126 | - next if( $Line =~ /^\d+:\s+/ ); # Skip hexdump 'count' lines 127 | - $Line =~ s/\s+$//; # Trim trailing whitespace 128 | $Line =~ s/ : / = /g; # Convert for easier parsing later 129 | - return 1; 130 | + } 131 | + elsif( /^\[(\d+) ms\] (.*)$/ ) { # 'new' usbsnoop format 132 | + $LineTime = $1; 133 | + $Line = $2; 134 | + if( $LineNo ) { # Could line numbers ourself 135 | + $LineNo++; 136 | + } 137 | + else { 138 | + $LineNo = 1; # Count line number ourself 139 | + $FreeStyle = 1; # Allow 'freestyle' lines 140 | + } 141 | + } 142 | + elsif( $FreeStyle ) { 143 | + s/^\s*//; 144 | + s/^[0-9a-f]+: //; # Nasty hack to get rid of markers in hex data 145 | + $Line = $_; 146 | + if( $Line =~ /^SetupPacket/ ) { 147 | + # Even nastier hack for the way setup packets are dumped 148 | + my $t = <>; 149 | + if( $t ) { 150 | + $t =~ s/^\s*//; 151 | + $t =~ s/\s+$//; 152 | + $t =~ s/^[0-9a-f]+: //; 153 | + $Line = "$Line $t"; 154 | + } 155 | + } 156 | + $LineNo++; 157 | } 158 | else { 159 | die "Parse error!"; 160 | } 161 | + next unless $Line; # SKIP blank lines 162 | + $Line =~ s/^\s*//; # Trim leading whitespace 163 | + $Line =~ s/\s+$//; # Trim trailing whitespace 164 | + next if( $Line =~ /^UsbSnoop/ ); # Skip UsbSnoop internal stuff 165 | + next if( $Line =~ /^fido=/ ); 166 | + next if( $Line =~ /^fdo=/ ); 167 | + next if( $Line =~ /^pdx=/ ); 168 | + next if( $Line =~ /^\d+:\s*$/ ); # Skip hexdump 'count' lines 169 | + #print "$LineNo/$LineTime '$Line'\n"; 170 | + return 1; 171 | } 172 | $Line = undef; 173 | return undef; 174 | -------------------------------------------------------------------------------- /libnetmd/utilities/hex-to-char.c: -------------------------------------------------------------------------------- 1 | /* hex-to-char.c 2 | * Copyright (C) 2002, 2003 Marc Britten 3 | * 4 | * This file is part of libnetmd. 5 | * 6 | * libnetmd is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * Libnetmd is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License 17 | * along with this program; if not, write to the Free Software 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 19 | */ 20 | #include 21 | 22 | int main(int argc, char* argv[]) 23 | { 24 | int i = 0; 25 | int j = 0; 26 | int iLen = 0; 27 | int iData = 0; 28 | char hex[5]; 29 | 30 | if(argc < 2) 31 | return 0; 32 | 33 | for(j = 1; j < argc; j++) 34 | { 35 | sprintf(hex, "0x%s", argv[j]); 36 | iData = strtol(hex, NULL, 16); 37 | 38 | if(iData < 30) 39 | printf(". "); 40 | else 41 | printf("%c ", iData); 42 | } 43 | 44 | printf("\n"); 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /libnetmd/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef UTILS_H 2 | #define UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | #include "error.h" 8 | 9 | typedef struct { 10 | unsigned char content[255]; 11 | size_t length; 12 | size_t position; 13 | } netmd_response; 14 | 15 | #ifndef min 16 | #define min(a,b) ((a)<(b)?(a):(b)) 17 | #endif 18 | 19 | unsigned char proper_to_bcd_single(unsigned char value); 20 | unsigned char* proper_to_bcd(unsigned int value, unsigned char* target, size_t len); 21 | unsigned char bcd_to_proper_single(unsigned char value); 22 | unsigned int bcd_to_proper(unsigned char* value, size_t len); 23 | 24 | void netmd_check_response_bulk(netmd_response *response, const unsigned char* const expected, 25 | const size_t expected_length, netmd_error *error); 26 | 27 | void netmd_check_response_word(netmd_response *response, const uint16_t expected, 28 | netmd_error *error); 29 | 30 | void netmd_check_response(netmd_response *response, const unsigned char expected, 31 | netmd_error *error); 32 | 33 | void netmd_read_response_bulk(netmd_response *response, unsigned char* target, 34 | const size_t length, netmd_error *error); 35 | 36 | 37 | 38 | unsigned char *netmd_copy_word_to_buffer(unsigned char **buf, uint16_t value, int little_endian); 39 | unsigned char *netmd_copy_doubleword_to_buffer(unsigned char **buf, uint32_t value, int little_endian); 40 | unsigned char *netmd_copy_quadword_to_buffer(unsigned char **buf, uint64_t value); 41 | 42 | unsigned char netmd_read(netmd_response *response); 43 | uint16_t netmd_read_word(netmd_response *response); 44 | uint32_t netmd_read_doubleword(netmd_response *response); 45 | uint64_t netmd_read_quadword(netmd_response *response); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /md.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = subdirs 2 | 3 | SUBDIRS = libnetmd libhimd netmdcli himdcli 4 | 5 | netmdcli.depends = libnetmd 6 | himdcli.depends = libhimd 7 | 8 | !without_gui { 9 | SUBDIRS += qhimdtransfer 10 | qhimdtransfer.depends = libhimd libnetmd 11 | } 12 | -------------------------------------------------------------------------------- /netmd/.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc -------------------------------------------------------------------------------- /netmd/README: -------------------------------------------------------------------------------- 1 | libnetmd.py - A python implementation of NetMD protocol. 2 | 3 | DISCLAIMER 4 | In short: If it break, you get to keep the pieces. 5 | 6 | This library implements a proprietary, non-documented protocol. 7 | Some methods are not tested [enough], so they might just not work, or cause 8 | data loss, or brick your NetMD. Use at your own risk. 9 | 10 | REQUIREMENTS 11 | libusb1 12 | python2.4 or later (not compatible with python 3.x), ctypes (required by 13 | python-libusb1, included here) 14 | A NetMD minidisc player. 15 | An USB cable. 16 | 17 | Linux: 18 | Your distro should package everything you need (python2.4 + ctypes). 19 | 20 | Windows: 21 | As of this writing, Windows XP, 2003, Vista & later are supported by 22 | libusb-1.0, both in 32 and 64 bits. 23 | - Go here: 24 | http://code.google.com/p/libusb-winusb-wip/downloads/list 25 | and download: 26 | - latest libusb release (libusb_2010.10.14.7z as of this writing) 27 | - zadig.exe 28 | - Extract libusb-1.0.dll to your system32 folder (should be something like 29 | C:\windows\system32). 30 | - Plug your NetMD via USB 31 | - Run zadig.exe, and select your inidisc in the drop-down list, then click 32 | "install". You will be prompted for confirmation that you really want to 33 | install this non-certified driver, then installation will happen. 34 | If you get errors, it might mean a driver is already installed for this 35 | device, you should uninstall it and retry installing zadig's driver. 36 | - If prompted, reboot. 37 | - Run python NetMD tools (example: c:\Python26\python.exe lsmd.py) 38 | Note: wait for the driver to be loaded before running commands, otherwise 39 | you will get errors, like "LIBUSB_ERROR_NOT_SUPPORTED". 40 | 41 | Note: by default, python does not package the Crypto package, required to 42 | download track to NetMD devices. (TODO: add Crypto URL here.) 43 | 44 | For dump_md.py: 45 | sox (and plugins to access your audio system) 46 | A sound card with analog input. 47 | An audio cable. 48 | 49 | FILES 50 | Libraries: 51 | libnetmd.py Python implementation of NetMD protocol. 52 | libusb1.py Ctypes-based python wrapper around libusb1. 53 | usb1.py Object definitions for libusb1.py functions. 54 | 55 | Utils: 56 | lsusb.py Sample implementation of lsusb command using usb1.py. 57 | mdctl.py Stupid pdb-based command line to test libnetmd.py methods. 58 | lsmd.py Display disc title, tracks, ... of connected NetMD. 59 | dump_md.py Play tracks on a connected NetMD and record them to files. 60 | 61 | NOTES 62 | You need to be root to access a device on the USB bus (or at least, to have 63 | read/write permission on the /proc/bus/usb/*/* corresponding to your NetMD). 64 | 65 | dump_md.py contains some Works-For-Me values, it might require some tweaks 66 | for tracks to be properly recorded (depends on noise level, minidisk player 67 | reactivity...). 68 | 69 | -------------------------------------------------------------------------------- /netmd/TODO: -------------------------------------------------------------------------------- 1 | Write documentation (docstrings for python libraries, '-h' for utilities). 2 | Make libraries a valid, installable python package. 3 | Integration with udev (to remove the need to be root to access usb device). 4 | 5 | -------------------------------------------------------------------------------- /netmd/downloadhack.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import os 3 | import usb1 4 | import libnetmd 5 | from Crypto.Cipher import DES 6 | 7 | def main(bus=None, device_address=None): 8 | context = usb1.LibUSBContext() 9 | for md in libnetmd.iterdevices(context, bus=bus, 10 | device_address=device_address): 11 | md_iface = libnetmd.NetMDInterface(md) 12 | DownloadHack(md_iface) 13 | 14 | class EKBopensource: 15 | def getRootKey(self): 16 | return "\x12\x34\x56\x78\x9a\xbc\xde\xf0\x0f\xed\xcb\xa9\x87\x65\x43\x21" 17 | 18 | def getEKBID(self): 19 | return 0x26422642 20 | 21 | def getEKBDataForLeafId(self,leaf_id): 22 | return (["\x25\x45\x06\x4d\xea\xca\x14\xf9\x96\xbd\xc8\xa4\x06\xc2\x2b\x81", 23 | "\xfb\x60\xbd\xdd\x0d\xbc\xab\x84\x8a\x00\x5e\x03\x19\x4d\x3e\xda"], 9, \ 24 | "\x8f\x2b\xc3\x52\xe8\x6c\x5e\xd3\x06\xdc\xae\x18\xd2\xf3\x8c\x7f\x89\xb5\xe1\x85\x55\xa1\x05\xea") 25 | 26 | testframes=4644 27 | 28 | class MDTrack: 29 | def getTitle(self): 30 | return "HACK" 31 | 32 | def getFramecount(self): 33 | return testframes 34 | 35 | def getDataFormat(self): 36 | return libnetmd.WIREFORMAT_LP2 37 | 38 | def getContentID(self): 39 | # value probably doesn't matter 40 | return "\x01\x0F\x50\0\0\4\0\0\0" "\x48\xA2\x8D\x3E\x1A\x3B\x0C\x44\xAF\x2f\xa0" 41 | 42 | def getKEK(self): 43 | # value does not matter 44 | return "\x14\xe3\x83\x4e\xe2\xd3\xcc\xa5" 45 | 46 | def getPacketcount(self): 47 | return 1 48 | 49 | def getPackets(self): 50 | # values do not matter at all 51 | datakey = "\x96\x03\xc7\xc0\x53\x37\xd2\xf0" 52 | firstiv = "\x08\xd9\xcb\xd4\xc1\x5e\xc0\xff" 53 | keycrypter = DES.new(self.getKEK(), DES.MODE_ECB) 54 | key = keycrypter.encrypt(datakey) 55 | datacrypter = DES.new(key, DES.MODE_CBC, firstiv) 56 | # to be obtained from http://users.physik.fu-berlin.de/~mkarcher/ATRAC/LP2.wav 57 | file = open("/tmp/LP2.wav") 58 | file.read(60) 59 | data = file.read(testframes*192) 60 | return [(datakey,firstiv,datacrypter.encrypt(data))] 61 | 62 | def DownloadHack(md_iface): 63 | try: 64 | md_iface.sessionKeyForget() 65 | md_iface.leaveSecureSession() 66 | except: 67 | None 68 | try: 69 | md_iface.disableNewTrackProtection(1) 70 | except libnetmd.NetMDNotImplemented: 71 | print "Can't set device to non-protecting" 72 | trk = MDTrack() 73 | md_session = libnetmd.MDSession(md_iface, EKBopensource()) 74 | 75 | (track, uuid, ccid) = md_session.downloadtrack(trk) 76 | 77 | print 'Track:', track 78 | print "UUID:",''.join(["%02x"%ord(i) for i in uuid]) 79 | print "Confirmed Content ID:",''.join(["%02x"%ord(i) for i in ccid]) 80 | md_session.close() 81 | 82 | if __name__ == '__main__': 83 | from optparse import OptionParser 84 | parser = OptionParser() 85 | parser.add_option('-b', '--bus') 86 | parser.add_option('-d', '--device') 87 | (options, args) = parser.parse_args() 88 | assert len(args) < 2 89 | main(bus=options.bus, device_address=options.device) 90 | 91 | -------------------------------------------------------------------------------- /netmd/dump_md.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import os 3 | import usb1 4 | import libnetmd 5 | from time import sleep 6 | import platform 7 | import subprocess 8 | 9 | def main(bus=None, device_address=None, ext='ogg', track_range=None, title=None): 10 | context = usb1.LibUSBContext() 11 | for md in libnetmd.iterdevices(context, bus=bus, 12 | device_address=device_address): 13 | md_iface = libnetmd.NetMDInterface(md) 14 | try: 15 | MDDump(md_iface, ext, track_range, title) 16 | finally: 17 | md_iface.stop() 18 | 19 | def getTrackList(md_iface, track_range): 20 | result = [] 21 | append = result.append 22 | track_count = md_iface.getTrackCount() 23 | if isinstance(track_range, tuple): 24 | min_track, max_track = track_range 25 | if max_track is None: 26 | max_track = track_count - 1 27 | assert max_track < track_count 28 | assert min_track < track_count 29 | track_list = xrange(min_track, max_track + 1) 30 | elif isinstance(track_range, int): 31 | assert track_range < track_count 32 | track_list = [track_range] 33 | else: 34 | track_list = xrange(track_count) 35 | for track in track_list: 36 | hour, minute, second, sample = md_iface.getTrackLength(track) 37 | codec, channel_count = md_iface.getTrackEncoding(track) 38 | channel_count = libnetmd.CHANNEL_COUNT_DICT[channel_count] 39 | ascii_title = md_iface.getTrackTitle(track) 40 | wchar_title = md_iface.getTrackTitle(track, True).decode('shift_jis') 41 | title = wchar_title or ascii_title 42 | append((track, 43 | (hour, minute, second, sample), 44 | str(channel_count), 45 | title)) 46 | return result 47 | 48 | def MDDump(md_iface, ext, track_range, disk_title_override=None): 49 | if disk_title_override is None: 50 | ascii_title = md_iface.getDiscTitle() 51 | wchar_title = md_iface.getDiscTitle(True).decode('shift_jis') 52 | disc_title = wchar_title or ascii_title 53 | else: 54 | disc_title = disk_title_override 55 | if disc_title == '': 56 | directory = '.' 57 | else: 58 | directory = disc_title; 59 | print 'Storing in ', directory 60 | if not os.path.exists(directory): 61 | os.mkdir(directory) 62 | for track, (hour, minute, second, sample), channels, title in \ 63 | getTrackList(md_iface, track_range): 64 | 65 | duration = '%02i:%02i:%02i.%03i' % (hour, minute, second, sample/.512) 66 | filename = '%02i - %s.%s' % (track + 1, title, ext) 67 | print 'Recording', filename, '(', duration, ')' 68 | md_iface.gotoTrack(track) 69 | # Attemp to reduce the MD play delay by... 70 | print 'Waiting for MD...' 71 | # ...starting to play (some devices start their seek at this 72 | # time, others already at gotoTrack)... 73 | md_iface.play() 74 | # ... wait until playing really begins ... (waits until the second 75 | # second of audio playing) 76 | while md_iface.getPosition()[0:4] != [track, 0, 0, 1]: 77 | print md_iface.getPosition() 78 | sleep(0.25) 79 | # ... pause and go back to track beginning. 80 | md_iface.pause() 81 | md_iface.gotoTrack(track) 82 | if platform.system() == 'Windows': 83 | sox = 'sox.exe' 84 | else: 85 | sox = 'sox' 86 | start_sox = [sox, 87 | '-d', 88 | '-S', 89 | '-c', channels, 90 | '%s/%s' % (directory, filename), 91 | 'silence', '1', '0.1', '0.1%', 92 | 'trim', '0', duration, 93 | ] 94 | pid = subprocess.Popen(start_sox) 95 | md_iface.play() 96 | sleep(((hour * 60 + minute) * 60) + second) 97 | while md_iface.getPosition()[0] == track: 98 | sleep(1) 99 | md_iface.pause() 100 | print 'Done, waiting for sox to return...' 101 | pid.wait() 102 | # TODO: generate playlists based on groups defined on the MD 103 | print 'Finished.' 104 | 105 | if __name__ == '__main__': 106 | from optparse import OptionParser 107 | parser = OptionParser() 108 | parser.add_option('-b', '--bus') 109 | parser.add_option('-d', '--device') 110 | parser.add_option('-t', '--track-range') 111 | parser.add_option('-T', '--title') 112 | (options, args) = parser.parse_args() 113 | assert len(args) < 2 114 | if len(args) == 1: 115 | ext = args[0] 116 | else: 117 | ext = 'ogg' 118 | track_range = options.track_range 119 | if track_range is not None: 120 | if '-' in track_range: 121 | begin, end = track_range.split('-', 1) 122 | if begin == '': 123 | begin = 0 124 | else: 125 | begin = int(begin) - 1 126 | if end == '': 127 | end = None 128 | else: 129 | end = int(end) - 1 130 | assert begin < end 131 | track_range = (begin, end) 132 | else: 133 | track_range = int(track_range) - 1 134 | main(bus=options.bus, device_address=options.device, ext=ext, 135 | track_range=track_range, title=options.title) 136 | 137 | -------------------------------------------------------------------------------- /netmd/etc/20-netmd.fdi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | portable_audio_player 8 | 9 | netmd 10 | audio/vnd.sony.atrac3 11 | audio/vnd.sony.atrac3 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /netmd/etc/README: -------------------------------------------------------------------------------- 1 | This directory contains files that might help interoperation between your 2 | system and the netmd stuff. 3 | 4 | 20-netmd.fdi: 5 | Place to /usr/share/hal/fdi/information/20thirdparty/ to make the NetMD 6 | devices known as portable audio player. On recent distributions this will 7 | grant the user of the currently active session access to the device 8 | without being root. 9 | 10 | netmd.rules: 11 | Place this file into /etc/udev/rules.d to add udev rules which will grant 12 | user access to all known MiniDisc devices according to their USB device 13 | IDs. -------------------------------------------------------------------------------- /netmd/etc/netmd.rules: -------------------------------------------------------------------------------- 1 | ## Rules file for NetMD devices and HiMD devices in NetMD mode 2 | ## source: https://usb-ids.gowdy.us/read/UD/054c 3 | ## last changed: 2011-06-29 4 | 5 | ## HiMD 6 | 7 | # Sony MZ-NH1 8 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="017e", MODE="0664", GROUP="plugdev" 9 | 10 | # Sony MZ-NH3D 11 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0180", MODE="0664", GROUP="plugdev" 12 | 13 | # Sony MZ-NH900 14 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0182", MODE="0664", GROUP="plugdev" 15 | 16 | # Sony MZ-NH700/800 17 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0184", MODE="0664", GROUP="plugdev" 18 | 19 | # Sony MZ-NH600/600D 20 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0186", MODE="0664", GROUP="plugdev" 21 | 22 | # Sony MZ-DH10P 23 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="01e9", MODE="0664", GROUP="plugdev" 24 | 25 | # Sony MZ-RH10 26 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0219", MODE="0664", GROUP="plugdev" 27 | 28 | # Sony MZ-RH910 29 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="021b", MODE="0664", GROUP="plugdev" 30 | 31 | # Sony CMT-AH10 32 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="022c", MODE="0664", GROUP="plugdev" 33 | 34 | # Sony DS-HMD1 35 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="023c", MODE="0664", GROUP="plugdev" 36 | 37 | # Sony MZ-RH1 38 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0286", MODE="0664", GROUP="plugdev" 39 | 40 | 41 | ## NetMD 42 | 43 | # Aiwa AM-NX1 44 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0113", MODE="0664", GROUP="plugdev" 45 | 46 | # Aiwa AM-NX9 47 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="014c", MODE="0664", GROUP="plugdev" 48 | 49 | # Sharp IM-MT880H/MT899H 50 | ATTRS{idVendor}=="04dd", ATTRS{idProduct}=="7202", MODE="0664", GROUP="plugdev" 51 | 52 | # Sharp IM-DR400/DR410 53 | ATTRS{idVendor}=="04dd", ATTRS{idProduct}=="9013", MODE="0664", GROUP="plugdev" 54 | 55 | # Sharp IM-DR420/DR80/DR580 - Kenwood DMC-S9NET 56 | ATTRS{idVendor}=="04dd", ATTRS{idProduct}=="9014", MODE="0664", GROUP="plugdev" 57 | 58 | # Sony NetMD (unknown model) 59 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0036", MODE="0664", GROUP="plugdev" 60 | 61 | # Sony NetMD MZ-N1 62 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0075", MODE="0664", GROUP="plugdev" 63 | 64 | # Sony NetMD (unknown model) 65 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="007c", MODE="0664", GROUP="plugdev" 66 | 67 | # Sony NetMD LAM-1 68 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0080", MODE="0664", GROUP="plugdev" 69 | 70 | # Sony NetMD MDS-JE780/JB980 71 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0081", MODE="0664", GROUP="plugdev" 72 | 73 | # Sony MZ-N505 74 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0084", MODE="0664", GROUP="plugdev" 75 | 76 | # Sony NetMD MZ-S1 77 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0085", MODE="0664", GROUP="plugdev" 78 | 79 | # Sony NetMD MZ-N707 80 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0086", MODE="0664", GROUP="plugdev" 81 | 82 | # Sony MZ-N10 83 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00c6", MODE="0664", GROUP="plugdev" 84 | 85 | # Sony NetMD MZ-N910 86 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00c7", MODE="0664", GROUP="plugdev" 87 | 88 | # Sony NetMD MZ-N710/NF810/NE810 89 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00c8", MODE="0664", GROUP="plugdev" 90 | 91 | # Sony NetMD MZ-N510/NF610 92 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00c9", MODE="0664", GROUP="plugdev" 93 | 94 | # Sony MZ-N410/NF520D 95 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00ca", MODE="0664", GROUP="plugdev" 96 | 97 | # Sony NetMD MZ-NE810/NE910/DN430 98 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00eb", MODE="0664", GROUP="plugdev" 99 | 100 | # Sony NetMD LAM-10 101 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0101", MODE="0664", GROUP="plugdev" 102 | 103 | # Sony MZ-N920 104 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0188", MODE="0664", GROUP="plugdev" 105 | 106 | # Sony NetMD LAM-3 107 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="018a", MODE="0664", GROUP="plugdev" 108 | 109 | # Sony NetMD CMT-AH10 110 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="021d", MODE="0664", GROUP="plugdev" 111 | -------------------------------------------------------------------------------- /netmd/lsmd.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import usb1 3 | import libnetmd 4 | 5 | def main(bus=None, device_address=None, show_uuids=False): 6 | context = usb1.LibUSBContext() 7 | for md in libnetmd.iterdevices(context, bus=bus, 8 | device_address=device_address): 9 | listMD(md, show_uuids) 10 | 11 | def listMD(md, show_uuids): 12 | md_iface = libnetmd.NetMDInterface(md) 13 | 14 | codec_name_dict = { 15 | libnetmd.ENCODING_SP: 'sp', 16 | libnetmd.ENCODING_LP2: 'lp2', 17 | libnetmd.ENCODING_LP4: 'lp4', 18 | } 19 | channel_count_dict = { 20 | libnetmd.CHANNELS_MONO: 'mono', 21 | libnetmd.CHANNELS_STEREO: 'stereo', 22 | } 23 | flag_dict = { 24 | libnetmd.TRACK_FLAG_PROTECTED: 'protected', 25 | 0: 'unprotected', 26 | } 27 | def reprDiscFlags(flags): 28 | result = [] 29 | if flags & libnetmd.DISC_FLAG_WRITABLE: 30 | result.append('writable media') 31 | if flags & libnetmd.DISC_FLAG_WRITE_PROTECTED: 32 | result.append('write-protected') 33 | return result 34 | 35 | def timeToFrames(time_tuple): 36 | assert len(time_tuple) == 4 37 | return (((time_tuple[0] * 60) + time_tuple[1]) * 60 + time_tuple[2]) \ 38 | * 512 + time_tuple[3] 39 | 40 | flags = reprDiscFlags(md_iface.getDiscFlags()) 41 | print 'Disk (%s) %s %s' % ( 42 | ', '.join(flags), md_iface.getDiscTitle(), 43 | md_iface.getDiscTitle(True).decode('shift_jis_2004')) 44 | disc_used, disc_total, disc_left = md_iface.getDiscCapacity() 45 | disc_total = timeToFrames(disc_total) 46 | disc_left = timeToFrames(disc_left) 47 | print 'Time used: %02i:%02i:%02i+%03i (%.02f%%)' % ( 48 | disc_used[0], disc_used[1], disc_used[2], disc_used[3], 49 | (disc_total - disc_left) / float(disc_total) * 100) 50 | track_count = md_iface.getTrackCount() 51 | print '%i tracks' % (track_count, ) 52 | for group, (group_name, track_list) in enumerate( 53 | md_iface.getTrackGroupList()): 54 | if group_name is None: 55 | prefix = '' 56 | else: 57 | prefix = ' ' 58 | print 'Group %r' % (group_name or group + 1, ) 59 | for track, real_track in enumerate(track_list): 60 | hour, minute, second, sample = md_iface.getTrackLength(real_track) 61 | codec, channel_count = md_iface.getTrackEncoding(real_track) 62 | flags = md_iface.getTrackFlags(real_track) 63 | print '%s%03i: %02i:%02i:%02i+%03i %s %s %s %s %s' % (prefix, 64 | track, hour, minute, second, sample, codec_name_dict[codec], 65 | channel_count_dict[channel_count], flag_dict[flags], 66 | md_iface.getTrackTitle(real_track).decode('shift_jis_2004'), 67 | md_iface.getTrackTitle(real_track, True).decode('shift_jis_2004')) 68 | if show_uuids: 69 | uuid = md_iface.getTrackUUID(real_track) 70 | print '%s UUID:' % prefix, ''.join(["%02x"%ord(i) for i in uuid]) 71 | 72 | if __name__ == '__main__': 73 | from optparse import OptionParser 74 | parser = OptionParser() 75 | parser.add_option('-b', '--bus') 76 | parser.add_option('-d', '--device') 77 | parser.add_option('-u', '--uuids', action="store_true") 78 | (options, args) = parser.parse_args() 79 | assert len(args) == 0 80 | 81 | main(bus=options.bus, device_address=options.device, 82 | show_uuids=options.uuids) 83 | 84 | -------------------------------------------------------------------------------- /netmd/lsusb.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import usb1 3 | import sys 4 | 5 | def main(): 6 | verbose = False 7 | filter_set = set() 8 | 9 | for arg in sys.argv: 10 | if arg == '-v': 11 | verbose = True 12 | elif ':' in arg: 13 | vendor, product = arg.split(':') 14 | filter_set.add((int(vendor, 16), int(product, 16))) 15 | 16 | if len(filter_set): 17 | def test(device): 18 | return (device.getVendorID(), device.getProductID()) in filter_set 19 | else: 20 | def test(device): 21 | return True 22 | context = usb1.LibUSBContext() 23 | for device in context.getDeviceList(): 24 | if test(device): 25 | print device 26 | if verbose: 27 | print device.reprConfigurations() 28 | 29 | if __name__ == '__main__': 30 | main() 31 | 32 | -------------------------------------------------------------------------------- /netmd/mdctl.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import usb1 3 | import libnetmd 4 | 5 | def main(bus=None, device_address=None): 6 | context = usb1.LibUSBContext() 7 | for md in libnetmd.iterdevices(context, bus=bus, 8 | device_address=device_address): 9 | MDctl(md) 10 | 11 | def MDctl(md): 12 | md_iface = libnetmd.NetMDInterface(md) 13 | import pdb; 14 | pdb.set_trace() 15 | 16 | if __name__ == '__main__': 17 | from optparse import OptionParser 18 | parser = OptionParser() 19 | parser.add_option('-b', '--bus') 20 | parser.add_option('-d', '--device') 21 | (options, args) = parser.parse_args() 22 | assert len(args) == 0 23 | 24 | main(bus=options.bus, device_address=options.device) 25 | 26 | -------------------------------------------------------------------------------- /netmdcli/.gitignore: -------------------------------------------------------------------------------- 1 | Makefile 2 | Makefile.Release 3 | Makefile.Debug 4 | netmdcli 5 | debug 6 | release -------------------------------------------------------------------------------- /netmdcli/netmdcli.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | CONFIG -= qt app_bundle 3 | CONFIG += console link_pkgconfig link_prl 4 | SOURCES += netmdcli.c 5 | 6 | include(../libnetmd/use_libnetmd.prl) 7 | include(../build/libusb.pri) 8 | include(../build/installunix.pri) 9 | include(../build/common.pri) 10 | -------------------------------------------------------------------------------- /qhimdtransfer/.gitignore: -------------------------------------------------------------------------------- 1 | *.qm 2 | debug 3 | release 4 | Makefile* 5 | ui_*.h 6 | moc_*.cpp 7 | qrc_*.cpp 8 | qhimdtransfer 9 | -------------------------------------------------------------------------------- /qhimdtransfer/icons.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | icons/upload_from_md.png 4 | icons/add_group.png 5 | icons/connect.png 6 | icons/delete.png 7 | icons/download_to_md.png 8 | icons/format.png 9 | icons/help.png 10 | icons/qhimdtransfer.png 11 | icons/quit.png 12 | icons/rename.png 13 | icons/info.png 14 | icons/arrow_download.png 15 | icons/arrow_upload.png 16 | icons/qhimdtransfer_24.png 17 | 18 | 19 | -------------------------------------------------------------------------------- /qhimdtransfer/icons/add_group.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/add_group.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/arrow_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/arrow_download.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/arrow_upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/arrow_upload.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/connect.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/connect.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/delete.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/download_to_md.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/download_to_md.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/format.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/format.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/help.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/help.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/info.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer.ico -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer_128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer_128.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer_16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer_16.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer_24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer_24.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer_256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer_256.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer_32.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer_48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer_48.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer_512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer_512.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer_64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer_64.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/qhimdtransfer_96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/qhimdtransfer_96.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/quit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/quit.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/rename.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/rename.png -------------------------------------------------------------------------------- /qhimdtransfer/icons/upload_from_md.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/icons/upload_from_md.png -------------------------------------------------------------------------------- /qhimdtransfer/linux/etc/udev/60-minidisc.rules: -------------------------------------------------------------------------------- 1 | ## Rules file for Minidisc devices 2 | ## based on source: https://usb-ids.gowdy.us/read/UD/054c 3 | ## last changed: 2017-02-09 4 | 5 | # check himd devices 6 | # Sony MZ-NH1 7 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="017f", MODE="0664", GROUP="plugdev" 8 | # Sony MZ-NH3D 9 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0181", MODE="0664", GROUP="plugdev" 10 | # Sony MZ-NH900 11 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0183", MODE="0664", GROUP="plugdev" 12 | # Sony MZ-NH700 13 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0185", MODE="0664", GROUP="plugdev" 14 | # Sony MZ-NH600 15 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0187", MODE="0664", GROUP="plugdev" 16 | # Sony LAM-3 17 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="018a", MODE="0664", GROUP="plugdev" 18 | # Sony MZ-DH10P 19 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="01ea", MODE="0664", GROUP="plugdev" 20 | # Sony MZ-RH10 21 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="021a", MODE="0664", GROUP="plugdev" 22 | # Sony MZ-RH910 23 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="021c", MODE="0664", GROUP="plugdev" 24 | # Sony CMT-AH10 25 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="022d", MODE="0664", GROUP="plugdev" 26 | # Sony DS-HMD1 27 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="023d", MODE="0664", GROUP="plugdev" 28 | # Sony MZ-RH1 29 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0287", MODE="0664", GROUP="plugdev" 30 | 31 | # check himd devices in netmd mode 32 | # Sony MZ-NH1 33 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="017e", MODE="0664", GROUP="plugdev" 34 | # Sony MZ-NH3D 35 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0180", MODE="0664", GROUP="plugdev" 36 | # Sony MZ-NH900 37 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0182", MODE="0664", GROUP="plugdev" 38 | # Sony MZ-NH700/800 39 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0184", MODE="0664", GROUP="plugdev" 40 | # Sony MZ-NH600/600D 41 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0186", MODE="0664", GROUP="plugdev" 42 | # Sony MZ-DH10P 43 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="01e9", MODE="0664", GROUP="plugdev" 44 | # Sony MZ-RH10 45 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0219", MODE="0664", GROUP="plugdev" 46 | # Sony MZ-RH910 47 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="021b", MODE="0664", GROUP="plugdev" 48 | # Sony CMT-AH10 49 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="022c", MODE="0664", GROUP="plugdev" 50 | # Sony DS-HMD1 51 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="023c", MODE="0664", GROUP="plugdev" 52 | # Sony MZ-RH1 53 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0286", MODE="0664", GROUP="plugdev" 54 | 55 | # check netmd devices 56 | # Aiwa AM-NX1 57 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0113", MODE="0664", GROUP="plugdev" 58 | # Aiwa AM-NX9 59 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="014c", MODE="0664", GROUP="plugdev" 60 | # Sharp IM-MT880H/MT899H 61 | ATTRS{idVendor}=="04dd", ATTRS{idProduct}=="7202", MODE="0664", GROUP="plugdev" 62 | # Sharp IM-DR400/DR410 63 | ATTRS{idVendor}=="04dd", ATTRS{idProduct}=="9013", MODE="0664", GROUP="plugdev" 64 | # Sharp IM-DR420/DR80/DR580 - Kenwood DMC-S9NET 65 | ATTRS{idVendor}=="04dd", ATTRS{idProduct}=="9014", MODE="0664", GROUP="plugdev" 66 | # Sony NetMD (unknown model) 67 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0036", MODE="0664", GROUP="plugdev" 68 | # Sony NetMD MZ-N1 69 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0075", MODE="0664", GROUP="plugdev" 70 | # Sony NetMD (unknown model) 71 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="007c", MODE="0664", GROUP="plugdev" 72 | # Sony NetMD LAM-1 73 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0080", MODE="0664", GROUP="plugdev" 74 | # Sony NetMD MDS-JE780/JB980 75 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0081", MODE="0664", GROUP="plugdev" 76 | # Sony MZ-N505 77 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0084", MODE="0664", GROUP="plugdev" 78 | # Sony NetMD MZ-S1 79 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0085", MODE="0664", GROUP="plugdev" 80 | # Sony NetMD MZ-N707 81 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0086", MODE="0664", GROUP="plugdev" 82 | # Sony MZ-N10 83 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00c6", MODE="0664", GROUP="plugdev" 84 | # Sony NetMD MZ-N910 85 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00c7", MODE="0664", GROUP="plugdev" 86 | # Sony NetMD MZ-N710/NF810/NE810 87 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00c8", MODE="0664", GROUP="plugdev" 88 | # Sony NetMD MZ-N510/NF610 89 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00c9", MODE="0664", GROUP="plugdev" 90 | # Sony MZ-N410/NF520D 91 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00ca", MODE="0664", GROUP="plugdev" 92 | # Sony NetMD MZ-NE810/NE910/DN430 93 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="00eb", MODE="0664", GROUP="plugdev" 94 | # Sony NetMD LAM-10 95 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0101", MODE="0664", GROUP="plugdev" 96 | # Sony MZ-N920 97 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="0188", MODE="0664", GROUP="plugdev" 98 | # Sony NetMD LAM-3 99 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="018a", MODE="0664", GROUP="plugdev" 100 | # Sony NetMD CMT-AH10 101 | ATTRS{idVendor}=="054c", ATTRS{idProduct}=="021d", MODE="0664", GROUP="plugdev" 102 | -------------------------------------------------------------------------------- /qhimdtransfer/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "qhimdmainwindow.h" 5 | 6 | /* stolen from Qt Creator */ 7 | #ifdef Q_OS_MAC 8 | #define SHARE_FROM_BIN "/../Resources" 9 | #else 10 | #define SHARE_FROM_BIN "/../share/qhimdtransfer" 11 | #endif 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | int status; 16 | 17 | QApplication a(argc, argv); 18 | QTranslator trans; 19 | QString transfile = QString("qhimdtransfer_") + QLocale::system().name(); 20 | QString transdir = QCoreApplication::applicationDirPath() + 21 | QString(SHARE_FROM_BIN "/translations"); 22 | // try cwd, then standard translation directory 23 | trans.load(transfile) || trans.load(transfile, transdir); 24 | a.installTranslator(&trans); 25 | a.setOrganizationName("linux-minidisc"); 26 | a.setApplicationName("QHiMDTransfer"); 27 | 28 | QHiMDMainWindow w; 29 | w.show(); 30 | status = a.exec(); 31 | return status; 32 | } 33 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimdaboutdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "qhimdaboutdialog.h" 2 | #include "ui_qhimdaboutdialog.h" 3 | 4 | QHiMDAboutDialog::QHiMDAboutDialog(QWidget *parent) : 5 | QDialog(parent), 6 | m_ui(new Ui::QHiMDAboutDialog) 7 | { 8 | m_ui->setupUi(this); 9 | m_ui->VersionString->setText(VER); 10 | m_ui->BuildDateString->setText(BDATE); 11 | } 12 | 13 | QHiMDAboutDialog::~QHiMDAboutDialog() 14 | { 15 | delete m_ui; 16 | } 17 | 18 | void QHiMDAboutDialog::changeEvent(QEvent *e) 19 | { 20 | switch (e->type()) { 21 | case QEvent::LanguageChange: 22 | m_ui->retranslateUi(this); 23 | break; 24 | default: 25 | break; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimdaboutdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef QHIMDABOUTDIALOG_H 2 | #define QHIMDABOUTDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class QHiMDAboutDialog; 8 | } 9 | 10 | class QHiMDAboutDialog : public QDialog { 11 | Q_OBJECT 12 | Q_DISABLE_COPY(QHiMDAboutDialog) 13 | public: 14 | explicit QHiMDAboutDialog(QWidget *parent = 0); 15 | virtual ~QHiMDAboutDialog(); 16 | 17 | protected: 18 | virtual void changeEvent(QEvent *e); 19 | 20 | private: 21 | Ui::QHiMDAboutDialog *m_ui; 22 | }; 23 | 24 | #endif // QHIMDABOUTDIALOG_H 25 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimddetection.h: -------------------------------------------------------------------------------- 1 | #ifndef QHIMDDETECTION_H 2 | #define QHIMDDETECTION_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "libusb.h" 11 | 12 | // known vendor IDs 13 | #define SONY 0x054c 14 | #define SHARP 0x4dd 15 | 16 | // known himd-mode product IDs 17 | #define MZ_NH1_HIMD 0x017f 18 | #define MZ_NH3D_HIMD 0x0181 19 | #define MZ_NH900_HIMD 0x0183 20 | #define MZ_NH700_HIMD 0x0185 21 | #define MZ_NH600_HIMD 0x0187 22 | #define LAM_3_HIMD 0x018b 23 | #define MZ_DH10P_HIMD 0x01ea 24 | #define MZ_RH10_HIMD 0x021a 25 | #define MZ_RH910_HIMD 0x021c // or MZ-M10 26 | #define CMT_AH10_HIMD 0x022d 27 | #define DS_HMD1_HIMD 0x023d 28 | #define MZ_RH1_HIMD 0x0287 29 | 30 | // known Sony/Aiwa netmd-mode product IDs 31 | #define PCLK_XX 0x34 32 | #define UNKNOWN_A 0x36 33 | #define MZ_N1 0x75 34 | #define UNKNOWN_B 0x7c 35 | #define LAM_1 0x80 36 | #define MDS_JE780 0x81 // or MDS-JE980 37 | #define MZ_N505 0x84 38 | #define MZ_S1 0x85 39 | #define MZ_N707 0x86 40 | #define CMT_C7NT 0x8e 41 | #define PCGA_MDN1 0x97 42 | #define CMT_L7HD 0xad 43 | #define MZ_N10 0xc6 44 | #define MZ_N910 0xc7 45 | #define MZ_N710 0xc8 // or MZ-NE810/NF810 46 | #define MZ_N510 0xc9 // or MZ-NF610 47 | #define MZ_NE410 0xca // or MZ-DN430/NF520 48 | #define MZ_NE810 0xeb // or MZ-NE910 49 | #define CMT_M333NT 0xe7 // or CMT-M373NT 50 | #define LAM_10 0x101 51 | #define AIWA_AM_NX1 0x113 52 | #define AIWA_AM_NX9 0x14c 53 | #define MZ_NH1 0x17e 54 | #define MZ_NH3D 0x180 55 | #define MZ_NH900 0x182 56 | #define MZ_NH700 0x184 // or MZ-NH800 57 | #define MZ_NH600 0x186 // or MZ-NH600D 58 | #define MZ_N920 0x188 59 | #define LAM_3 0x18a 60 | #define MZ_DH10P 0x1e9 61 | #define MZ_RH10 0x219 62 | #define MZ_RH910 0x21b // or MZ-M10 63 | #define CMT_AH10_A 0x21d 64 | #define CMT_AH10_B 0x22c 65 | #define DS_HMD1 0x23c 66 | #define MZ_RH1 0x286 67 | 68 | // known Sharp netmd-mode product IDs 69 | #define IM_MT880H 0x7202 // or IM-MT899H 70 | #define IM_DR400 0x9013 // or IM-DR410 71 | #define IM_DR80 0x9014 // or IM-DR420/DR580 / Kenwood DMC-S9NET 72 | 73 | const char * identify_usb_device(int vid, int pid); 74 | 75 | typedef QList QMDDevicePtrList; 76 | 77 | // polling object for libusb hotplug events 78 | class QLibusbPoller : public QThread { 79 | Q_OBJECT 80 | Q_DISABLE_COPY(QLibusbPoller) 81 | 82 | protected: 83 | QTimer t; 84 | libusb_context *lct; 85 | virtual void run(); 86 | protected slots: 87 | void poll(); 88 | public: 89 | QLibusbPoller(QObject *parent = 0, libusb_context *ctx = 0); 90 | virtual ~QLibusbPoller(); 91 | void idle(); 92 | void continue_polling(); 93 | /* provide static sleep function */ 94 | static void sleep(unsigned long secs) {QThread::sleep(secs);} 95 | }; 96 | 97 | 98 | class QHiMDDetection : public QObject { 99 | Q_OBJECT 100 | Q_DISABLE_COPY(QHiMDDetection) 101 | 102 | protected: 103 | QMDDevicePtrList dlist; 104 | netmd_device * dev_list; 105 | libusb_hotplug_callback_handle cb_handle; 106 | QLibusbPoller * poller; 107 | libusb_context * ctx; 108 | public: 109 | explicit QHiMDDetection(QObject *parent = 0); 110 | virtual ~QHiMDDetection(); 111 | bool start_hotplug(); 112 | virtual void clearDeviceList(); 113 | void rescan_netmd_devices(); 114 | void scan_for_minidisc_devices(); 115 | virtual void scan_for_himd_devices() {} // platform dependent 116 | virtual void add_hotplug_device(libusb_device * dev); 117 | virtual void remove_hotplug_device(libusb_device * dev); 118 | void scan_for_netmd_devices(); 119 | QMDDevice *find_by_path(QString path); 120 | QMDDevice *find_by_name(QString name); 121 | QMDDevice *find_by_libusbDevice(libusb_device * dev); 122 | virtual QString mountpoint(QMDDevice *dev); 123 | private: 124 | virtual void add_himddevice(QString path, QString name, libusb_device * dev) {} 125 | virtual void remove_himddevice(QString path, libusb_device * dev = NULL); 126 | void add_netmddevice(libusb_device * dev, QString name); 127 | void remove_netmddevice(libusb_device * dev); 128 | 129 | signals: 130 | void deviceListChanged(QMDDevicePtrList list); 131 | }; 132 | 133 | QHiMDDetection * createDetection(QObject * parent = NULL); 134 | 135 | #endif // QHIMDDETECTION_H 136 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimddummydetection.cpp: -------------------------------------------------------------------------------- 1 | #include "qhimddetection.h" 2 | 3 | QHiMDDetection * createDetection(QObject * parent) 4 | { 5 | return new QHiMDDetection(parent); 6 | } 7 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimdformatdialog.cpp: -------------------------------------------------------------------------------- 1 | #include "qhimdformatdialog.h" 2 | #include "ui_qhimdformatdialog.h" 3 | 4 | QHiMDFormatDialog::QHiMDFormatDialog(QWidget *parent) : 5 | QDialog(parent), 6 | m_ui(new Ui::QHiMDFormatDialog) 7 | { 8 | m_ui->setupUi(this); 9 | } 10 | 11 | QHiMDFormatDialog::~QHiMDFormatDialog() 12 | { 13 | delete m_ui; 14 | } 15 | 16 | void QHiMDFormatDialog::changeEvent(QEvent *e) 17 | { 18 | switch (e->type()) { 19 | case QEvent::LanguageChange: 20 | m_ui->retranslateUi(this); 21 | break; 22 | default: 23 | break; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimdformatdialog.h: -------------------------------------------------------------------------------- 1 | #ifndef QHIMDFORMATDIALOG_H 2 | #define QHIMDFORMATDIALOG_H 3 | 4 | #include 5 | 6 | namespace Ui { 7 | class QHiMDFormatDialog; 8 | } 9 | 10 | class QHiMDFormatDialog : public QDialog { 11 | Q_OBJECT 12 | Q_DISABLE_COPY(QHiMDFormatDialog) 13 | public: 14 | explicit QHiMDFormatDialog(QWidget *parent = 0); 15 | virtual ~QHiMDFormatDialog(); 16 | 17 | protected: 18 | virtual void changeEvent(QEvent *e); 19 | 20 | private: 21 | Ui::QHiMDFormatDialog *m_ui; 22 | }; 23 | 24 | #endif // QHIMDFORMATDIALOG_H 25 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimdformatdialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | QHiMDFormatDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 397 10 | 189 11 | 12 | 13 | 14 | Format Medium 15 | 16 | 17 | 18 | 19 | 30 20 | 20 21 | 341 22 | 151 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | icons/format.png 35 | 36 | 37 | 38 | 39 | 40 | 41 | Really format MiniDisc (all audio-tracks and data will be lost) ? 42 | 43 | 44 | true 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | Qt::Horizontal 54 | 55 | 56 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | buttonBox 67 | accepted() 68 | QHiMDFormatDialog 69 | accept() 70 | 71 | 72 | 248 73 | 254 74 | 75 | 76 | 157 77 | 274 78 | 79 | 80 | 81 | 82 | buttonBox 83 | rejected() 84 | QHiMDFormatDialog 85 | reject() 86 | 87 | 88 | 316 89 | 260 90 | 91 | 92 | 286 93 | 274 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimdmacdetection.cpp: -------------------------------------------------------------------------------- 1 | #include "qhimddetection.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class QHiMDMacDetection : public QHiMDDetection { 8 | public: 9 | QHiMDMacDetection(QObject * parent = NULL); 10 | ~QHiMDMacDetection(); 11 | 12 | void scan_for_himd_devices(); 13 | 14 | private: 15 | virtual void add_himddevice(QString path, QString name, libusb_device * dev); 16 | }; 17 | 18 | 19 | QHiMDDetection * createDetection(QObject * parent) 20 | { 21 | return new QHiMDMacDetection(parent); 22 | } 23 | 24 | QHiMDMacDetection::QHiMDMacDetection(QObject * parent) 25 | : QHiMDDetection(parent) 26 | { 27 | ctx = NULL; 28 | dev_list = NULL; 29 | } 30 | 31 | QHiMDMacDetection::~QHiMDMacDetection() 32 | { 33 | poller->idle(); 34 | poller->quit(); 35 | delete poller; 36 | libusb_hotplug_deregister_callback(ctx, cb_handle); 37 | libusb_exit(ctx); 38 | clearDeviceList(); 39 | if(!ctx) 40 | netmd_clean(&dev_list); 41 | } 42 | 43 | void QHiMDMacDetection::scan_for_himd_devices() 44 | { 45 | const QString BASE_DIR = "/Volumes/"; 46 | 47 | /* skip enumeration when libusb hotplug events are used 48 | * path is empty for hotplugged devices but will be asked for and set when opening 49 | * alternatively use enueration but hotplug events will not detect disconnection of these devices */ 50 | if(ctx) 51 | return; 52 | 53 | QString path; 54 | foreach (path, QDir(BASE_DIR).entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { 55 | QString fullPath = BASE_DIR + path; 56 | if (QFile(fullPath + "/HI-MD.IND").exists()) { 57 | add_himddevice(fullPath, path, NULL); 58 | } 59 | } 60 | } 61 | 62 | void QHiMDMacDetection::add_himddevice(QString path, QString name, libusb_device * dev = NULL) 63 | { 64 | QMDDevice *device; 65 | 66 | if(dev) { 67 | /* already present in the device list */ 68 | if(find_by_libusbDevice(dev)) 69 | return; 70 | /* TODO: find path for the corresponding device 71 | * qhimdtransfer will ask for path if not provided */ 72 | } 73 | else { 74 | foreach (device, dlist) { 75 | if (device->path() == path) { 76 | // Device is already added -- skip duplicate 77 | return; 78 | } 79 | } 80 | } 81 | 82 | QHiMDDevice * new_device = new QHiMDDevice(); 83 | new_device->setMdInserted(true); 84 | new_device->setName(name); 85 | new_device->setPath(path); 86 | new_device->setBusy(false); 87 | new_device->setLibusbDevice(dev); 88 | 89 | dlist.append(new_device); 90 | emit deviceListChanged(dlist); 91 | } 92 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimdmainwindow.h: -------------------------------------------------------------------------------- 1 | #ifndef QHIMDMAINWINDOW_H 2 | #define QHIMDMAINWINDOW_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include "qhimdaboutdialog.h" 8 | #include "qhimdformatdialog.h" 9 | #include "qhimddetection.h" 10 | #include "qmdmodel.h" 11 | 12 | namespace Ui 13 | { 14 | class QHiMDMainWindowClass; 15 | } 16 | 17 | class QHiMDMainWindow : public QMainWindow 18 | { 19 | Q_OBJECT 20 | 21 | public: 22 | QHiMDMainWindow(QWidget *parent = 0); 23 | ~QHiMDMainWindow(); 24 | 25 | private: 26 | Ui::QHiMDMainWindowClass *ui; 27 | QHiMDAboutDialog * aboutDialog; 28 | QHiMDFormatDialog * formatDialog; 29 | QHiMDDetection * detect; 30 | QNetMDTracksModel ntmodel; 31 | QHiMDTracksModel htmodel; 32 | QHiMDFileSystemModel localmodel; 33 | QSettings settings; 34 | QMDDevice * current_device; 35 | void set_buttons_enable(bool connect, bool download, bool upload, bool rename, bool del, bool format, bool quit); 36 | void init_himd_browser(QMDTracksModel *model); 37 | void init_local_browser(); 38 | void save_window_settings(); 39 | void read_window_settings(); 40 | bool autodetect_init(); 41 | void setCurrentDevice(QMDDevice * dev); 42 | void open_device(QMDDevice * dev); 43 | void upload_to(const QString & path); 44 | 45 | private slots: 46 | void on_action_Connect_triggered(); 47 | void on_action_Format_triggered(); 48 | void on_action_Upload_triggered(); 49 | void on_action_Download_triggered(); 50 | void on_action_Quit_triggered(); 51 | void on_action_About_triggered(); 52 | void on_upload_button_clicked(); 53 | void handle_himd_selection_change(const QItemSelection&, const QItemSelection&); 54 | void handle_local_selection_change(const QItemSelection&, const QItemSelection&); 55 | void device_list_changed(QMDDevicePtrList dplist); 56 | void on_himd_devices_activated(QString device); 57 | void current_device_closed(); 58 | void on_download_button_clicked(); 59 | }; 60 | 61 | #endif // QHIMDMAINWINDOW_H 62 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimdtransfer.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/qhimdtransfer.icns -------------------------------------------------------------------------------- /qhimdtransfer/qhimdtransfer.pro: -------------------------------------------------------------------------------- 1 | TEMPLATE = app 2 | CONFIG += link_prl link_pkgconfig 3 | 4 | # Mixed case target name for operating systems on which this is convention 5 | win32|mac { 6 | TARGET = QHiMDTransfer 7 | } else { 8 | TARGET = qhimdtransfer 9 | } 10 | 11 | DEPENDPATH += . 12 | INCLUDEPATH += . 13 | 14 | # for Qt5 compatibility 15 | QT += gui core 16 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets 17 | 18 | # determine version number from git 19 | VERSION = $$system(sh ../build/get_version.sh) 20 | VERSTR = '\\"$${VERSION}\\"' # place quotes around the version string 21 | DEFINES += VER=\"$${VERSTR}\" # create a VER macro containing the version string 22 | 23 | # determine build date (Using QMAKE_HOST here to account for cross-compilation case) 24 | equals(QMAKE_HOST.os,Windows) { 25 | BUILDDATE = $$system(date /T) 26 | } else { 27 | BUILDDATE = $$system(date +%a\\ %m\\/%d\\/%Y) 28 | } 29 | BDATESTR = '\\"$${BUILDDATE}\\"' # place quotes around the build date string 30 | DEFINES += BDATE=\"$${BDATESTR}\" # create a BDATE macro containing the build date string 31 | 32 | # language logic heavily inspired by Qt Creator's 33 | # share/qtcreator/translations/translations.pro 34 | include(util.pri) 35 | LANGUAGES = de \ 36 | nb \ 37 | sv \ 38 | fr \ 39 | pt \ 40 | pl \ 41 | ru \ 42 | it \ 43 | ja \ 44 | fi \ 45 | ar \ 46 | el \ 47 | da \ 48 | tr \ 49 | es \ 50 | nl \ 51 | cs \ 52 | uk \ 53 | br 54 | TRANSLATIONS = $$bracketAll(LANGUAGES, qhimdtransfer_,.ts) 55 | include(translate.pri) 56 | 57 | # Input 58 | HEADERS += qhimdaboutdialog.h \ 59 | qhimdformatdialog.h \ 60 | qhimduploaddialog.h \ 61 | qhimdmainwindow.h \ 62 | qhimddetection.h \ 63 | qmdmodel.h \ 64 | qmdtrack.h \ 65 | qmddevice.h 66 | FORMS += qhimdaboutdialog.ui \ 67 | qhimdformatdialog.ui \ 68 | qhimduploaddialog.ui \ 69 | qhimdmainwindow.ui 70 | SOURCES += main.cpp \ 71 | qhimdaboutdialog.cpp \ 72 | qhimdformatdialog.cpp \ 73 | qhimduploaddialog.cpp \ 74 | qhimdmainwindow.cpp \ 75 | qhimddetection.cpp \ 76 | qmdmodel.cpp \ 77 | qmdtrack.cpp \ 78 | qmddevice.cpp 79 | 80 | win32 { 81 | SOURCES += qhimdwindetection.cpp 82 | } else:mac { 83 | SOURCES += qhimdmacdetection.cpp 84 | } else:unix:!mac { 85 | SOURCES += qhimdlinuxdetection.cpp 86 | QT += dbus 87 | } else { 88 | SOURCES += qhimddummydetection.cpp 89 | } 90 | 91 | RESOURCES += icons.qrc 92 | 93 | win32:LIBS += -lsetupapi -lcfgmgr32 94 | 95 | SOURCES += wavefilewriter.cpp 96 | HEADERS += wavefilewriter.h 97 | 98 | win32:RC_FILE = qhimdtransfer.rc 99 | mac:ICON = qhimdtransfer.icns 100 | 101 | # Installing stuff 102 | translations.files = $$bracketAll(LANGUAGES, qhimdtransfer_,.qm) 103 | unix { 104 | INSTALLS += translations 105 | HACK = $$system(lrelease $$TRANSLATIONS) 106 | macx:translations.path = QHiMDTransfer.app/Contents/Resources/translations 107 | !macx:translations.path = /usr/share/qhimdtransfer/translations 108 | } 109 | 110 | include(../libhimd/use_libhimd.pri) 111 | include(../libnetmd/use_libnetmd.prl) 112 | include(../build/libusb.pri) 113 | include(../build/libtaglib.pri) 114 | include(../build/libmad.pri) 115 | include(../build/libid3tag.pri) 116 | include(../build/libz.pri) 117 | include(../build/installunix.pri) 118 | include(../build/common.pri) 119 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimdtransfer.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "icons/qhimdtransfer.ico" -------------------------------------------------------------------------------- /qhimdtransfer/qhimduploaddialog.cpp: -------------------------------------------------------------------------------- 1 | #include "qhimduploaddialog.h" 2 | #include "ui_qhimduploaddialog.h" 3 | 4 | void QHiMDUploadDialog::trackFailed(const QString & errmsg) 5 | { 6 | allfinished -= thisfilefinished; 7 | allfinished += thisfileblocks; 8 | m_ui->AllPBar->setValue(allfinished); 9 | 10 | m_ui->failed_text->setText(tr("%1 track(s) could not be uploaded").arg(++fcount)); 11 | 12 | QTreeWidgetItem * ErrorMsg; 13 | ErrorMsg = new QTreeWidgetItem(0); 14 | 15 | ErrorMsg->setText(0, tr("Track %1").arg(tracknum)); 16 | ErrorMsg->setText(1, errmsg); 17 | m_ui->ErrorList->insertTopLevelItem(0, ErrorMsg); 18 | m_ui->details_button->setEnabled(true); 19 | } 20 | 21 | void QHiMDUploadDialog::trackSucceeded() 22 | { 23 | /* should do nothing, just to be sure */ 24 | allfinished -= thisfilefinished; 25 | allfinished += thisfileblocks; 26 | m_ui->AllPBar->setValue(allfinished); 27 | 28 | m_ui->success_text->setText(tr("%1 track(s) successfully uploaded").arg(++scount)); 29 | } 30 | 31 | void QHiMDUploadDialog::finished() 32 | { 33 | m_ui->curtrack_label->setText(tr("upload finished")); 34 | /* Prevent shrinking of the box when hiding the indicators */ 35 | m_ui->current->setMinimumSize(m_ui->current->size()); 36 | m_ui->TrkPBar->hide(); 37 | /* set AllPBar to 100% if it is not used during transfer, 38 | * current netmd uploads doesn´t set the range correctly 39 | */ 40 | if(m_ui->AllPBar->maximum() == 0) 41 | { 42 | m_ui->AllPBar->setMaximum(1); 43 | m_ui->AllPBar->setValue(1); 44 | } 45 | m_ui->curtrack_label->hide(); 46 | 47 | m_ui->cancel_button->hide(); 48 | m_ui->close_button->show(); 49 | 50 | return; 51 | } 52 | 53 | void QHiMDUploadDialog::starttrack(const QMDTrack & trk, const QString & title) 54 | { 55 | tracknum = trk.tracknum() + 1; 56 | m_ui->curtrack_label->setText(tr("current track: %1 - %2").arg(tracknum).arg(title)); 57 | thisfileblocks = trk.blockcount(); 58 | thisfilefinished = 0; 59 | m_ui->TrkPBar->setRange(0, thisfileblocks); 60 | m_ui->TrkPBar->reset(); 61 | } 62 | 63 | void QHiMDUploadDialog::blockTransferred() 64 | { 65 | m_ui->TrkPBar->setValue(++thisfilefinished); 66 | m_ui->AllPBar->setValue(++allfinished); 67 | } 68 | 69 | void QHiMDUploadDialog::init(int trackcount, int totalblocks) 70 | { 71 | allblocks = totalblocks; 72 | allfinished = 0; 73 | m_ui->AllPBar->setRange(0, allblocks); 74 | m_ui->AllPBar->reset(); 75 | canceled = false; 76 | 77 | scount = fcount = 0; 78 | m_ui->success_text->setText(""); 79 | m_ui->failed_text->setText(""); 80 | 81 | if(!trackcount) 82 | { 83 | m_ui->alltrack_label->setText(tr("no tracks selected")); 84 | finished(); 85 | } 86 | else 87 | { 88 | m_ui->alltrack_label->setText(tr("please wait while uploading %1 track(s)").arg(trackcount)); 89 | /* undo QHiMDUploadDialog::finished */ 90 | m_ui->TrkPBar->show(); 91 | m_ui->curtrack_label->show(); 92 | m_ui->current->setMinimumSize(0,0); 93 | m_ui->close_button->hide(); 94 | m_ui->cancel_button->show(); 95 | } 96 | 97 | m_ui->ErrorList->setColumnWidth(0, 100); 98 | m_ui->ErrorList->clear(); 99 | m_ui->details_button->setChecked(false); 100 | m_ui->details_button->setEnabled(false); 101 | 102 | show(); 103 | resize(size().width(), sizeHint().height()); 104 | } 105 | 106 | QHiMDUploadDialog::QHiMDUploadDialog(QWidget *parent) : 107 | QDialog(parent), 108 | m_ui(new Ui::QHiMDUploadDialog), 109 | canceled(false) 110 | { 111 | m_ui->setupUi(this); 112 | } 113 | 114 | QHiMDUploadDialog::~QHiMDUploadDialog() 115 | { 116 | delete m_ui; 117 | } 118 | 119 | void QHiMDUploadDialog::on_details_button_toggled(bool checked) 120 | { 121 | if (checked) 122 | { 123 | m_ui->line->show(); 124 | m_ui->ErrorList->show(); 125 | } 126 | else 127 | { 128 | m_ui->line->hide(); 129 | m_ui->ErrorList->hide(); 130 | } 131 | /* Need to process events to make the show or hide calls take effect 132 | before calling sizeHint() */ 133 | QApplication::processEvents(); 134 | resize(size().width(), sizeHint().height()); 135 | } 136 | 137 | void QHiMDUploadDialog::on_close_button_clicked() 138 | { 139 | close(); 140 | } 141 | 142 | void QHiMDUploadDialog::on_cancel_button_clicked() 143 | { 144 | m_ui->alltrack_label->setText(tr("upload aborted by the user")); 145 | canceled = true; 146 | } 147 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimduploaddialog.h: -------------------------------------------------------------------------------- 1 | #ifndef QHIMDUPLOADDIALOG_H 2 | #define QHIMDUPLOADDIALOG_H 3 | 4 | #include 5 | #include "qmdtrack.h" 6 | 7 | namespace Ui { 8 | class QHiMDUploadDialog; 9 | } 10 | 11 | class QHiMDUploadDialog : public QDialog { 12 | Q_OBJECT 13 | 14 | public: 15 | explicit QHiMDUploadDialog(QWidget *parent = 0); 16 | virtual ~QHiMDUploadDialog(); 17 | bool upload_canceled() { return canceled; } 18 | 19 | void init(int trackcount, int totalblocks); 20 | void starttrack(const QMDTrack & trk, const QString & title); 21 | void blockTransferred(); 22 | void trackFailed(const QString & errmsg); 23 | void trackSucceeded(); 24 | void finished(); 25 | 26 | private: 27 | Ui::QHiMDUploadDialog *m_ui; 28 | int allblocks, allfinished; 29 | int tracknum; 30 | int thisfileblocks, thisfilefinished; 31 | int scount, fcount; 32 | bool canceled; 33 | 34 | private slots: 35 | /* UI slots */ 36 | void on_close_button_clicked(); 37 | void on_cancel_button_clicked(); 38 | void on_details_button_toggled(bool checked); 39 | }; 40 | 41 | #endif // QHIMDUPLOADDIALOG_H 42 | -------------------------------------------------------------------------------- /qhimdtransfer/qhimduploaddialog.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | QHiMDUploadDialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 357 10 | 447 11 | 12 | 13 | 14 | Track upload - QHiMDTransfer 15 | 16 | 17 | 18 | :/icons/upload_from_md.png 19 | 20 | 21 | 22 | true 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 0 32 | 0 33 | 34 | 35 | 36 | 37 | 38 | 39 | :/icons/upload_from_md.png 40 | 41 | 42 | true 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 75 51 | true 52 | 53 | 54 | 55 | please wait while uploading XX track(s) 56 | 57 | 58 | Qt::AlignCenter 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | overall progress 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 0 83 | 84 | 85 | 86 | 87 | 88 | 0 89 | 0 90 | 91 | 92 | 93 | current track: trknum - filename 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | xx track(s) successfully uploaded 109 | 110 | 111 | 112 | 113 | 114 | 115 | xx track(s) could not be uploaded 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 30 125 | 126 | 127 | 128 | 129 | Show Details 130 | 131 | 132 | true 133 | 134 | 135 | true 136 | 137 | 138 | 139 | 140 | 141 | 142 | Cancel 143 | 144 | 145 | 146 | 147 | 148 | 149 | Close 150 | 151 | 152 | true 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 3 162 | 163 | 164 | Qt::Horizontal 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | QFrame::Sunken 174 | 175 | 176 | false 177 | 178 | 179 | false 180 | 181 | 182 | 80 183 | 184 | 185 | 186 | Tracknr. 187 | 188 | 189 | 190 | 191 | Error message 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | -------------------------------------------------------------------------------- /qhimdtransfer/qmddevice.cpp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/qhimdtransfer/qmddevice.cpp -------------------------------------------------------------------------------- /qhimdtransfer/qmddevice.h: -------------------------------------------------------------------------------- 1 | #ifndef QMDDEVICE_H 2 | #define QMDDEVICE_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include "qhimduploaddialog.h" 9 | 10 | enum device_type { 11 | NO_DEVICE, 12 | NETMD_DEVICE, 13 | HIMD_DEVICE 14 | }; 15 | 16 | class QMDDevice : public QObject { 17 | Q_OBJECT 18 | Q_DISABLE_COPY(QMDDevice) 19 | 20 | QString recorder_name; 21 | bool is_busy; 22 | protected: 23 | QString device_path; 24 | QString device_file; 25 | enum device_type dev_type; 26 | bool is_open; 27 | unsigned int trk_count; 28 | bool md_inserted; 29 | void * devhandle; 30 | void * mdChange; 31 | QHiMDUploadDialog uploadDialog; 32 | libusb_device * ldev; 33 | public: 34 | explicit QMDDevice(); 35 | virtual ~QMDDevice(); 36 | virtual enum device_type deviceType(); 37 | virtual void setPath(QString path); 38 | virtual QString path(); 39 | virtual void setName(QString name); 40 | virtual QString name(); 41 | virtual void setDeviceFile(QString devfile); 42 | virtual QString deviceFile(); 43 | virtual void setBusy(bool busy); 44 | virtual bool isBusy(); 45 | virtual QString open() {return QString();} 46 | virtual void close() {} 47 | virtual bool isOpen() {return is_open;} 48 | virtual QString discTitle() {return QString();} 49 | virtual void setMdInserted(bool inserted); 50 | virtual bool mdInserted(); 51 | virtual void setDeviceHandle(void * devicehandle); 52 | virtual void * deviceHandle(); 53 | virtual void registerMdChange(void * regMdChange); 54 | virtual void * MdChange(); 55 | virtual void setLibusbDevice(libusb_device * dev); 56 | virtual libusb_device * libusbDevice(); 57 | virtual int trackCount() {return trk_count;} 58 | virtual QStringList downloadableFileExtensions() const; 59 | virtual void checkfile(QString UploadDirectory, QString &filename, QString extension); 60 | virtual void batchUpload(QMDTrackIndexList tlist, QString path) = 0; 61 | virtual void upload(unsigned int trackidx, QString path) = 0; 62 | virtual bool download(const QString &filename) = 0; 63 | 64 | signals: 65 | void opened(); 66 | void closed(); 67 | }; 68 | 69 | class QNetMDDevice : public QMDDevice { 70 | 71 | netmd_device * netmd; 72 | netmd_dev_handle * devh; 73 | minidisc current_md; 74 | private: 75 | QString upload_track_blocks(uint32_t length, FILE *file, size_t chunksize); 76 | public: 77 | explicit QNetMDDevice(); 78 | virtual ~QNetMDDevice(); 79 | virtual void setUsbDevice(netmd_device * dev); 80 | virtual netmd_device * usbDevice() {return netmd;} 81 | virtual QString open(); 82 | virtual void close(); 83 | virtual QString discTitle(); 84 | virtual QNetMDTrack netmdTrack(unsigned int trkindex); 85 | virtual void batchUpload(QMDTrackIndexList tlist, QString path); 86 | virtual void upload(unsigned int trackidx, QString path); 87 | virtual bool download(const QString &filename); 88 | 89 | }; 90 | 91 | class QHiMDDevice : public QMDDevice { 92 | 93 | struct himd * himd; 94 | private: 95 | QString dumpmp3(const QHiMDTrack &trk, QString file); 96 | QString dumpoma(const QHiMDTrack & track, QString file); 97 | QString dumppcm(const QHiMDTrack &track, QString file); 98 | public: 99 | explicit QHiMDDevice(); 100 | virtual ~QHiMDDevice(); 101 | virtual QString open(); 102 | virtual void close(); 103 | virtual QHiMDTrack himdTrack(unsigned int trkindex); 104 | virtual void upload(unsigned int trackidx, QString path); 105 | virtual void batchUpload(QMDTrackIndexList tlist, QString path); 106 | virtual bool download(const QString &filename); 107 | 108 | }; 109 | 110 | #endif // QMDDEVICE_H 111 | -------------------------------------------------------------------------------- /qhimdtransfer/qmdmodel.h: -------------------------------------------------------------------------------- 1 | #ifndef QMDMODEL_H 2 | #define QMDMODEL_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class QMDTracksModel : public QAbstractListModel { 12 | Q_OBJECT 13 | 14 | public: 15 | QMDTracksModel() {} 16 | /* Make this method from QAbstractListModel public */ 17 | virtual int columnCount(const QModelIndex & parent = QModelIndex() ) const = 0; 18 | /* dummy data for unknown devices */ 19 | virtual QString open(QMDDevice *device = NULL) = 0; 20 | virtual bool is_open() {return false;} 21 | virtual void close() {} 22 | }; 23 | 24 | class QNetMDTracksModel : public QMDTracksModel { 25 | Q_OBJECT 26 | 27 | QNetMDDevice * ndev; 28 | QNetMDTrackList allTracks; 29 | public: 30 | QNetMDTracksModel() {ndev = NULL;} 31 | /* QAbstractListModel stuff */ 32 | virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; 33 | virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; 34 | virtual int rowCount(const QModelIndex & parent = QModelIndex() ) const; 35 | virtual int columnCount(const QModelIndex & parent = QModelIndex() ) const; 36 | /* NetMD device stuff */ 37 | QString open(QMDDevice *device); /* returns null if OK, error message otherwise */ 38 | virtual bool is_open(); 39 | void close(); 40 | }; 41 | 42 | class QHiMDTracksModel : public QMDTracksModel { 43 | Q_OBJECT 44 | 45 | QHiMDDevice * hdev; 46 | public: 47 | QHiMDTracksModel() {hdev = NULL;} 48 | /* QAbstractListModel stuff */ 49 | virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; 50 | virtual QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const; 51 | virtual int rowCount(const QModelIndex & parent = QModelIndex() ) const; 52 | virtual int columnCount(const QModelIndex & parent = QModelIndex() ) const; 53 | /* HiMD containter stuff */ 54 | virtual QString open(QMDDevice *device); /* returns null if OK, error message otherwise */ 55 | virtual bool is_open(); 56 | virtual void close(); 57 | }; 58 | 59 | class QHiMDFileSystemModel : public QFileSystemModel { 60 | Q_OBJECT 61 | 62 | QStringList selectableExtensions; 63 | public: 64 | virtual Qt::ItemFlags flags(const QModelIndex &index) const; 65 | void setSelectableExtensions(QStringList extensions); 66 | }; 67 | 68 | #endif // QMDMODEL_H 69 | -------------------------------------------------------------------------------- /qhimdtransfer/qmdtrack.cpp: -------------------------------------------------------------------------------- 1 | #include "qmdtrack.h" 2 | 3 | static QString get_himd_str(struct himd * himd, int idx) 4 | { 5 | QString outstr; 6 | char * str; 7 | if(!idx) 8 | return QString(); 9 | str = himd_get_string_utf8(himd, idx, NULL, NULL); 10 | if(!str) 11 | return QString(); 12 | 13 | outstr = QString::fromUtf8(str); 14 | himd_free(str); 15 | return outstr; 16 | } 17 | 18 | QHiMDTrack::QHiMDTrack(struct himd * himd, unsigned int trackindex) : himd(himd), trknum(trackindex) 19 | { 20 | trackslot = himd_get_trackslot(himd, trackindex, NULL); 21 | if(trackslot != 0) 22 | if(himd_get_track_info(himd, trackslot, &ti, NULL) < 0) 23 | trackslot = -1; 24 | } 25 | 26 | QHiMDTrack::~QHiMDTrack() 27 | { 28 | himd = NULL; 29 | } 30 | 31 | unsigned int QHiMDTrack::tracknum() const 32 | { 33 | return trknum; 34 | } 35 | 36 | QString QHiMDTrack::title() const 37 | { 38 | if(trackslot != 0) 39 | return get_himd_str(himd, ti.title); 40 | else 41 | return QString(); 42 | } 43 | 44 | QString QHiMDTrack::artist() const 45 | { 46 | if(trackslot != 0) 47 | return get_himd_str(himd, ti.artist); 48 | else 49 | return QString(); 50 | } 51 | 52 | QString QHiMDTrack::album() const 53 | { 54 | if(trackslot != 0) 55 | return get_himd_str(himd, ti.album); 56 | else 57 | return QString(); 58 | } 59 | 60 | QString QHiMDTrack::codecname() const 61 | { 62 | if(trackslot != 0) 63 | return himd_get_codec_name(&ti); 64 | else 65 | return QString(); 66 | } 67 | 68 | QTime QHiMDTrack::duration() const 69 | { 70 | QTime t(0,0,0); 71 | if(trackslot != 0) 72 | return t.addSecs(ti.seconds); 73 | else 74 | return QTime(); 75 | } 76 | 77 | QDateTime QHiMDTrack::recdate() const 78 | { 79 | QDate d(0,0,0); 80 | QTime t(0,0,0); 81 | if (trackslot != 0) 82 | { 83 | t.setHMS(ti.recordingtime.tm_hour, 84 | ti.recordingtime.tm_min, 85 | ti.recordingtime.tm_sec); 86 | d.setDate(ti.recordingtime.tm_year+1900, 87 | ti.recordingtime.tm_mon+1, 88 | ti.recordingtime.tm_mday); 89 | return QDateTime(d,t); 90 | } 91 | return QDateTime(); 92 | } 93 | 94 | bool QHiMDTrack::copyprotected() const 95 | { 96 | if(trackslot != 0) 97 | return !himd_track_uploadable(himd, &ti); 98 | return true; 99 | } 100 | 101 | int QHiMDTrack::blockcount() const 102 | { 103 | if(trackslot != 0) 104 | return himd_track_blocks(himd, &ti, NULL); 105 | else 106 | return 0; 107 | } 108 | 109 | QString QHiMDTrack::openMpegStream(struct himd_mp3stream * str) const 110 | { 111 | struct himderrinfo status; 112 | if(himd_mp3stream_open(himd, trackslot, str, &status) < 0) 113 | return QString::fromUtf8(status.statusmsg); 114 | return QString(); 115 | } 116 | 117 | QString QHiMDTrack::openNonMpegStream(struct himd_nonmp3stream * str) const 118 | { 119 | struct himderrinfo status; 120 | if(himd_nonmp3stream_open(himd, trackslot, str, &status) < 0) 121 | return QString::fromUtf8(status.statusmsg); 122 | return QString(); 123 | } 124 | 125 | QByteArray QHiMDTrack::makeEA3Header() const 126 | { 127 | char header[EA3_FORMAT_HEADER_SIZE]; 128 | make_ea3_format_header(header, &ti.codec_info); 129 | return QByteArray(header,EA3_FORMAT_HEADER_SIZE); 130 | } 131 | 132 | 133 | QNetMDTrack::QNetMDTrack(netmd_dev_handle * deviceh, minidisc * my_md, int trackindex) 134 | { 135 | uint8_t g; 136 | struct netmd_pair const *bitrate; 137 | char *name, buffer[256]; 138 | 139 | devh = deviceh; 140 | md = my_md; 141 | trkindex = trackindex; 142 | 143 | if(netmd_request_title(devh, trkindex, buffer, sizeof(buffer)) < 0) 144 | { 145 | trkindex = -1; 146 | return; // no track with this trackindex 147 | } 148 | 149 | /* Figure out which group this track is in */ 150 | for( g = 1; g < md->group_count; g++ ) 151 | { 152 | if( (md->groups[g].start <= trkindex+1U) && (md->groups[g].finish >= trkindex+1U )) 153 | { 154 | groupstring = QString(md->groups[g].name); 155 | break; 156 | } 157 | } 158 | 159 | netmd_request_track_time(devh, trkindex, &time); 160 | netmd_request_track_flags(devh, trkindex, &flags); 161 | netmd_request_track_bitrate(devh, trkindex, &bitrate_id, &channel); 162 | 163 | bitrate = find_pair(bitrate_id, bitrates); 164 | 165 | /* Skip 'LP:' prefix... the codec type shows up in the list anyway*/ 166 | name = strncmp( buffer, "LP:", 3 ) ? buffer : buffer+3 ; 167 | 168 | titlestring = QString(name); 169 | codecstring = QString(bitrate->name); 170 | blocks = 0; 171 | } 172 | 173 | QNetMDTrack::~QNetMDTrack() 174 | { 175 | devh = NULL; 176 | md = NULL; 177 | } 178 | 179 | unsigned int QNetMDTrack::tracknum() const 180 | { 181 | /* returns zero based track number, maybe this function should return a one based track number as shown in the treeview, 182 | * trackindex -> zero based; tracknumber -> one based 183 | */ 184 | return trkindex; 185 | } 186 | 187 | QString QNetMDTrack::group() const 188 | { 189 | if(trkindex < 0) 190 | return QString(); 191 | 192 | return groupstring; 193 | } 194 | 195 | QString QNetMDTrack::title() const 196 | { 197 | if(trkindex < 0) 198 | return QString(); 199 | 200 | return titlestring; 201 | } 202 | 203 | QString QNetMDTrack::codecname() const 204 | { 205 | if(trkindex < 0) 206 | return QString(); 207 | 208 | return codecstring; 209 | } 210 | 211 | QTime QNetMDTrack::duration() const 212 | { 213 | QTime t(0,0,0); 214 | 215 | if(trkindex < 0) 216 | return QTime(); 217 | 218 | return t.addSecs( time.minute * 60 + time.second); 219 | } 220 | 221 | bool QNetMDTrack::copyprotected() const 222 | { 223 | switch(flags) 224 | { 225 | case 0x00 : return false; 226 | case 0x03 : return true; 227 | default : return true; // return true if unknown 228 | } 229 | } 230 | 231 | void QNetMDTrack::setBlocks(int cnt) 232 | { 233 | blocks = cnt; 234 | } 235 | 236 | int QNetMDTrack::blockcount() const 237 | { 238 | return blocks; 239 | } 240 | -------------------------------------------------------------------------------- /qhimdtransfer/qmdtrack.h: -------------------------------------------------------------------------------- 1 | #ifndef QMDTRACK_H 2 | #define QMDTRACK_H 3 | 4 | #include 5 | #include "himd.h" 6 | #include "sony_oma.h" 7 | 8 | #ifdef Q_OS_WIN 9 | #ifdef WINVER // WINVER needs to be 0x500 or later to make the windows autodetection mechanism work and it 10 | #undef WINVER // must be defined correctly before including libusb.h (included from libnetmd.h), else it will be defined 11 | #endif // in windef.h to 0x400 12 | #define WINVER 0x500 13 | #endif 14 | 15 | extern "C" { 16 | #include 17 | } 18 | 19 | /* define buffer size for netmd uploads */ 20 | #define NETMD_RECV_BUF_SIZE 0x10000 21 | 22 | class QMDTrack 23 | { 24 | public: 25 | QMDTrack() {} // returns dummy data, implemented to have a common class name with common members 26 | virtual ~QMDTrack() {} 27 | virtual unsigned int tracknum() const {return -1;} 28 | virtual QString group() const {return QString();} 29 | virtual QString title() const {return QString();} 30 | virtual QString artist() const {return QString();} 31 | virtual QString album() const {return QString();} 32 | virtual QString codecname() const {return QString();} 33 | virtual QTime duration() const {return QTime();} 34 | virtual bool copyprotected() const {return true;} 35 | virtual int blockcount() const {return 0;} 36 | }; 37 | 38 | class QHiMDTrack : public QMDTrack{ 39 | struct himd * himd; 40 | unsigned int trknum; 41 | unsigned int trackslot; 42 | struct trackinfo ti; 43 | public: 44 | QHiMDTrack(struct himd * himd, unsigned int trackindex); 45 | virtual ~QHiMDTrack(); 46 | virtual unsigned int tracknum() const; 47 | virtual QString title() const; 48 | virtual QString artist() const; 49 | virtual QString album() const; 50 | virtual QString codecname() const; 51 | virtual QTime duration() const; 52 | QDateTime recdate() const; 53 | virtual bool copyprotected() const; 54 | virtual int blockcount() const; 55 | 56 | QString openMpegStream(struct himd_mp3stream * str) const; 57 | QString openNonMpegStream(struct himd_nonmp3stream * str) const; 58 | QByteArray makeEA3Header() const; 59 | }; 60 | 61 | class QNetMDTrack : public QMDTrack { 62 | netmd_dev_handle * devh; 63 | minidisc * md; 64 | int8_t trkindex; 65 | struct netmd_track time; 66 | unsigned char flags; 67 | QString groupstring; 68 | QString titlestring; 69 | QString codecstring; 70 | private: 71 | int blocks; 72 | public: 73 | unsigned char bitrate_id; 74 | unsigned char channel; 75 | QNetMDTrack(netmd_dev_handle *deviceh, minidisc * my_md, int trackindex); 76 | virtual ~QNetMDTrack(); 77 | virtual unsigned int tracknum() const; 78 | virtual QString group() const; 79 | virtual QString title() const; 80 | virtual QString codecname() const; 81 | virtual QTime duration() const; 82 | virtual bool copyprotected() const; 83 | virtual void setBlocks(int cnt); 84 | virtual int blockcount() const; 85 | }; 86 | 87 | typedef QList QMDTrackList; 88 | typedef QList QHiMDTrackList; 89 | typedef QList QNetMDTrackList; 90 | typedef QList QMDTrackIndexList; 91 | 92 | #endif // QMDTRACK_H 93 | -------------------------------------------------------------------------------- /qhimdtransfer/translate.pri: -------------------------------------------------------------------------------- 1 | LUPDATE = $$[QT_INSTALL_BINS]/lupdate 2 | LRELEASE = $$[QT_INSTALL_BINS]/lrelease 3 | 4 | contains(QT_VERSION, ^4\\.[0-5]\\..*):ts.commands = @echo This Qt version is too old for the ts target. Need Qt 4.6+. 5 | else:ts.commands = $$LUPDATE . -ts $$TRANSLATIONS 6 | QMAKE_EXTRA_TARGETS += ts 7 | 8 | updateqm.input = TRANSLATIONS 9 | updateqm.output = ${QMAKE_FILE_BASE}.qm 10 | updateqm.commands = $$LRELEASE ${QMAKE_FILE_IN} -qm ${QMAKE_FILE_OUT} 11 | updateqm.name = LRELEASE ${QMAKE_FILE_IN} 12 | updateqm.CONFIG += no_link target_predeps 13 | QMAKE_EXTRA_COMPILERS += updateqm 14 | -------------------------------------------------------------------------------- /qhimdtransfer/util.pri: -------------------------------------------------------------------------------- 1 | defineReplace(bracketAll) { 2 | for(a,$$1):result += $$2$${a}$$3 3 | return($$result) 4 | } 5 | -------------------------------------------------------------------------------- /qhimdtransfer/wavefilewriter.cpp: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * wavfilewriter: Helper class to write .wav file headers 4 | * Copyright (C) 2016 Thomas Perl 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | **/ 20 | 21 | #include "wavefilewriter.h" 22 | 23 | #include 24 | #include 25 | #include 26 | 27 | /** 28 | * Based on the file format description at http://soundfile.sapp.org/doc/WaveFormat/ 29 | **/ 30 | 31 | struct RIFFHeader { 32 | char riff[4]; // "RIFF" 33 | uint32_t total_size; 34 | char format[4]; // "WAVE" 35 | }; 36 | 37 | struct ChunkHeader { 38 | char id[4]; // "fmt " for format chunk, "data" for samples 39 | uint32_t size; 40 | }; 41 | 42 | struct FormatChunk { 43 | int16_t audioFormat; 44 | uint16_t numChannels; 45 | uint32_t sampleRate; 46 | uint32_t bytesPerSecond; 47 | uint16_t blockAlign; 48 | uint16_t bitsPerSample; 49 | }; 50 | 51 | WaveFileWriter::WaveFileWriter() 52 | : output() 53 | , updateSize(false) 54 | { 55 | } 56 | 57 | WaveFileWriter::~WaveFileWriter() 58 | { 59 | close(); 60 | } 61 | 62 | bool 63 | WaveFileWriter::open(const QString &filename, int sampleRate, int sampleSize, int channels) 64 | { 65 | output.close(); 66 | output.setFileName(filename); 67 | output.open(QIODevice::WriteOnly); 68 | 69 | RIFFHeader hdr; 70 | ChunkHeader chk; 71 | FormatChunk fmt; 72 | 73 | // RIFF header 74 | memcpy(hdr.riff, "RIFF", 4); 75 | hdr.total_size = 0; // To be filled later 76 | memcpy(hdr.format, "WAVE", 4); 77 | if ((size_t)output.write((char *)&hdr, sizeof(hdr)) != sizeof(hdr)) { 78 | return false; 79 | } 80 | 81 | // Format chunk header 82 | memcpy(chk.id, "fmt ", 4); 83 | chk.size = qToLittleEndian(uint32_t(sizeof(fmt))); 84 | if ((size_t)output.write((char *)&chk, sizeof(chk)) != sizeof(chk)) { 85 | return false; 86 | } 87 | 88 | // Format chunk 89 | fmt.audioFormat = qToLittleEndian(int16_t(1)); // PCM 90 | fmt.numChannels = qToLittleEndian(uint32_t(channels)); 91 | fmt.sampleRate = qToLittleEndian(uint32_t(sampleRate)); 92 | fmt.bytesPerSecond = qToLittleEndian(uint32_t(channels * (sampleSize / 8) * sampleRate)); 93 | fmt.blockAlign = qToLittleEndian(uint32_t(channels * (sampleSize / 8))); 94 | fmt.bitsPerSample = qToLittleEndian(uint32_t(sampleSize)); 95 | if ((size_t)output.write((char *)&fmt, sizeof(fmt)) != sizeof(fmt)) { 96 | return false; 97 | } 98 | 99 | // Data chunk header 100 | memcpy(chk.id, "data", 4); 101 | chk.size = 0; // To be filled later 102 | if ((size_t)output.write((char *)&chk, sizeof(chk)) != sizeof(chk)) { 103 | return false; 104 | } 105 | 106 | updateSize = true; 107 | return true; 108 | } 109 | 110 | bool 111 | WaveFileWriter::write_signed_big_endian(const int16_t *data, size_t samples) 112 | { 113 | int16_t tmp[samples]; 114 | for (size_t i=0; i(tmp), sizeof(tmp)) == sizeof(tmp)); 118 | } 119 | 120 | static bool 121 | updateU32LESizeField(QFile &file, size_t offset, uint32_t new_value) 122 | { 123 | if (!file.seek(offset)) { 124 | qWarning() << "Could not seek to update field"; 125 | return false; 126 | } 127 | 128 | // The "remaining" size is calculated from after the value (subtract offset + value size) 129 | new_value = qToLittleEndian(uint32_t(new_value - (offset + sizeof(new_value)))); 130 | if ((size_t)file.write((char *)&new_value, sizeof(new_value)) != sizeof(new_value)) { 131 | qWarning() << "Could not update field in file"; 132 | return false; 133 | } 134 | 135 | return true; 136 | } 137 | 138 | void 139 | WaveFileWriter::close() 140 | { 141 | // File size in the RIFF header 142 | size_t riff_header_offset = offsetof(RIFFHeader, total_size); 143 | // Chunk size in the "data" chunk 144 | size_t data_header_offset = sizeof(RIFFHeader) + sizeof(ChunkHeader) + sizeof(FormatChunk) + offsetof(ChunkHeader, size); 145 | 146 | if (updateSize && 147 | updateU32LESizeField(output, riff_header_offset, output.size()) && 148 | updateU32LESizeField(output, data_header_offset, output.size())) { 149 | updateSize = false; 150 | } 151 | 152 | output.close(); 153 | } 154 | -------------------------------------------------------------------------------- /qhimdtransfer/wavefilewriter.h: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * wavfilewriter: Helper class to write .wav file headers 4 | * Copyright (C) 2016 Thomas Perl 5 | * 6 | * This program is free software; you can redistribute it and/or modify 7 | * it under the terms of the GNU General Public License as published by 8 | * the Free Software Foundation; either version 2 of the License, or 9 | * (at your option) any later version. 10 | * 11 | * This program is distributed in the hope that it will be useful, 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | * GNU General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU General Public License along 17 | * with this program; if not, write to the Free Software Foundation, Inc., 18 | * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 19 | **/ 20 | 21 | #ifndef _WAVEFILEWRITER_H 22 | #define _WAVEFILEWRITER_H 23 | 24 | #include 25 | #include 26 | 27 | #include 28 | 29 | class WaveFileWriter { 30 | public: 31 | WaveFileWriter(); 32 | ~WaveFileWriter(); 33 | 34 | bool open(const QString &filename, int sampleRate, int sampleSize, int channels); 35 | bool write_signed_big_endian(const int16_t *data, size_t samples); 36 | void close(); 37 | 38 | private: 39 | QFile output; 40 | bool updateSize; 41 | }; 42 | 43 | #endif /* _WAVEFILEWRITER_H */ 44 | -------------------------------------------------------------------------------- /testdata/himd/HI-MD.IND: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/testdata/himd/HI-MD.IND -------------------------------------------------------------------------------- /testdata/himd/HMDHIFI/00010012.HMA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/testdata/himd/HMDHIFI/00010012.HMA -------------------------------------------------------------------------------- /testdata/himd/HMDHIFI/ATDATA07.HMA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/testdata/himd/HMDHIFI/ATDATA07.HMA -------------------------------------------------------------------------------- /testdata/himd/HMDHIFI/MCLIST06.HMA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/testdata/himd/HMDHIFI/MCLIST06.HMA -------------------------------------------------------------------------------- /testdata/himd/HMDHIFI/MCLIST07.HMA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/testdata/himd/HMDHIFI/MCLIST07.HMA -------------------------------------------------------------------------------- /testdata/himd/HMDHIFI/TRKIDX07.HMA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/testdata/himd/HMDHIFI/TRKIDX07.HMA -------------------------------------------------------------------------------- /testdata/himd/HMDHIFI/_0010012.HMA: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /testdata/himd/HMDHIFI/_MDHIFI.HMA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/testdata/himd/HMDHIFI/_MDHIFI.HMA -------------------------------------------------------------------------------- /testdata/himd/HMDHIFI/_RKIDX08.HMA: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/testdata/himd/HMDHIFI/_RKIDX08.HMA -------------------------------------------------------------------------------- /testdata/himd/README.TXT: -------------------------------------------------------------------------------- 1 | Hi-MD Format Upload Test Data 2 | ============================= 3 | 4 | Siesta by Jahzzar is licensed under a Creative Commons Attribution-ShareAlike 5 | 3.0 International License. 6 | 7 | http://freemusicarchive.org/music/Jahzzar/Travellers_Guide/Siesta 8 | -------------------------------------------------------------------------------- /testdata/netmd/captures/README: -------------------------------------------------------------------------------- 1 | This directory contains NetMD-related USB captures for Sonicstage operations. 2 | 3 | * mz-n710-transfer.pcapng: erase disc and transfer 10 second track to MZ-N710. 4 | Erase occurs at packet 2479, transfer starts at 6061, track name write at 6351, 5 | commit at 6367. 6 | -------------------------------------------------------------------------------- /testdata/netmd/captures/mz-n710-transfer.pcapng: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuori/linux-minidisc/7bc0672bfe68cfc0a1bc1e8acd8c5658e4792b9c/testdata/netmd/captures/mz-n710-transfer.pcapng --------------------------------------------------------------------------------