docs: function convert (buffer, from, to) {
  	//ensure formats are full
  	if (!isNormalized(from)) from = normalize(from)
  	if (!isNormalized(to)) to = normalize(to)
  
  	//convert buffer/alike to arrayBuffer
  	var data
  	if (buffer instanceof ArrayBuffer) {
  		data = buffer
  	}
  	else if (ArrayBuffer.isView(buffer)) {
  		if (buffer.byteOffset != null) data = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
  		else data = buffer.buffer;
  	}
  	else {
  		data = (new Uint8Array(buffer.length != null ? buffer : [buffer])).buffer
  	}
  
  	//ignore needless conversion
  	if (equal(from ,to)) {
  		return data
  	}
  
  	//create containers for conversion
  	var fromArray = new (arrayClass(from))(data)
  
  	//toArray is automatically filled with mapped values
  	//but in some cases mapped badly, e. g. float → int(round + rotate)
  	var toArray = new (arrayClass(to))(fromArray)
  
  	//if range differ, we should apply more thoughtful mapping
  	if (from.max !== to.max) {
  		fromArray.forEach(function (value, idx) {
  			//ignore not changed range
  			//bring to 0..1
  			var normalValue = (value - from.min) / (from.max - from.min)
  
  			//bring to new format ranges
  			value = normalValue * (to.max - to.min) + to.min
  
  			//clamp (buffers does not like values outside of bounds)
  			toArray[idx] = Math.max(to.min, Math.min(to.max, value))
  		})
  	}
  
  	//reinterleave, if required
  	if (from.interleaved != to.interleaved) {
  		var channels = from.channels
  		var len = Math.floor(fromArray.length / channels)
  
  		//deinterleave
  		if (from.interleaved && !to.interleaved) {
  			toArray = toArray.map(function (value, idx, data) {
  				var targetOffset = idx % len
  				var targetChannel = ~~(idx / len)
  
  				return data[targetOffset * channels + targetChannel]
  			})
  		}
  		//interleave
  		else if (!from.interleaved && to.interleaved) {
  			toArray = toArray.map(function (value, idx, data) {
  				var targetOffset = ~~(idx / channels)
  				var targetChannel = idx % channels
  
  				return data[targetChannel * len + targetOffset]
  			})
  		}
  	}
  
  	//ensure endianness
  	if (!to.float && from.byteOrder !== to.byteOrder) {
  		var le = to.byteOrder === 'LE'
  		var view = new DataView(toArray.buffer)
  		var step = to.bitDepth / 8
  		var methodName = 'set' + getDataViewSuffix(to)
  		for (var i = 0, l = toArray.length; i < l; i++) {
  			view[methodName](i*step, toArray[i], le)
  		}
  	}
  
  	return toArray.buffer
  }