You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
116 lines
3.8 KiB
116 lines
3.8 KiB
module bio.sff.writer;
|
|
|
|
import bio.sff.constants;
|
|
import bio.sff.utils.roundup;
|
|
|
|
import bio.core.utils.stream;
|
|
import undead.stream;
|
|
import std.system;
|
|
|
|
/// Class for outputting SFF files
|
|
class SffWriter {
|
|
|
|
/// Create new writer.
|
|
this(string filename, string flow_order, string key_sequence)
|
|
{
|
|
_filename = filename;
|
|
_flow_order = flow_order;
|
|
_key_seq = key_sequence;
|
|
|
|
auto f = new bio.core.utils.stream.File(filename, "wb+");
|
|
auto stream = new BufferedStream(f, 1024576);
|
|
_endian_stream = new EndianStream(stream, Endian.bigEndian);
|
|
|
|
writeHeader();
|
|
}
|
|
|
|
/// Flow order
|
|
string flow_order() @property const {
|
|
return _flow_order;
|
|
}
|
|
|
|
/// Key sequence
|
|
string key_sequence() @property const {
|
|
return _key_seq;
|
|
}
|
|
|
|
/// Add a read to the end of file
|
|
void append(R)(R sff_read) {
|
|
// compute read_header_length
|
|
ushort exact_read_header_length = cast(ushort)(16 + sff_read.name.length);
|
|
ushort read_header_length = roundup(exact_read_header_length);
|
|
|
|
_endian_stream.write(read_header_length);
|
|
_endian_stream.write(cast(ushort)sff_read.name.length);
|
|
_endian_stream.write(cast(uint)sff_read.bases.length);
|
|
_endian_stream.write(sff_read.clip_qual_left);
|
|
_endian_stream.write(sff_read.clip_qual_right);
|
|
_endian_stream.write(sff_read.clip_adapter_left);
|
|
_endian_stream.write(sff_read.clip_adapter_right);
|
|
_endian_stream.writeExact(sff_read.name.ptr, sff_read.name.length);
|
|
for (size_t i = 0; i < read_header_length - exact_read_header_length; ++i)
|
|
_endian_stream.write(cast(ubyte)0);
|
|
|
|
for (size_t i = 0; i < _flow_order.length; ++i)
|
|
_endian_stream.write(sff_read.flowgram_values[i]);
|
|
|
|
auto n_bases = sff_read.bases.length;
|
|
_endian_stream.writeExact(sff_read.flow_index_per_base.ptr, n_bases);
|
|
_endian_stream.writeExact(sff_read.bases.ptr, n_bases);
|
|
_endian_stream.writeExact(sff_read.quality_scores.ptr, n_bases);
|
|
|
|
auto k = 2 * _flow_order.length + 3 * n_bases;
|
|
auto padding = roundup(k) - k;
|
|
|
|
for (size_t i = 0; i < padding; ++i)
|
|
_endian_stream.write(cast(ubyte)0);
|
|
|
|
++_n_reads;
|
|
}
|
|
|
|
/// Flush all buffers and update number of reads in the file header
|
|
void finish() {
|
|
updateNumberOfReads();
|
|
_endian_stream.close();
|
|
}
|
|
|
|
private {
|
|
string _filename;
|
|
string _flow_order;
|
|
string _key_seq;
|
|
Stream _endian_stream;
|
|
|
|
uint _n_reads;
|
|
|
|
ushort _exact_header_len() @property const {
|
|
return cast(ushort)(31 + _flow_order.length + _key_seq.length);
|
|
}
|
|
|
|
ushort _header_len() @property const {
|
|
return roundup(_exact_header_len);
|
|
}
|
|
|
|
void writeHeader() {
|
|
_endian_stream.write(SFF_MAGIC);
|
|
_endian_stream.writeExact(SFF_VERSION.ptr, 4);
|
|
_endian_stream.write(0UL);
|
|
_endian_stream.write(0U);
|
|
_endian_stream.write(_n_reads);
|
|
_endian_stream.write(_header_len);
|
|
_endian_stream.write(cast(ushort)_key_seq.length);
|
|
_endian_stream.write(cast(ushort)_flow_order.length);
|
|
_endian_stream.write(cast(ubyte)1);
|
|
_endian_stream.writeExact(_flow_order.ptr, _flow_order.length);
|
|
_endian_stream.writeExact(_key_seq.ptr, _key_seq.length);
|
|
for (size_t i = 0; i < _header_len - _exact_header_len; ++i)
|
|
_endian_stream.write(cast(ubyte)0);
|
|
}
|
|
|
|
void updateNumberOfReads() {
|
|
auto old_pos = _endian_stream.position;
|
|
_endian_stream.position = 20;
|
|
_endian_stream.write(_n_reads);
|
|
_endian_stream.position = old_pos;
|
|
}
|
|
}
|
|
}
|
|
|