Как прочитать данные типа UInt8(Objective-C) в byte(Java)?

247
26 октября 2017, 07:15

Извините, но я не знаю даже, как правильно вопрос задать.
Нужно сделать тестовое задание на языке Java для Android. Суть следующая. Есть закодированный файл "File.TRK", этот файл состоит из списка нот, как мне сказали. Дали поля для ноты, но эти поля из Objective-C:

@property (nonatomic) Float64 timeStamp;
@property (nonatomic) UInt8 status;
@property (nonatomic) UInt8 notenum;
@property (nonatomic) UInt8 velocity;
@property (nonatomic) UInt8 trackN;
@property (nonatomic) Float32 duration;
@property (nonatomic) UInt16 scoreBits;

В своем проекте Java для модельки ноты я сделал такие поля с соответствующими геттерами и сеттерами:

private double timeStamp; //8 байт
private byte status;  //1 байт
private byte notenum;  //1 байт
private byte velocity;  //1 байт
private byte trackN;   //1 байт
private float duration;  //4 байта
private short scoreBits;  //2 байта
//суммарно каждая нота  = 18 байтам

Далее я получаю байты моего закодированного файла:

byte[] bytesFile = loadBytes("File.TRK");
private byte[] loadBytes(String s) {
        byte[] bytes = new byte[0];
        try {
            InputStream stream = getAssets().open(s);
            try {
                bytes = IOUtils.toByteArray(stream);
            } finally {
                stream.close();
            }
        } catch (IOException e) {
            Log.d("logs", "not load");
        }
        return bytes;
    }

На этом моменте логи показывают, что длина моего массива bytesFile = 4752 (я так понимаю 4752/18 = 264 ноты. Т.е. мой закодированный файл состоит из 264 нот)
Далее методом setNotes() я заношу каждую ноту в ArrayList.

List<Note> notesFile = new ArrayList<>();
setNotes(bytesFile, notesFile);
private void setNotes(byte[] bytes, List<Note> list) {
        for (int a=0; a<bytesFile.length; a+=18){
            Note note = new Note();
            double myTimeStamp=ByteBuffer.wrap(Arrays.copyOfRange(bytes , a, a+8)).getDouble();
            float myDuration=ByteBuffer.wrap(Arrays.copyOfRange(bytes , a+12, a+16)).getFloat();
            short myScoreBits=ByteBuffer.wrap(Arrays.copyOfRange(bytes , a+16, a+18)).getShort();
            note.setTimeStamp(myTimeStamp);
            note.setStatus(bytes[a+8]);
            note.setNotenum(bytes[a+9]);
            note.setVelocity(bytes[a+10]);
            note.setTrackN(bytes[a+11]);
            note.setDuration(myDuration);
            note.setScoreBits(myScoreBits);
            list.add(note);
        }
    }

Логи показывают, что в списке нот содержится 264 ноты, все хорошо. Но затем, когда я в логах вывожу каждую ноту, то получаю вот такой результат (далее покажу первые 5 нот):

1 нота - timeStamp-1.469233414E-314, status-0, notenum-0, velocity-0, trackN-0, duration--32.75, scoreBits--25564
2 нота - timeStamp-2.052246093756482, status-0, notenum-0, velocity--100, trackN-38, duration-2.2061368E12, scoreBits-0
3 нота - -3.2944383806221925E-82, status-112, notenum-0, velocity-0, trackN-0, duration-4.725109E-13, scoreBits--25813
4 нота - 6.978446977931939E38, status-0, notenum-0, velocity--102, trackN-48, duration-2.006836, scoreBits-0
5 нота - 2.588782193414443E-183, status-107, notenum-0, velocity-0, trackN-0, duration--1.0570736E-28, scoreBits--25816

Для вывода ноты в логи я переопределил метод toString() в модельке ноты:

@Override
    public String toString() {
        return "timeStamp-"+getTimeStamp()+", status-"+getStatus()+", notenum-"+getNotenum()+", velocity-"+getVelocity()+
                ", trackN-"+getTrackN()+", duration-"+getDuration()+", scoreBits-"+getScoreBits();
    }

Суть моего задания в том, что мне нужно проиграть эту мелодию из нот. Но я не понимаю, почему в полях многих нот у меня встречаются отрицательные значения. Разве такое может быть? Все ли я делаю правильно? У меня вообще есть один из вариантов, что надо мной жестоко стебуться :) хеееелп, плиз!)

Answer 1

UInt8 -- беззнаковый тип (unsigned int), а byte в Java со знаком. Думаю, поэтому при побайтовом чтении у Вас получаются отрицательные числа.

Answer 2

Вам не должно быть разницы как это хранится в виде signed byte или unsigned byte. Если уж так хочется видеть на выдаче беззнаковые байтовые поля ноты, то надо сделать что-то типа:

private int byteToUnsignedInt(byte b) {
   return b & 0xFF;
}
@Override
public String toString() {
    return "timeStamp-"+getTimeStamp()+", status-"+byteToUnsignedInt(getStatus())+", notenum-"+byteToUnsignedInt(getNotenum())+", velocity-"+byteToUnsignedInt(getVelocity())+
            ", trackN-"+byteToUnsignedInt(getTrackN())+", duration-"+getDuration()+", scoreBits-"+getScoreBits();
}

Тогда в выдаче вы увидите беззнаковые байты

Правда, что это вам даст? Вы знаете как их интерпретировать и что с ними надо делать проигрывателю ваших нот?

READ ALSO
Проектирование кода: использование return в switch

Проектирование кода: использование return в switch

Какой код с точки зрения проектирования более правильный

178
Spring BCryptPasswordEncoder некорректно работает

Spring BCryptPasswordEncoder некорректно работает

Я использую BCryptPasswordEncoder для шифрования пароля при регистрации на сайтеНо есть проблема, при логине пароль пользователя не подтверждается

226
Отловить первый запуск приложения

Отловить первый запуск приложения

Объясните пожалуйста в теории, как отловить первый запуск приложения? Читал тут, не то, все слишком громоздко

233
Считывание текста из файла в нужной кодировке

Считывание текста из файла в нужной кодировке

Необходимо считать строки из файла и записать их в массив, а потом отобразить на лейблеНо почему-то русскую кодировку не распознает

308