text: /*************************************************************************/
  /*  editor_sample_import_plugin.cpp                                      */
  /*************************************************************************/
  /*                       This file is part of:                           */
  /*                           GODOT ENGINE                                */
  /*                    http://www.godotengine.org                         */
  /*************************************************************************/
  /* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur.                 */
  /*                                                                       */
  /* Permission is hereby granted, free of charge, to any person obtaining */
  /* a copy of this software and associated documentation files (the       */
  /* "Software"), to deal in the Software without restriction, including   */
  /* without limitation the rights to use, copy, modify, merge, publish,   */
  /* distribute, sublicense, and/or sell copies of the Software, and to    */
  /* permit persons to whom the Software is furnished to do so, subject to */
  /* the following conditions:                                             */
  /*                                                                       */
  /* The above copyright notice and this permission notice shall be        */
  /* included in all copies or substantial portions of the Software.       */
  /*                                                                       */
  /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       */
  /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    */
  /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  */
  /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  */
  /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
  /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
  /*************************************************************************/
  #include "editor_sample_import_plugin.h"
  #include "tools/editor/editor_file_dialog.h"
  #include "tools/editor/editor_dir_dialog.h"
  #include "tools/editor/editor_node.h"
  #include "tools/editor/property_editor.h"
  #include "scene/resources/sample.h"
  #include "io/resource_saver.h"
  #include "os/file_access.h"
  #include "io/marshalls.h"
  #include "tools/editor/editor_settings.h"
  
  class _EditorSampleImportOptions : public Object {
  
  	OBJ_TYPE(_EditorSampleImportOptions,Object);
  public:
  
  	enum CompressMode {
  		COMPRESS_MODE_DISABLED,
  		COMPRESS_MODE_RAM,
  		COMPRESS_MODE_DISK
  	};
  
  	enum CompressBitrate {
  		COMPRESS_64,
  		COMPRESS_96,
  		COMPRESS_128,
  		COMPRESS_192
  	};
  
  	bool force_8_bit;
  	bool force_mono;
  	bool force_rate;
  	float force_rate_hz;
  
  	bool edit_trim;
  	bool edit_normalize;
  	bool edit_loop;
  
  	CompressMode compress_mode;
  	CompressBitrate compress_bitrate;
  
  
  	bool _set(const StringName& p_name, const Variant& p_value) {
  
  		String n = p_name;
  		if (n=="force/8_bit")
  			force_8_bit=p_value;
  		else if (n=="force/mono")
  			force_mono=p_value;
  		else if (n=="force/max_rate")
  			force_rate=p_value;
  		else if (n=="force/max_rate_hz")
  			force_rate_hz=p_value;
  		else if (n=="edit/trim")
  			edit_trim=p_value;
  		else if (n=="edit/normalize")
  			edit_normalize=p_value;
  		else if (n=="edit/loop")
  			edit_loop=p_value;
  		else if (n=="compress/mode")
  			compress_mode=CompressMode(int(p_value));
  		else if (n=="compress/bitrate")
  			compress_bitrate=CompressBitrate(int(p_value));
  		else
  			return false;
  
  		return true;
  
  	}
  
  	bool _get(const StringName& p_name,Variant &r_ret) const{
  
  		String n = p_name;
  		if (n=="force/8_bit")
  			r_ret=force_8_bit;
  		else if (n=="force/mono")
  			r_ret=force_mono;
  		else if (n=="force/max_rate")
  			r_ret=force_rate;
  		else if (n=="force/max_rate_hz")
  			r_ret=force_rate_hz;
  		else if (n=="edit/trim")
  			r_ret=edit_trim;
  		else if (n=="edit/normalize")
  			r_ret=edit_normalize;
  		else if (n=="edit/loop")
  			r_ret=edit_loop;
  		else if (n=="compress/mode")
  			r_ret=compress_mode;
  		else if (n=="compress/bitrate")
  			r_ret=compress_bitrate;
  		else
  			return false;
  
  		return true;
  
  	}
  	void _get_property_list( List<PropertyInfo> *p_list) const{
  
  		p_list->push_back(PropertyInfo(Variant::BOOL,"force/8_bit"));
  		p_list->push_back(PropertyInfo(Variant::BOOL,"force/mono"));
  		p_list->push_back(PropertyInfo(Variant::BOOL,"force/max_rate"));
  		p_list->push_back(PropertyInfo(Variant::REAL,"force/max_rate_hz",PROPERTY_HINT_EXP_RANGE,"11025,192000,1"));
  		p_list->push_back(PropertyInfo(Variant::BOOL,"edit/trim"));
  		p_list->push_back(PropertyInfo(Variant::BOOL,"edit/normalize"));
  		p_list->push_back(PropertyInfo(Variant::BOOL,"edit/loop"));
  		p_list->push_back(PropertyInfo(Variant::INT,"compress/mode",PROPERTY_HINT_ENUM,"Disabled,RAM (Ima-ADPCM)"));
  		//p_list->push_back(PropertyInfo(Variant::INT,"compress/bitrate",PROPERTY_HINT_ENUM,"64,96,128,192"));
  
  
  	}
  
  
  	static void _bind_methods() {
  
  
  		ADD_SIGNAL( MethodInfo("changed"));
  	}
  
  
  	_EditorSampleImportOptions() {
  
  		force_8_bit=false;
  		force_mono=false;
  		force_rate=true;
  		force_rate_hz=44100;
  
  		edit_trim=true;
  		edit_normalize=true;
  		edit_loop=false;
  
  		compress_mode=COMPRESS_MODE_RAM;
  		compress_bitrate=COMPRESS_128;
  	}
  
  
  };
  
  class EditorSampleImportDialog : public ConfirmationDialog {
  
  	OBJ_TYPE(EditorSampleImportDialog,ConfirmationDialog);
  
  	EditorSampleImportPlugin *plugin;
  
  	LineEdit *import_path;
  	LineEdit *save_path;
  	EditorFileDialog *file_select;
  	EditorDirDialog *save_select;
  	ConfirmationDialog *error_dialog;
  	PropertyEditor *option_editor;
  
  	_EditorSampleImportOptions *options;
  
  
  public:
  
  	void _choose_files(const Vector<String>& p_path) {
  
  		String files;
  		for(int i=0;i<p_path.size();i++) {
  
  			if (i>0)
  				files+=",";
  			files+=p_path[i];
  		}
  		/*
  		if (p_path.size()) {
  			String srctex=p_path[0];
  			String ipath = EditorImportDB::get_singleton()->find_source_path(srctex);
  
  			if (ipath!="")
  				save_path->set_text(ipath.get_base_dir());
  		}*/
  		import_path->set_text(files);
  
  	}
  	void _choose_save_dir(const String& p_path) {
  
  		save_path->set_text(p_path);
  	}
  
  	void _browse() {
  
  		file_select->popup_centered_ratio();
  	}
  
  	void _browse_target() {
  
  		save_select->popup_centered_ratio();
  
  	}
  
  
  	void popup_import(const String& p_path) {
  
  		popup_centered(Size2(400,400));
  		if (p_path!="") {
  
  			Ref<ResourceImportMetadata> rimd = ResourceLoader::load_import_metadata(p_path);
  			ERR_FAIL_COND(!rimd.is_valid());
  
  			save_path->set_text(p_path.get_base_dir());
  			List<String> opts;
  			rimd->get_options(&opts);
  			for(List<String>::Element *E=opts.front();E;E=E->next()) {
  
  				options->_set(E->get(),rimd->get_option(E->get()));
  			}
  
  			String src = "";
  			for(int i=0;i<rimd->get_source_count();i++) {
  				if (i>0)
  					src+=",";
  				src+=EditorImportPlugin::expand_source_path(rimd->get_source_path(i));
  			}
  			import_path->set_text(src);
  		}
  	}
  
  
  	void _import() {
  
  		Vector<String> samples = import_path->get_text().split(",");
  
  		if (samples.size()==0) {
  			error_dialog->set_text(TTR("No samples to import!"));
  			error_dialog->popup_centered(Size2(200,100));
  		}
  
  		if (save_path->get_text().strip_edges()=="") {
  			error_dialog->set_text(TTR("Target path is empty."));
  			error_dialog->popup_centered_minsize();
  			return;
  		}
  
  		if (!save_path->get_text().begins_with("res://")) {
  			error_dialog->set_text(TTR("Target path must be full resource path."));
  			error_dialog->popup_centered_minsize();
  			return;
  		}
  
  		if (!DirAccess::exists(save_path->get_text())) {
  			error_dialog->set_text(TTR("Target path must exist."));
  			error_dialog->popup_centered_minsize();
  			return;
  		}
  
  		for(int i=0;i<samples.size();i++) {
  
  			Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
  
  			List<PropertyInfo> pl;
  			options->_get_property_list(&pl);
  			for(List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
  
  				Variant v;
  				String opt=E->get().name;
  				options->_get(opt,v);
  				imd->set_option(opt,v);
  
  			}
  
  			imd->add_source(EditorImportPlugin::validate_source_path(samples[i]));
  
  			String dst = save_path->get_text();
  			if (dst=="") {
  				error_dialog->set_text(TTR("Save path is empty!"));
  				error_dialog->popup_centered(Size2(200,100));
  			}
  
  			dst = dst.plus_file(samples[i].get_file().basename()+".smp");
  
  			Error err = plugin->import(dst,imd);
  		}
  
  		hide();
  
  	}
  
  
  	void _notification(int p_what) {
  
  
  		if (p_what==NOTIFICATION_ENTER_TREE) {
  
  			option_editor->edit(options);
  		}
  	}
  
  	static void _bind_methods() {
  
  
  		ObjectTypeDB::bind_method("_choose_files",&EditorSampleImportDialog::_choose_files);
  		ObjectTypeDB::bind_method("_choose_save_dir",&EditorSampleImportDialog::_choose_save_dir);
  		ObjectTypeDB::bind_method("_import",&EditorSampleImportDialog::_import);
  		ObjectTypeDB::bind_method("_browse",&EditorSampleImportDialog::_browse);
  		ObjectTypeDB::bind_method("_browse_target",&EditorSampleImportDialog::_browse_target);
  	//	ADD_SIGNAL( MethodInfo("imported",PropertyInfo(Variant::OBJECT,"scene")) );
  	}
  
  	EditorSampleImportDialog(EditorSampleImportPlugin *p_plugin) {
  
  		plugin=p_plugin;
  
  
  		set_title(TTR("Import Audio Samples"));
  
  		VBoxContainer *vbc = memnew( VBoxContainer );
  		add_child(vbc);
  		set_child_rect(vbc);
  
  
  		HBoxContainer *hbc = memnew( HBoxContainer );
  		vbc->add_margin_child(TTR("Source Sample(s):"),hbc);
  
  		import_path = memnew( LineEdit );
  		import_path->set_h_size_flags(SIZE_EXPAND_FILL);
  		hbc->add_child(import_path);
  
  		Button * import_choose = memnew( Button );
  		import_choose->set_text(" .. ");
  		hbc->add_child(import_choose);
  
  		import_choose->connect("pressed", this,"_browse");
  
  		hbc = memnew( HBoxContainer );
  		vbc->add_margin_child(TTR("Target Path:"),hbc);
  
  		save_path = memnew( LineEdit );
  		save_path->set_h_size_flags(SIZE_EXPAND_FILL);
  		hbc->add_child(save_path);
  
  		Button * save_choose = memnew( Button );
  		save_choose->set_text(" .. ");
  		hbc->add_child(save_choose);
  
  		save_choose->connect("pressed", this,"_browse_target");
  
  		file_select = memnew(EditorFileDialog);
  		file_select->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  		add_child(file_select);
  		file_select->set_mode(EditorFileDialog::MODE_OPEN_FILES);
  		file_select->connect("files_selected", this,"_choose_files");
  		file_select->add_filter("*.wav ; MS Waveform");
  		save_select = memnew(	EditorDirDialog );
  		add_child(save_select);
  
  	//	save_select->set_mode(EditorFileDialog::MODE_OPEN_DIR);
  		save_select->connect("dir_selected", this,"_choose_save_dir");
  
  		get_ok()->connect("pressed", this,"_import");
  		get_ok()->set_text(TTR("Import"));
  
  
  		error_dialog = memnew ( ConfirmationDialog );
  		add_child(error_dialog);
  		error_dialog->get_ok()->set_text(TTR("Accept"));
  	//	error_dialog->get_cancel()->hide();
  
  		set_hide_on_ok(false);
  		options = memnew( _EditorSampleImportOptions );
  
  		option_editor = memnew( PropertyEditor );
  		option_editor->hide_top_label();
  		vbc->add_margin_child(TTR("Options:"),option_editor,true);
  	}
  
  	~EditorSampleImportDialog() {
  		memdelete(options);
  	}
  
  };
  
  
  String EditorSampleImportPlugin::get_name() const {
  
  	return "sample";
  }
  String EditorSampleImportPlugin::get_visible_name() const{
  
  	return TTR("Audio Sample");
  }
  void EditorSampleImportPlugin::import_dialog(const String& p_from){
  
  	dialog->popup_import(p_from);
  }
  Error EditorSampleImportPlugin::import(const String& p_path, const Ref<ResourceImportMetadata>& p_from){
  
  	ERR_FAIL_COND_V(p_from->get_source_count()!=1,ERR_INVALID_PARAMETER);
  
  	Ref<ResourceImportMetadata> from=p_from;
  
  	String src_path=EditorImportPlugin::expand_source_path(from->get_source_path(0));
  	Ref<Sample> smp = ResourceLoader::load(src_path);
  	ERR_FAIL_COND_V(smp.is_null(),ERR_CANT_OPEN);
  
  
  	float rate = smp->get_mix_rate();
  	bool is16 = smp->get_format()==Sample::FORMAT_PCM16;
  	int chans = smp->is_stereo()?2:1;
  	int len = smp->get_length();
  	Sample::LoopFormat loop= smp->get_loop_format();
  	int loop_beg = smp->get_loop_begin();
  	int loop_end = smp->get_loop_end();
  
  	print_line("Input Sample: ");
  	print_line("\tlen: "+itos(len));
  	print_line("\tchans: "+itos(chans));
  	print_line("\t16bits: "+itos(is16));
  	print_line("\trate: "+itos(rate));
  	print_line("\tloop: "+itos(loop));
  	print_line("\tloop begin: "+itos(loop_beg));
  	print_line("\tloop end: "+itos(loop_end));
  	Vector<float> data;
  	data.resize(len*chans);
  
  	{
  		DVector<uint8_t> src_data = smp->get_data();
  		DVector<uint8_t>::Read sr = src_data.read();
  
  
  		for(int i=0;i<len*chans;i++) {
  
  			float s=0;
  			if (is16) {
  
  				int16_t i16 = decode_uint16(&sr[i*2]);
  				s=i16/32767.0;
  			} else {
  
  				int8_t i8 = sr[i];
  				s=i8/127.0;
  			}
  			data[i]=s;
  		}
  	}
  
  	//apply frequency limit
  
  	bool limit_rate = from->get_option("force/max_rate");
  	int limit_rate_hz = from->get_option("force/max_rate_hz");
  	if (limit_rate && rate > limit_rate_hz) {
  		//resampleeee!!!
  		int new_data_len = len * limit_rate_hz / rate;
  		Vector<float> new_data;
  		new_data.resize( new_data_len * chans );
  		for(int c=0;c<chans;c++) {
  
  			for(int i=0;i<new_data_len;i++) {
  
  				//simple cubic interpolation should be enough.
  				float pos = float(i) * len / new_data_len;
  				float mu = pos-Math::floor(pos);
  				int ipos = int(Math::floor(pos));
  
  				float y0=data[MAX(0,ipos-1)*chans+c];
  				float y1=data[ipos*chans+c];
  				float y2=data[MIN(len-1,ipos+1)*chans+c];
  				float y3=data[MIN(len-1,ipos+2)*chans+c];
  
  				float mu2 = mu*mu;
  				float a0 = y3 - y2 - y0 + y1;
  				float a1 = y0 - y1 - a0;
  				float a2 = y2 - y0;
  				float a3 = y1;
  
  				float res=(a0*mu*mu2+a1*mu2+a2*mu+a3);
  
  				new_data[i*chans+c]=res;
  			}
  		}
  
  		if (loop) {
  
  			loop_beg=loop_beg*new_data_len/len;
  			loop_end=loop_end*new_data_len/len;
  		}
  		data=new_data;
  		rate=limit_rate_hz;
  		len=new_data_len;
  	}
  
  
  	bool normalize = from->get_option("edit/normalize");
  
  	if (normalize) {
  
  		float max=0;
  		for(int i=0;i<data.size();i++) {
  
  			float amp = Math::abs(data[i]);
  			if (amp>max)
  				max=amp;
  		}
  
  		if (max>0) {
  
  			float mult=1.0/max;
  			for(int i=0;i<data.size();i++) {
  
  				data[i]*=mult;
  			}
  
  		}
  	}
  
  	bool trim = from->get_option("edit/trim");
  
  	if (trim && !loop) {
  
  		int first=0;
  		int last=(len*chans)-1;
  		bool found=false;
  		float limit = Math::db2linear(-30);
  		for(int i=0;i<data.size();i++) {
  			float amp = Math::abs(data[i]);
  
  			if (!found && amp > limit) {
  				first=i;
  				found=true;
  			}
  
  			if (found && amp > limit) {
  				last=i;
  			}
  		}
  
  		first/=chans;
  		last/=chans;
  
  		if (first<last) {
  
  			Vector<float> new_data;
  			new_data.resize((last-first+1)*chans);
  			for(int i=first*chans;i<=last*chans;i++) {
  				new_data[i-first*chans]=data[i];
  			}
  
  			data=new_data;
  			len=data.size()/chans;
  		}
  
  	}
  
  	bool make_loop = from->get_option("edit/loop");
  
  	if (make_loop && !loop) {
  
  		loop=Sample::LOOP_FORWARD;
  		loop_beg=0;
  		loop_end=len;
  	}
  
  	int compression = from->get_option("compress/mode");
  	bool force_mono = from->get_option("force/mono");
  
  
  	if (force_mono && chans==2) {
  
  		Vector<float> new_data;
  		new_data.resize(data.size()/2);
  		for(int i=0;i<len;i++) {
  			new_data[i]=(data[i*2+0]+data[i*2+1])/2.0;
  		}
  
  		data=new_data;
  		chans=1;
  	}
  
  	bool force_8_bit = from->get_option("force/8_bit");
  	if (force_8_bit) {
  
  		is16=false;
  	}
  
  
  	DVector<uint8_t> dst_data;
  	Sample::Format dst_format;
  
  	if ( compression == _EditorSampleImportOptions::COMPRESS_MODE_RAM) {
  
  		dst_format=Sample::FORMAT_IMA_ADPCM;
  		if (chans==1) {
  			_compress_ima_adpcm(data,dst_data);
  		} else {
  
  			print_line("INTERLEAAVE!");
  
  
  
  			//byte interleave
  			Vector<float> left;
  			Vector<float> right;
  
  			int tlen = data.size()/2;
  			left.resize(tlen);
  			right.resize(tlen);
  
  			for(int i=0;i<tlen;i++) {
  				left[i]=data[i*2+0];
  				right[i]=data[i*2+1];
  			}
  
  			DVector<uint8_t> bleft;
  			DVector<uint8_t> bright;
  
  			_compress_ima_adpcm(left,bleft);
  			_compress_ima_adpcm(right,bright);
  
  			int dl = bleft.size();
  			dst_data.resize( dl *2 );
  
  			DVector<uint8_t>::Write w=dst_data.write();
  			DVector<uint8_t>::Read rl=bleft.read();
  			DVector<uint8_t>::Read rr=bright.read();
  
  			for(int i=0;i<dl;i++) {
  				w[i*2+0]=rl[i];
  				w[i*2+1]=rr[i];
  			}
  		}
  
  //		print_line("compressing ima-adpcm, resulting buffersize is "+itos(dst_data.size())+" from "+itos(data.size()));
  
  	} else {
  
  		dst_format=is16?Sample::FORMAT_PCM16:Sample::FORMAT_PCM8;
  		dst_data.resize( data.size() * (is16?2:1));
  		{
  			DVector<uint8_t>::Write w = dst_data.write();
  
  			int ds=data.size();
  			for(int i=0;i<ds;i++) {
  
  				if (is16) {
  					int16_t v = CLAMP(data[i]*32767,-32768,32767);
  					encode_uint16(v,&w[i*2]);
  				} else {
  					int8_t v = CLAMP(data[i]*127,-128,127);
  					w[i]=v;
  				}
  			}
  		}
  	}
  
  
  	Ref<Sample> target;
  
  	if (ResourceCache::has(p_path)) {
  
  		target = Ref<Sample>( ResourceCache::get(p_path)->cast_to<Sample>() );
  	} else {
  
  		target = smp;
  	}
  
  	target->create(dst_format,chans==2?true:false,len);
  	target->set_data(dst_data);
  	target->set_mix_rate(rate);
  	target->set_loop_format(loop);
  	target->set_loop_begin(loop_beg);
  	target->set_loop_end(loop_end);
  
  	from->set_source_md5(0,FileAccess::get_md5(src_path));
  	from->set_editor(get_name());
  	target->set_import_metadata(from);
  
  
  	Error err = ResourceSaver::save(p_path,smp);
  
  	return err;
  
  }
  
  void EditorSampleImportPlugin::_compress_ima_adpcm(const Vector<float>& p_data,DVector<uint8_t>& dst_data) {
  
  
  	/*p_sample_data->data = (void*)malloc(len);
  	xm_s8 *dataptr=(xm_s8*)p_sample_data->data;*/
  
  	static const int16_t _ima_adpcm_step_table[89] = {
  		7, 8, 9, 10, 11, 12, 13, 14, 16, 17,
  		19, 21, 23, 25, 28, 31, 34, 37, 41, 45,
  		50, 55, 60, 66, 73, 80, 88, 97, 107, 118,
  		130, 143, 157, 173, 190, 209, 230, 253, 279, 307,
  		337, 371, 408, 449, 494, 544, 598, 658, 724, 796,
  		876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066,
  		2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358,
  		5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899,
  		15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767
  	};
  
  	static const int8_t _ima_adpcm_index_table[16] = {
  		-1, -1, -1, -1, 2, 4, 6, 8,
  		-1, -1, -1, -1, 2, 4, 6, 8
  	};
  
  
  	int datalen = p_data.size();
  	int datamax=datalen;
  	if (datalen&1)
  		datalen++;
  
  	dst_data.resize(datalen/2+4);
  	DVector<uint8_t>::Write w = dst_data.write();
  
  
  	int i,step_idx=0,prev=0;
  	uint8_t *out = w.ptr();
  	//int16_t xm_prev=0;
  	const float *in=p_data.ptr();
  
  
  	/* initial value is zero */
  	*(out++) =0;
  	*(out++) =0;
  	/* Table index initial value */
  	*(out++) =0;
  	/* unused */
  	*(out++) =0;
  
  	for (i=0;i<datalen;i++) {
  		int step,diff,vpdiff,mask;
  		uint8_t nibble;
  		int16_t xm_sample;
  
  		if (i>=datamax)
  			xm_sample=0;
  		else {
  
  
  			xm_sample=CLAMP(in[i]*32767.0,-32768,32767);
  			//if (xm_sample==32767 || xm_sample==-32768)
  			//	printf("clippy!\n",xm_sample);
  		}
  
  	//	xm_sample=xm_sample+xm_prev;
  	//	xm_prev=xm_sample;
  
  		diff = (int)xm_sample - prev ;
  
  		nibble=0 ;
  		step =  _ima_adpcm_step_table[ step_idx ];
  		vpdiff = step >> 3 ;
  		if (diff < 0) {
  			nibble=8;
  			diff=-diff ;
  		}
  		mask = 4 ;
  		while (mask) {
  
  			if (diff >= step) {
  
  				nibble |= mask;
  				diff -= step;
  				vpdiff += step;
  			}
  
  			step >>= 1 ;
  			mask >>= 1 ;
  		};
  
  		if (nibble&8)
  			prev-=vpdiff ;
  		else
  			prev+=vpdiff ;
  
  		if (prev > 32767) {
  			//printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip up %i\n",i,xm_sample,prev,diff,vpdiff,prev);
  			prev=32767;
  		} else if (prev < -32768) {
  			//printf("%i,xms %i, prev %i,diff %i, vpdiff %i, clip down %i\n",i,xm_sample,prev,diff,vpdiff,prev);
  			prev = -32768 ;
  		}
  
  		step_idx += _ima_adpcm_index_table[nibble];
  		if (step_idx< 0)
  			step_idx= 0 ;
  		else if (step_idx> 88)
  			step_idx= 88 ;
  
  
  		if (i&1) {
  			*out|=nibble<<4;
  			out++;
  		} else {
  			*out=nibble;
  		}
  		/*dataptr[i]=prev>>8;*/
  	}
  
  }
  
  
  EditorSampleImportPlugin* EditorSampleImportPlugin::singleton=NULL;
  
  
  
  EditorSampleImportPlugin::EditorSampleImportPlugin(EditorNode* p_editor) {
  
  	singleton=this;
  	dialog = memnew( EditorSampleImportDialog(this));
  	p_editor->get_gui_base()->add_child(dialog);
  }
  
  Vector<uint8_t> EditorSampleExportPlugin::custom_export(String& p_path,const Ref<EditorExportPlatform> &p_platform) {
  
  
  
  	if (EditorImportExport::get_singleton()->sample_get_action()==EditorImportExport::SAMPLE_ACTION_NONE || p_path.extension().to_lower()!="wav") {
  
  		return Vector<uint8_t>();
  	}
  
  	Ref<ResourceImportMetadata> imd = memnew( ResourceImportMetadata );
  
  	imd->add_source(EditorImportPlugin::validate_source_path(p_path));
  
  	imd->set_option("force/8_bit",false);
  	imd->set_option("force/mono",false);
  	imd->set_option("force/max_rate",true);
  	imd->set_option("force/max_rate_hz",EditorImportExport::get_singleton()->sample_get_max_hz());
  	imd->set_option("edit/trim",EditorImportExport::get_singleton()->sample_get_trim());
  	imd->set_option("edit/normalize",false);
  	imd->set_option("edit/loop",false);
  	imd->set_option("compress/mode",1);
  
  	String savepath = EditorSettings::get_singleton()->get_settings_path().plus_file("tmp/smpconv.smp");
  	Error err = EditorSampleImportPlugin::singleton->import(savepath,imd);
  
  
  	ERR_FAIL_COND_V(err!=OK,Vector<uint8_t>());
  
  	p_path=p_path.basename()+".converted.smp";
  	return FileAccess::get_file_as_array(savepath);
  
  }
  
  
  EditorSampleExportPlugin::EditorSampleExportPlugin() {
  
  }
  
  
  