@@ -353,6 +353,64 @@ inline std::vector<float> causal_context_mask_window(
353353
354354namespace engine ::codecs {
355355
356+ MossTokenRowBuilder::MossTokenRowBuilder (int64_t num_codebooks, int32_t audio_pad_token_id)
357+ : num_codebooks_(num_codebooks),
358+ audio_pad_token_id_ (audio_pad_token_id) {
359+ if (num_codebooks_ <= 0 ) {
360+ throw std::runtime_error (" MOSS token row builder requires a positive codebook count" );
361+ }
362+ }
363+
364+ void MossTokenRowBuilder::push_text_token (int32_t token_id) {
365+ rows_.text_tokens .push_back (token_id);
366+ rows_.audio_codes .insert (rows_.audio_codes .end (), static_cast <size_t >(num_codebooks_), audio_pad_token_id_);
367+ }
368+
369+ void MossTokenRowBuilder::push_text_tokens (const std::vector<int32_t > & token_ids) {
370+ for (const int32_t token_id : token_ids) {
371+ push_text_token (token_id);
372+ }
373+ }
374+
375+ void MossTokenRowBuilder::push_audio_row (int32_t text_slot_token_id, const int32_t * codes, int64_t num_codebooks) {
376+ if (num_codebooks != num_codebooks_) {
377+ throw std::runtime_error (" MOSS audio row codebook count mismatch" );
378+ }
379+ if (codes == nullptr ) {
380+ throw std::runtime_error (" MOSS audio row codes are missing" );
381+ }
382+ rows_.text_tokens .push_back (text_slot_token_id);
383+ rows_.audio_codes .insert (rows_.audio_codes .end (), codes, codes + num_codebooks);
384+ }
385+
386+ void MossTokenRowBuilder::push_audio_row (
387+ int32_t text_slot_token_id,
388+ const std::vector<std::vector<int32_t >> & codes,
389+ int64_t frame) {
390+ if (static_cast <int64_t >(codes.size ()) != num_codebooks_) {
391+ throw std::runtime_error (" MOSS audio row codebook count mismatch" );
392+ }
393+ rows_.text_tokens .push_back (text_slot_token_id);
394+ for (int64_t codebook = 0 ; codebook < num_codebooks_; ++codebook) {
395+ const auto & channel = codes[static_cast <size_t >(codebook)];
396+ if (frame < 0 || static_cast <size_t >(frame) >= channel.size ()) {
397+ throw std::runtime_error (" MOSS audio row frame index is out of range" );
398+ }
399+ rows_.audio_codes .push_back (channel[static_cast <size_t >(frame)]);
400+ }
401+ }
402+
403+ MossTokenRows MossTokenRowBuilder::finish () {
404+ if (rows_.text_tokens .empty ()) {
405+ throw std::runtime_error (" MOSS token rows must not be empty" );
406+ }
407+ if (static_cast <int64_t >(rows_.audio_codes .size ()) !=
408+ static_cast <int64_t >(rows_.text_tokens .size ()) * num_codebooks_) {
409+ throw std::runtime_error (" MOSS token rows audio code shape mismatch" );
410+ }
411+ return std::move (rows_);
412+ }
413+
356414// Dequantizes MOSS-Audio-Tokenizer-v2 codes (RLFQ) into the codec's continuous
357415// latent, i.e. the input to the codec decoder stack. Codes are the
358416// [num_quantizers, steps] matrix produced by generation; the returned latent is
0 commit comments