Как установить 24-битное целое число со знаком в DataView?

Я нашел это, но это для 24-битных целых чисел без знака:

DataView.prototype.setUint24 = function(pos, val) {
    this.setUint16(pos, val >> 8);
    this.setUint8(pos+2, val & ~4294967040); // this "magic number" masks off the first 16 bits
}

Простое изменение setUint16 на setInt16 и setUint8 на setInt8 не работает. Мои знания о низкоуровневых двоичных файлах очень ограничены, поэтому мне нужна помощь. Я понимаю большую часть этой функции:

  • val >> 8 хранит только первые 16 бит в виде 16-битного
  • pos + 2 потому что 16-битное целое занимает 2 байта с точки зрения пространства
  • Что касается val & ~4294967040, то есть комментарий, лол.

Я не слишком уверен, почему простое изменение вызовов методов, которые устанавливают значение со знаком, не работает/я не слишком уверен, почему процесс отличается при установке значений со знаком/без знака.


person maximedupre    schedule 14.02.2017    source источник
comment
val & ~4294967040 глупо; val & 0xff будет намного читабельнее. В любом случае, setUint24 должно работать для целых чисел со знаком без изменений.   -  person Ry-♦    schedule 14.02.2017
comment
@Ryan Мне бы по крайней мере нужно было использовать setInt16 и setInt8 вместо их неподписанной альтернативы, верно? Я думаю, что-то еще не так с моим кодом, тогда...   -  person maximedupre    schedule 14.02.2017
comment
Нет, должно работать без изменений.   -  person Ry-♦    schedule 14.02.2017
comment
Итак, я хочу установить 24-битное целое число со знаком, но с помощью методов для установки целого числа без знака 16 и 8 работает? Я в замешательстве, но я уже был в замешательстве до твоего ответа, так что, думаю, это ничего не меняет.   -  person maximedupre    schedule 14.02.2017
comment
Целочисленные типы JavaScript — это 32-битные целые числа со знаком и без знака… вроде бы. Все, что вы получаете от побитового оператора, представляет собой 32-битное целое число. Результат подписывается всеми операторами, кроме >>>, который дает беззнаковый результат. Если вы обрабатываете 32-битное целое со знаком как 32-битное целое без знака и маскируете его до 24 бит, результат будет таким же, как маскирование знакового до 24 бит, и эта реализация setUint24 на самом деле не делает ничего особенного для беззнакового. целые числа. Так что я уверен, что это должно просто работать. Хотя, может, и нет.   -  person Ry-♦    schedule 14.02.2017
comment
на самом деле маска во второй строке совершенно не нужна, так как this.setUint8(pos+2, val) уже маскирует правильные байты. Как и первая строка, setUint16() игнорирует первые 2 байта переданного int32 и использует только последние 2 байта.   -  person Thomas    schedule 14.02.2017
comment
Я не знаю, имеет ли это значение, но передается int24, а не int32. Разве он не получит первый байт вместо последнего без маски?   -  person maximedupre    schedule 14.02.2017
comment
@maximedupre >> в val >> 8 всегда создает int32; JS знает только int32 и 64-битные числа с плавающей запятой. So I want to set a signed 24-bit integer, but using the methods to set an unsigned 16 and 8 integer works? знаковые и беззнаковые целые используют одни и те же биты, только интерпретация отличается. Для простоты давайте поговорим о int8 и uint8: значения -128 .. -1 имеют те же биты, что и значения 128 .. 255. Настоящая разница будет в функциях getUint24 и getInt24(), где вы должны различать, является ли ведущий бит знаком или нет, и соответственно интерпретировать остальные биты.   -  person Thomas    schedule 14.02.2017


Ответы (1)


Как прокомментировали @Ryan и @Thomas, этот метод работает. Я думал, что это не работает, потому что wav-файл, который я создавал, был чистым белым шумом. Оказывается, хотя этот метод работает, он может устанавливать байты в неправильном порядке (что проблематично для wav-файлов, но не для других обработок). См. есть ли что-то особенное, что мне нужно сделать, чтобы создать 24-битный файл WAV? для получения дополнительной информации.

person maximedupre    schedule 15.02.2017