FU Logo
  • Startseite
  • Kontakt
  • Impressum
  • Home
  • Listenauswahl
  • Anleitungen

Re: [linux-minidisc] implementing netmd support in the gui application

<-- thread -->
<-- date -->
  • From: Thomas Arp <manner.moe@gmx.de>
  • To: linux-minidisc@lists.fu-berlin.de
  • Date: Sat, 12 Jan 2013 23:39:52 +0100
  • Subject: Re: [linux-minidisc] implementing netmd support in the gui application

Am 10.01.2013 00:18, schrieb Thomas Arp:
Hi,
as some patches have been committed since i started implementation of netmd support i rebased my local master branch now and updated my local work branch.
You can find my work at netmd_integration_latest branch on my github account [1].
Also i made a patch which can be applied to the current master repository attached to this email.

Thomas

[1] http://github.com/tharp/linux-minidisc


_______________________________________________
linux-minidisc mailing list
linux-minidisc@lists.fu-berlin.de
https://lists.fu-berlin.de/listinfo/linux-minidisc
Hi,
now i have implemeted netmd usb upload routine (supported by Sony MZ-RH1 only).
You can find my work at netmd_integration_latest branch on my github account [1].
I made a patch attached to this mail.

Thomas


[1] http://github.com/tharp/linux-minidisc
>From fcb9ecc352ad6687edb708cfd83a7341759f8060 Mon Sep 17 00:00:00 2001
From: Thomas Arp <manner.moe@gmx.de>
Date: Sat, 12 Jan 2013 23:31:15 +0100
Subject: [PATCH 2/2] implement netmd usb uploads (supported by SONY MZ-RH1
 only)

---
 libnetmd/libnetmd.pro               |   3 +-
 libnetmd/libnetmd_extended.h        |  37 +++++++++
 qhimdtransfer/qhimdmainwindow.cpp   |   2 +-
 qhimdtransfer/qhimduploaddialog.cpp |   7 ++
 qhimdtransfer/qmddevice.cpp         | 145 +++++++++++++++++++++++++++++++++++-
 qhimdtransfer/qmddevice.h           |  11 ++-
 qhimdtransfer/qmdmodel.cpp          |   2 +-
 qhimdtransfer/qmdtrack.cpp          |  16 +++-
 qhimdtransfer/qmdtrack.h            |  11 ++-
 9 files changed, 218 insertions(+), 16 deletions(-)
 create mode 100644 libnetmd/libnetmd_extended.h

diff --git a/libnetmd/libnetmd.pro b/libnetmd/libnetmd.pro
index eb6a402..3319d85 100644
--- a/libnetmd/libnetmd.pro
+++ b/libnetmd/libnetmd.pro
@@ -5,7 +5,8 @@ CONFIG += staticlib link_pkgconfig create_prl console debug_and_release_target
 DEFINES += G_DISABLE_DEPRECATED=1
 
 PKGCONFIG += libusb-1.0
-HEADERS += common.h const.h error.h libnetmd.h log.h netmd_dev.h playercontrol.h secure.h trackinformation.h utils.h
+HEADERS += common.h const.h error.h libnetmd.h log.h netmd_dev.h playercontrol.h secure.h trackinformation.h utils.h \
+    libnetmd_extended.h
 SOURCES += common.c error.c libnetmd.c log.c netmd_dev.c playercontrol.c secure.c trackinformation.c utils.c
 LIBS    += -lgcrypt
 
diff --git a/libnetmd/libnetmd_extended.h b/libnetmd/libnetmd_extended.h
new file mode 100644
index 0000000..1eb74db
--- /dev/null
+++ b/libnetmd/libnetmd_extended.h
@@ -0,0 +1,37 @@
+/*
+ * include this header file to get access to additional libnetmd members
+ */
+
+#include "libnetmd.h"
+
+typedef struct {
+        unsigned char content[255];
+        size_t length;
+        size_t position;
+} netmd_response;
+
+/*
+ * additional members from secure.c
+ */
+
+void netmd_send_secure_msg(netmd_dev_handle *dev, unsigned char cmd, unsigned char *data, size_t data_size);
+netmd_error netmd_recv_secure_msg(netmd_dev_handle *dev, unsigned char cmd, netmd_response *response,
+                                  unsigned char expected_response_code);
+netmd_error netmd_secure_real_recv_track(netmd_dev_handle *dev, uint32_t length, FILE *file, size_t chunksize);
+void netmd_write_aea_header(char *name, uint32_t frames, unsigned char channel, FILE* f);
+void netmd_write_wav_header(unsigned char format, uint32_t bytes, FILE *f);
+
+/*
+ * additional members from utils.c
+ * XXX: do not include utils.h when using taglib, definition of min(a,b) is incomatible with definition of min(...) in taglib
+ */
+void netmd_check_response_bulk(netmd_response *response, const unsigned char* const expected,
+                               const size_t expected_length, netmd_error *error);
+void netmd_check_response_word(netmd_response *response, const uint16_t expected,
+                               netmd_error *error);
+void netmd_read_response_bulk(netmd_response *response, unsigned char* target,
+                              const size_t length, netmd_error *error);
+unsigned char *netmd_copy_word_to_buffer(unsigned char **buf, uint16_t value, int little_endian);
+unsigned char netmd_read(netmd_response *response);
+uint16_t netmd_read_word(netmd_response *response);
+uint32_t netmd_read_doubleword(netmd_response *response);
diff --git a/qhimdtransfer/qhimdmainwindow.cpp b/qhimdtransfer/qhimdmainwindow.cpp
index a406ea5..8c4d19f 100644
--- a/qhimdtransfer/qhimdmainwindow.cpp
+++ b/qhimdtransfer/qhimdmainwindow.cpp
@@ -31,7 +31,7 @@ void QHiMDMainWindow::init_local_browser()
 {
     QStringList DownloadFileList;
     localmodel.setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
-    localmodel.setNameFilters(QStringList() << "*.mp3" << "*.wav" << "*.oma");
+    localmodel.setNameFilters(QStringList() << "*.mp3" << "*.wav" << "*.oma" << "*.aea");
     localmodel.setNameFilterDisables(false);
     localmodel.setReadOnly(false);
     localmodel.setRootPath("/");
diff --git a/qhimdtransfer/qhimduploaddialog.cpp b/qhimdtransfer/qhimduploaddialog.cpp
index 13f327e..605c868 100644
--- a/qhimdtransfer/qhimduploaddialog.cpp
+++ b/qhimdtransfer/qhimduploaddialog.cpp
@@ -34,6 +34,13 @@ void QHiMDUploadDialog::finished()
     /* Prevent shrinking of the box when hiding the indicators */
     m_ui->current->setMinimumSize(m_ui->current->size());
     m_ui->TrkPBar->hide();
+    /* set AllPBar to 100% if it is not used during transfer,
+     * current netmd uploads doesn´t set the range correctly
+     */
+    if(m_ui->AllPBar->maximum() == 0) {
+        m_ui->AllPBar->setMaximum(1);
+        m_ui->AllPBar->setValue(1);
+    }
     m_ui->curtrack_label->hide();
 
     m_ui->cancel_button->hide();
diff --git a/qhimdtransfer/qmddevice.cpp b/qhimdtransfer/qmddevice.cpp
index eeb7e78..be85492 100644
--- a/qhimdtransfer/qmddevice.cpp
+++ b/qhimdtransfer/qmddevice.cpp
@@ -166,12 +166,151 @@ QNetMDTrack QNetMDDevice::netmdTrack(unsigned int trkindex)
     return QNetMDTrack(devh, disc, trkindex);
 }
 
+QString QNetMDDevice::upload_track_blocks(uint32_t length, FILE *file, size_t chunksize)
+{
+    /* this is a copy of netmd_secure_real_recv_track(...) function, but updates upload dialog progress bar */
+    uint32_t done = 0;
+    unsigned char *data;
+    int status;
+    netmd_error error = NETMD_NO_ERROR;
+    int transferred = 0;
+
+    data = (unsigned char *)malloc(chunksize);
+    while (done < length) {
+        if ((length - done) < chunksize) {
+            chunksize = length - done;
+        }
+
+        status = libusb_bulk_transfer((libusb_device_handle*)devh, 0x81, data, (int)chunksize, &transferred, 10000);
+
+        if (status >= 0) {
+            done += transferred;
+            fwrite(data, transferred, 1, file);
+            netmd_log(NETMD_LOG_DEBUG, "%.1f%%\n", (double)done/(double)length * 100);
+
+            uploadDialog.blockTransferred();
+            /* do not check for uploadDialog.upload_canceled() here, netmd device will remain busy if track upload hasn´t finished */
+        }
+        else if (status != -LIBUSB_ERROR_TIMEOUT) {
+            error = NETMD_USB_ERROR;
+        }
+    }
+    free(data);
+
+    return (error != NETMD_NO_ERROR) ? netmd_strerror(error) : QString();
+}
+
+void QNetMDDevice::upload(unsigned int trackidx, QString path)
+{
+    /* this is a copy of netmd_secure_recv_track(...) function, we need single block transfer function to make use of a progress bar,
+     * maybe we can change libnetmd to make use of a single chunk transfer function for this
+     */
+    QNetMDTrack track = netmdTrack(trackidx);
+    uint16_t track_id = trackidx;
+    unsigned char cmdhdr[] = {0x00, 0x10, 0x01};
+    unsigned char cmd[sizeof(cmdhdr) + sizeof(track_id)] = { 0 };
+    unsigned char *buf;
+    unsigned char codec;
+    uint32_t length;
+    netmd_response response;
+    netmd_error error;
+    QString filename, errmsg, filepath;
+    FILE * file;
+
+    // create filename first
+    if(track.title().isEmpty())
+        filename = tr("Track %1").arg(track.tracknum());
+    else
+        filename = track.title();
+
+    if(track.bitrate_id == NETMD_ENCODING_SP) {
+        checkfile(path, filename, ".aea");
+        filepath = path + "/" + filename + ".aea";
+    }
+    else {
+        checkfile(path, filename, ".wav");
+        filepath = path + "/" + filename + ".wav";
+    }
+
+    if(!(file = fopen(filepath.toUtf8().data(), "wb"))) {
+            errmsg = tr("cannot open file %1 for writing").arg(filepath);
+            goto clean;
+    }
+
+    buf = cmd;
+    memcpy(buf, cmdhdr, sizeof(cmdhdr));
+    buf += sizeof(cmdhdr);
+    netmd_copy_word_to_buffer(&buf, trackidx + 1U, 0);
+
+    netmd_send_secure_msg(devh, 0x30, cmd, sizeof(cmd));
+    error = netmd_recv_secure_msg(devh, 0x30, &response, NETMD_STATUS_INTERIM);
+    netmd_check_response_bulk(&response, cmdhdr, sizeof(cmdhdr), &error);
+    netmd_check_response_word(&response, track_id + 1U, &error);
+    codec = netmd_read(&response);
+    length = netmd_read_doubleword(&response);
+
+    /* initialize track.blockcount() needed by uploadDialog */
+    track.setBlocks(length%NETMD_RECV_BUF_SIZE ? length / NETMD_RECV_BUF_SIZE + 1 : length / NETMD_RECV_BUF_SIZE);
+    uploadDialog.starttrack(track, filename);
+    if (track.bitrate_id == NETMD_ENCODING_SP) {
+        netmd_write_aea_header(track.title().toUtf8().data(), codec, track.channel, file);
+    }
+    else {
+        netmd_write_wav_header(codec, length, file);
+    }
+
+    errmsg = upload_track_blocks(length, file, NETMD_RECV_BUF_SIZE);
+    if(!errmsg.isNull()) {
+        goto clean;
+    }
+
+    error = netmd_recv_secure_msg(devh, 0x30, &response, NETMD_STATUS_ACCEPTED);
+    netmd_check_response_bulk(&response, cmdhdr, sizeof(cmdhdr), &error);
+    netmd_read_response_bulk(&response, NULL, 2, &error);
+    netmd_check_response_word(&response, 0, &error);
+
+    if(error != NETMD_NO_ERROR)
+        errmsg = QString(netmd_strerror(error));
+
+clean:
+    if(errmsg.isNull())
+        uploadDialog.trackSucceeded();
+    else
+        uploadDialog.trackFailed(errmsg);
+
+    fclose(file);
+    if(!errmsg.isNull()) {
+        QFile f(filepath);
+        if(f.exists())
+            f.remove();
+    }
+}
+
 void QNetMDDevice::batchUpload(QMDTrackIndexList tlist, QString path)
 {
-    QMessageBox mdStatus;
+    int allblocks = 0;
+
+    setBusy(true);
+
+    /* does not work yet, is there any way to get track length without recieving a complete track ?
+     * as far as i´ve tested device remains busy if download procedure hasn´t finished.
+     * progressbar for all tracks shows idle mode if maximum value is set to 0
+     */
+    for(int i = 0;i < tlist.length(); i++) {
+        allblocks += netmdTrack(tlist.at(i)).blockcount();
+    }
+
+    uploadDialog.init(tlist.length(), allblocks);
+
+    for(int i = 0; i < tlist.length(); i++) {
+        upload(tlist[i], path);
+        QApplication::processEvents();
+        if(uploadDialog.upload_canceled())
+            break;
+    }
 
-    mdStatus.setText(tr("netmd uploads are not implemented, yet\n will be comming soon"));
-    mdStatus.exec();
+    uploadDialog.finished();
+    setBusy(false);
 }
 
 /* himd device members */
diff --git a/qhimdtransfer/qmddevice.h b/qhimdtransfer/qmddevice.h
index 2e92102..3be6c36 100644
--- a/qhimdtransfer/qmddevice.h
+++ b/qhimdtransfer/qmddevice.h
@@ -65,6 +65,8 @@ class QNetMDDevice : public QMDDevice {
     netmd_device * netmd;
     netmd_dev_handle * devh;
     minidisc current_md;
+private:
+    QString upload_track_blocks(uint32_t length, FILE *file, size_t chunksize);
 public:
     explicit QNetMDDevice();
     virtual ~QNetMDDevice();
@@ -74,22 +76,23 @@ public:
     virtual QString discTitle();  //
     virtual QNetMDTrack netmdTrack(unsigned int trkindex);
     virtual void batchUpload(QMDTrackIndexList tlist, QString path);
-    virtual void upload(unsigned int trackidx, QString path) {}
+    virtual void upload(unsigned int trackidx, QString path);
 
 };
 
 class QHiMDDevice : public QMDDevice {
 
     struct himd * himd;
+private:
+    QString dumpmp3(const QHiMDTrack &trk, QString file);
+    QString dumpoma(const QHiMDTrack & track, QString file);
+    QString dumppcm(const QHiMDTrack &track, QString file);
 public:
     explicit QHiMDDevice();
     virtual ~QHiMDDevice();
     virtual QString open();  //
     virtual void close();  //
     virtual QHiMDTrack himdTrack(unsigned int trkindex);  //
-    QString dumpmp3(const QHiMDTrack &trk, QString file);
-    QString dumpoma(const QHiMDTrack & track, QString file);
-    QString dumppcm(const QHiMDTrack &track, QString file);
     virtual void upload(unsigned int trackidx, QString path);
     virtual void batchUpload(QMDTrackIndexList tlist, QString path);
 
diff --git a/qhimdtransfer/qmdmodel.cpp b/qhimdtransfer/qmdmodel.cpp
index abbdddc..04e67da 100644
--- a/qhimdtransfer/qmdmodel.cpp
+++ b/qhimdtransfer/qmdmodel.cpp
@@ -73,7 +73,7 @@ QVariant QNetMDTracksModel::data(const QModelIndex & index, int role) const
     QNetMDTrack track = allTracks[index.row()];
 
     if(role == Qt::CheckStateRole && index.column() == CoUploadable)
-        return track.copyprotected() ? Qt::Unchecked : Qt::Checked;
+        return ((ndev->name() != "SONY MZ-RH1 (NetMD)") && track.copyprotected()) ? Qt::Unchecked : Qt::Checked;
 
     if(role == Qt::DisplayRole)
     {
diff --git a/qhimdtransfer/qmdtrack.cpp b/qhimdtransfer/qmdtrack.cpp
index 84643f8..e3ea7d7 100644
--- a/qhimdtransfer/qmdtrack.cpp
+++ b/qhimdtransfer/qmdtrack.cpp
@@ -1,4 +1,5 @@
 #include "qmdtrack.h"
+#include <QDebug>
 
 static QString get_himd_str(struct himd * himd, int idx)
 {
@@ -112,8 +113,6 @@ QNetMDTrack::QNetMDTrack(netmd_dev_handle * deviceh, minidisc * my_md, unsigned
 {
     uint8_t g;
     struct netmd_pair const *bitrate;
-    unsigned char bitrate_id;
-    unsigned char channel;
     char *name, buffer[256];
 
     devh = deviceh;
@@ -147,11 +146,15 @@ QNetMDTrack::QNetMDTrack(netmd_dev_handle * deviceh, minidisc * my_md, unsigned
 
     titlestring = QString(name);
     codecstring = QString(bitrate->name);
+    blocks = 0;
 }
 
 unsigned int QNetMDTrack::tracknum() const
 {
-    return (trkindex < 0 ? trkindex : trkindex + 1);
+    /* returns zero based track number, maybe this function should return a one based track number as shown in the treeview,
+     * trackindex -> zero based; tracknumber -> one based
+     */
+    return trkindex;
 }
 
 QString QNetMDTrack::group() const
@@ -198,7 +201,12 @@ bool QNetMDTrack::copyprotected() const
     }
 }
 
+void QNetMDTrack::setBlocks(int cnt)
+{
+    blocks = cnt;
+}
+
 int QNetMDTrack::blockcount() const
 {
-    return 0;  // not implemented, yet
+    return blocks;
 }
diff --git a/qhimdtransfer/qmdtrack.h b/qhimdtransfer/qmdtrack.h
index c7f30ad..47f93f8 100644
--- a/qhimdtransfer/qmdtrack.h
+++ b/qhimdtransfer/qmdtrack.h
@@ -13,9 +13,12 @@
 #endif
 
 extern "C" {
-#include <libnetmd.h>
+#include <libnetmd_extended.h>
 }
 
+/* define buffer size for netmd downloads */
+#define NETMD_RECV_BUF_SIZE 0x10000
+
 class QMDTrack
 {
 public:
@@ -61,8 +64,11 @@ class QNetMDTrack : public QMDTrack {
     QString groupstring;
     QString titlestring;
     QString codecstring;
-
+private:
+    int blocks;
 public:
+    unsigned char bitrate_id;
+    unsigned char channel;
     QNetMDTrack(netmd_dev_handle *deviceh, minidisc * my_md, unsigned int trackindex);
     virtual unsigned int tracknum() const;
     virtual QString group() const;
@@ -70,6 +76,7 @@ public:
     virtual QString codecname() const;
     virtual QTime duration() const;
     virtual bool copyprotected() const;
+    virtual void setBlocks(int cnt);
     virtual int blockcount() const;
 };
 
-- 
1.8.0.msysgit.0

<-- thread -->
<-- date -->
  • Follow-Ups:
    • Re: [linux-minidisc] implementing netmd support in the gui application
      • From: Thomas Arp <manner.moe@gmx.de>
  • References:
    • Re: [linux-minidisc] implementing netmd support in the gui application
      • From: Thomas Arp <manner.moe@gmx.de>
    • Re: [linux-minidisc] implementing netmd support in the gui application
      • From: Thomas Arp <manner.moe@gmx.de>
  • linux-minidisc - January 2013 - Archives indexes sorted by:
    [ thread ] [ subject ] [ author ] [ date ]
  • Complete archive of the linux-minidisc mailing list
  • More info on this list...

Hilfe

  • FAQ
  • Dienstbeschreibung
  • ZEDAT Beratung
  • postmaster@lists.fu-berlin.de

Service-Navigation

  • Startseite
  • Listenauswahl

Einrichtung Mailingliste

  • ZEDAT-Portal
  • Mailinglisten Portal