// ----
// ---- file   : AR_Sound.cpp
// ---- author : Bastian Spiegel <bs@tkscript.de>
// ---- legal  : (c) 2017 by Bastian Spiegel. 
// ----          Distributed under terms of the GNU LESSER GENERAL PUBLIC LICENSE (LGPL). See 
// ----          http://www.gnu.org/licenses/licenses.html#LGPL or COPYING for further information.
// ----
// ---- info   : This is part of the "tkanalogrytm" plugin.
// ----
// ---- changed: 21Aug2017
// ----
// ----
// ----

#include "tkanalogrytm.h"


AR_Sound::AR_Sound(void) {
   current_buf = NULL;
}

AR_Sound::~AR_Sound() {
}

void YAC_VCALL AR_Sound::yacOperator(sSI _cmd, YAC_Object *_robj, YAC_Value *_r) {
   if(YAC_OP_ASSIGN == _cmd)
   {
      if(YAC_CHK(_robj, clid_AR_Sound))
      {
         YAC_CAST_ARG(AR_Sound, o, _robj);

         memcpy(syx, o->syx, AR_SOUND_SYX_SZ);
         memcpy(raw, o->raw, AR_SOUND_SZ);

         if(o->current_buf == o->syx)
         {
            current_buf = syx;
         }
         else if(o->current_buf == o->raw)
         {
            current_buf = raw;
         }
         else
         {
            current_buf = NULL;
         }
      }
   }
   else
   {
      YAC_Object::yacOperator(_cmd, _robj, _r);
   }
}

sUI AR_Sound::getRequiredSizeSyx(void) {
   return AR_SOUND_SYX_SZ;
}

sUI AR_Sound::getRequiredSizeRaw(void) {
   return AR_SOUND_SZ;
}

sSI AR_Sound::getCurrentDataIdx(void) {
   if(syx == current_buf)
   {
      return 1;
   }
   else if(raw == current_buf)
   {
      return 2;
   }
   else
   {
      return 0;
   }
}

void AR_Sound::saveSyxToStream(YAC_Object *_ofs) {
   if(YAC_IS_STREAM(_ofs))
   {
      _ofs->yacStreamWriteI16(1); // version

      _ofs->yacStreamWriteI16(AR_SOUND_SYX_SZ);

      for(sUI i=0; i < AR_SOUND_SYX_SZ; i++)
      {
         _ofs->yacStreamWriteI8(syx[i]);
      }
   }
}

void AR_Sound::saveRawToStream(YAC_Object *_ofs) {
   if(YAC_IS_STREAM(_ofs))
   {
      _ofs->yacStreamWriteI16(1); // version

      _ofs->yacStreamWriteI16(AR_SOUND_SZ);

      for(sUI i=0; i < AR_SOUND_SZ; i++)
      {
         _ofs->yacStreamWriteI8(raw[i]);
      }
   }
}

sBool AR_Sound::loadSyxFromStream(YAC_Object *_ifs) {
   if(YAC_IS_STREAM(_ifs))
   {
      sU16 ver = _ifs->yacStreamReadI16();

      if(ver >= 1u)
      {
         sU16 sz = _ifs->yacStreamReadI16();

         if(AR_SOUND_SYX_SZ == sz)
         {
            for(sUI i=0; i < AR_SOUND_SYX_SZ; i++)
            {
               syx[i] = _ifs->yacStreamReadI8();
            }

            current_buf = syx;

            // Succeeded
            return YAC_TRUE;
         }
         else
         {
            yac_host->printf("[---] AR_Sound::loadSyxFromStream: bad sz=%u\n", sz);
         }
      }
      else
      {
         yac_host->printf("[---] AR_Sound::loadSyxFromStream: bad ver=%u\n", ver);
      }
   }

   // Failed
   return YAC_FALSE;
}

sBool AR_Sound::loadRawFromStream(YAC_Object *_ifs) {
   if(YAC_IS_STREAM(_ifs))
   {
      sU16 ver = _ifs->yacStreamReadI16();

      if(ver >= 1u)
      {
         sU16 sz = _ifs->yacStreamReadI16();

         if(AR_SOUND_SZ == sz)
         {
            for(sUI i=0; i < AR_SOUND_SZ; i++)
            {
               raw[i] = _ifs->yacStreamReadI8();
            }

            current_buf = raw;

            // Succeeded
            return YAC_TRUE;
         }
         else
         {
            yac_host->printf("[---] AR_Sound::loadRawFromStream: bad sz=%u\n", sz);
         }
      }
      else
      {
         yac_host->printf("[---] AR_Sound::loadRawFromStream: bad ver=%u\n", ver);
      }
   }

   // Failed
   return YAC_FALSE;
}

sBool AR_Sound::addSoundRequestX(YAC_Buffer *_d, sUI _devId, sUI _soundNr) {
   sBool ret = YAC_FALSE;

   if(YAC_Is_Buffer(_d))
   {
      if((_d->io_offset + AR_SYSEX_REQUEST_MSG_SZ) <= _d->size)
      {
         if(AR_ERR_OK == ar_sound_request_x(_d->buffer + _d->io_offset, _devId&127u, _soundNr&127u))
         {
            _d->io_offset += AR_SYSEX_REQUEST_MSG_SZ;

            // Succeeded
            ret = YAC_TRUE;
         }
      }
   }

   return ret;
}

sBool AR_Sound::syxToRaw(YAC_Buffer *_s) {
   sBool ret = YAC_FALSE;

   if(YAC_Is_Buffer(_s))
   {
      if(_s->size >= AR_SOUND_SYX_SZ)
      {
         const sU8 *srcBuf = _s->buffer;
         sU32 srcBufSz = _s->io_offset;

         sU32 retRawBufSz = AR_SOUND_SZ;

         ar_sysex_meta_t meta;

         if(AR_ERR_OK == ar_sysex_to_raw(raw, &srcBuf, &srcBufSz, &retRawBufSz, &meta))
         {
            // Succeeded
            ret = YAC_TRUE;

            yac_host->printf("[dbg] AR_Sound::syxToRaw: OK, retRawBufSz=%u.\n", retRawBufSz);

            current_buf = raw;
         }
         else
         {
            yac_host->printf("[---] AR_Sound::syxToRaw: ar_sysex_to_raw() failed.\n");
            current_buf = NULL;
         }
      }
      else
      {
         yac_host->printf("[---] AR_Sound::syxToRaw: source buffer too small (have=%u, need=%u).\n", _s->size, AR_SOUND_SYX_SZ);
         current_buf = NULL;
      }
   }

   return ret;
}

sBool AR_Sound::copyFromKitTrack(YAC_Object *_kit, sUI _srcTrackIdx) {
   if(YAC_CHK(_kit, clid_AR_Kit))
   {
      YAC_CAST_ARG(AR_Kit, o, _kit);

      if(2u == o->ar_kit_version)
      {
         const ar_kit_t *datO = (const ar_kit_t *)o->raw;
         ar_sound_t *dat = (ar_sound_t *)raw;

         memcpy((void*)dat, &datO->tracks[_srcTrackIdx % 12], sizeof(ar_sound_t));

         return YAC_TRUE;
      }
   }
   return YAC_FALSE;
}

sBool AR_Sound::sendSound(YAC_Buffer *_d, sUI _devId, sUI _soundNr, sBool _bEditBuf) {
   sBool ret = YAC_FALSE;

   if(YAC_Is_Buffer(_d))
   {
      if(_d->size >= AR_SOUND_SYX_SZ)
      {
         sU8 *dstBuf = _d->buffer;
         sU32 retSyxBufSz = 0;
         ar_sysex_meta_t meta;

         AR_SYSEX_META_INIT(meta, _devId, AR_TYPE_SOUND, ((_bEditBuf ? 128u : 0u) + (_soundNr & 127u)));

         if(current_buf == raw)
         {
            if(AR_ERR_OK == ar_raw_to_sysex(dstBuf, raw, AR_SOUND_SZ, &retSyxBufSz, &meta))
            {
               _d->io_offset = retSyxBufSz;

               // Succeeded
               ret = YAC_TRUE;
              
               yac_host->printf("[dbg] AR_Sound::sendSound: OK, retSyxBufSz=%u.\n", retSyxBufSz);
            }
            else
            {
               yac_host->printf("[---] AR_Sound::sendSound: ar_raw_to_sysex() failed\n");
            }
         }
         else
         {
            yac_host->printf("[---] AR_Sound::sendSound: current_buf != raw\n");
         }
      }
      else
      {
         yac_host->printf("[---] AR_Sound::sendSound: dest buffer too small (have=%u, need=%u).\n", _d->size, AR_SOUND_SYX_SZ);
      }

   }

   return ret;
}

sBool AR_Sound::getRawBuffer(YAC_Buffer *_ret) {
   sBool ret = YAC_FALSE;

   if(YAC_Is_Buffer(_ret))
   {
      // Free previous contents (if any)
      _ret->yacArrayAlloc(0, 0, 0, 0);

      _ret->size      = AR_SOUND_SZ;
      _ret->io_offset = AR_SOUND_SZ;
      _ret->buffer    = raw;
      _ret->deleteme  = YAC_FALSE;

      ret = YAC_TRUE;
   }

   return ret;
}
