Re: [linux-minidisc] implementing netmd support in the gui application
- 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,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
- Follow-Ups:
- 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
- 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>
- Re: [linux-minidisc] implementing netmd support in the gui application
-
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...

