コード例 #1
0
static void play_note2(Data *data, int time, note_t note){
  //printf("Playing %f\n",note.pitch);

  Voice *voice = data->voices_not_playing;

  if(voice==NULL){
    printf("no more free voices\n");
    return;
  }

  RT_remove_voice(&data->voices_not_playing, voice);
  RT_add_voice(&data->voices_playing, voice);

  *(voice->myUI._gate_control) = 1.0f;
  *(voice->myUI._freq_control) = midi_to_hz(note.pitch);
  *(voice->myUI._gain_control) = velocity2gain(note.velocity);

  voice->note_num = note.pitch;
  voice->note_id = note.id;
  voice->seqblock = note.seqblock;
  
  voice->frames_since_stop = 0;
  voice->delta_pos_at_start = time;
  voice->delta_pos_at_end = -1;
}
コード例 #2
0
ファイル: faust_tapiir.cpp プロジェクト: renno23/radium
static void play_note(struct SoundPlugin *plugin, int64_t time, float note_num, int64_t note_id, float volume, float pan){
  Data *data = (Data*)plugin->data;

  //printf("Playing %d\n",note_num);

  Voice *voice = data->voices_not_playing;

  if(voice==NULL){
    printf("no more free voices\n");
    return;
  }

  RT_remove_voice(&data->voices_not_playing, voice);
  RT_add_voice(&data->voices_playing, voice);

  //voice->dsp_instance->init((int)data->samplerate);

  *(voice->myUI._gate_control) = 1.0f;
  *(voice->myUI._freq_control) = midi_to_hz(note_num);
  *(voice->myUI._gain_control) = velocity2gain(volume);

  voice->note_num = note_num;
  voice->note_id = note_id;

  voice->frames_since_stop = 0;
  voice->delta_pos_at_start = time;
  voice->delta_pos_at_end = -1;
}
コード例 #3
0
static void set_note_pitch2(Data *data, int time, note_t note){
  Voice *voice = data->voices_playing;
  //printf("Setting volume %f / %f\n",volume,velocity2gain(volume));
  while(voice!=NULL){
    if(is_note(note, voice->note_id, voice->seqblock))
      *(voice->myUI._freq_control) = midi_to_hz(note.pitch);
    voice=voice->next;
  }
}
コード例 #4
0
ファイル: faust_tapiir.cpp プロジェクト: renno23/radium
static void set_note_pitch(struct SoundPlugin *plugin, int64_t time, float note_num, int64_t note_id, float pitch){
  Data *data = (Data*)plugin->data;
  Voice *voice = data->voices_playing;
  //printf("Setting volume %f / %f\n",volume,velocity2gain(volume));
  while(voice!=NULL){
    if(voice->note_id==note_id)
      *(voice->myUI._freq_control) = midi_to_hz(pitch);
    voice=voice->next;
  }
}
コード例 #5
0
ファイル: jeg.c プロジェクト: Claudiu/jeg
int main( int argc, const char ** argv )
{
    PaStreamParameters outputParameters;
    PaError pa_err;
    SF_INFO sfinfo;

    int i;
    for (i = 1; i < argc; i++)
    {
        if (!strncmp(argv[i], "-m", 2))
        {
            mute = 1;
        }
        if (!strncmp(argv[i], "-o", 2))
        {
            to_stdout = 1;
        }
    }

    gen_default_drums();

    pa_err = Pa_Initialize();
    outputParameters.device = Pa_GetDefaultOutputDevice();
    outputParameters.channelCount = CHANNELS;
    outputParameters.sampleFormat = paFloat32;
    outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
    outputParameters.hostApiSpecificStreamInfo = NULL;
    pa_err = Pa_OpenStream( &stream, NULL, &outputParameters, SAMPLE_RATE, BUFFER_SIZE, paClipOff, audio_callback, NULL );

    sfinfo.samplerate = SAMPLE_RATE;
    sfinfo.channels = CHANNELS;
    sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
    wave_output = sf_open( OUTPUT_FILE, SFM_WRITE, &sfinfo );

    convert_buf = (int32_t*)malloc(SAMPLE_RATE * 4 * 2);

    srand( time( 0 ) );

    bass_z = 0.0f;
    bass_freq = midi_to_hz( BASE_NOTE );

    pa_err = Pa_StartStream( stream );

    while( 1 )
        Pa_Sleep( 10000 );

    sf_close( wave_output );
    pa_err = Pa_StopStream( stream );
    pa_err = Pa_CloseStream( stream );
    Pa_Terminate();

    return 0;
}
コード例 #6
0
ファイル: jeg.c プロジェクト: deveah/jeg
int main( void )
{
	PaStreamParameters outputParameters;
	PaError pa_err;
	SF_INFO sfinfo;

	signal( SIGINT, interrupt );

	gen_default_drums();

	pa_err = Pa_Initialize();
	outputParameters.device = Pa_GetDefaultOutputDevice();
	outputParameters.channelCount = CHANNELS;
	outputParameters.sampleFormat = paFloat32;
	outputParameters.suggestedLatency =
		Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency;
	outputParameters.hostApiSpecificStreamInfo = NULL;
	pa_err = Pa_OpenStream( &stream, NULL, &outputParameters, SAMPLE_RATE,
		BUFFER_SIZE, paClipOff, audio_callback, NULL );

	sfinfo.samplerate = SAMPLE_RATE;
	sfinfo.channels = CHANNELS;
	sfinfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
	wave_output = sf_open( OUTPUT_FILE, SFM_WRITE, &sfinfo );

	srand( time( 0 ) );

	bass_z = 0.0f;
	bass_freq = midi_to_hz( BASE_NOTE );

	pa_err = Pa_StartStream( stream );
	
	while( 1 )
		Pa_Sleep( 1000 );

	sf_close( wave_output );
	pa_err = Pa_StopStream( stream );
	pa_err = Pa_CloseStream( stream );
	Pa_Terminate();

	return 0;
}
コード例 #7
0
ファイル: stk_bass.cpp プロジェクト: dieface/radium-1
static void play_note(struct SoundPlugin *plugin, int64_t time, int note_num, float volume){
  Data *data = (Data*)plugin->data;

  //printf("Playing %d\n",note_num);

  Voice *voice = data->voices_not_playing;

  if(voice==NULL){
    printf("no more free voices\n");
    return;
  }

  RT_remove_voice(&data->voices_not_playing, voice);
  RT_add_voice(&data->voices_playing, voice);

  *(voice->myUI._gate_control) = 1.0f;
  *(voice->myUI._freq_control) = midi_to_hz(note_num);
  *(voice->myUI._gain_control) = velocity2gain(volume);

  voice->note_num = note_num;
  
}
コード例 #8
0
ファイル: so-404.c プロジェクト: EQ4/So-synth-LV2
void runSO_404( LV2_Handle arg, uint32_t nframes ) {
	so_404* so=(so_404*)arg;
	lv2_event_begin(&so->in_iterator,so->MidiIn);
	
	float* outbuffer=so->output;

	if(*so->controlmode_p >0) {
		so->cutoff=*so->cutoff_p;
		so->portamento=*so->portamento_p;
		so->release=*so->release_p;
		so->volume=*so->volume_p;
		so->envmod=*so->envmod_p;
		so->resonance=*so->resonance_p;
	}
	
	int i;
	for( i=0; i<nframes; i++ ) {
		while(lv2_event_is_valid(&so->in_iterator)) {
			uint8_t* data;
			LV2_Event* event= lv2_event_get(&so->in_iterator,&data);
			if (event->type == 0) {
				so->event_ref->lv2_event_unref(so->event_ref->callback_data, event);
			} else if(event->type==so->midi_event_id) {
				if(event->frames > i) {
					break;
				} else {
					const uint8_t* evt=(uint8_t*)data;
					if((evt[0]&MIDI_CHANNELMASK)==(int) (*so->channel_p)) {
						if((evt[0]&MIDI_COMMANDMASK)==MIDI_NOTEON) 	{
							unsigned int note = evt[1];
							so->tfreq=midi_to_hz(note);
							if( so->noteson == 0 )
							{
								so->freq = so->tfreq;
								so->amp=1.0;
								so->vel = ((float)evt[2]);
								so->env=so->vel/127.0;
								so->cdelay = 0;
							}
							so->noteson += 1;
						}
						else if((evt[0]&MIDI_COMMANDMASK)==MIDI_NOTEOFF )	{
							so->noteson -= 1;
							if(so->noteson<0) {
								so->noteson=0;
							}
						}
						else if((*so->controlmode_p<=0) && (evt[0]&MIDI_COMMANDMASK)==MIDI_CONTROL )	{
							unsigned int command_val=evt[2];
							switch(evt[1]) {
								case 74:
									so->cutoff =command_val;
									break;
								case 65:
									so->portamento = command_val;
									break;
								case 72:
									so->release = command_val;
									break;
								case 7:
									so->volume = command_val;
									break;
								case 79:
									so->envmod = command_val;
									break;
								case 71:
									so->resonance = command_val;
									break;
							}
						}
					}
				}
			}
			lv2_event_increment(&so->in_iterator);
		}
		if( so->cdelay <= 0 )
		{
			so->freq = ((so->portamento/127.0)*0.9)*so->freq + (1.0-((so->portamento/127.0)*0.9))*so->tfreq;
			if( so->noteson > 0 ) {
				so->amp *= 0.99;
			} else {
				so->amp *= 0.5;
			}
			so->env*=0.8+powf(so->release/127.0,0.25)/5.1;

			so->fcutoff = powf(so->cutoff/127.0,2.0)+powf(so->env,2.0)*powf(so->envmod/127.0,2.0);
			so->fcutoff = tanh(so->fcutoff);
			so->freso = powf(so->resonance/130.0,0.25);
			so->cdelay = so->samplerate/100;
		}
		so->cdelay--;
		
		float max = so->samplerate / so->freq;
		float sample = (so->phase/max)*(so->phase/max)-0.25;
		so->phase++;
		if( so->phase >= max ) {
			so->phase -= max;
		}
		
		if(so->vel>100) {
			sample*=so->env;
		} else {
			sample*=so->amp;
		}

		so->fpos += so->fspeed;
		so->fspeed *= so->freso;
		so->fspeed += (sample-so->fpos)*so->fcutoff;
		sample = so->fpos;

		sample = sample*0.5+so->lastsample*0.5;
		so->lastsample = sample;

		outbuffer[i] = sample * (so->volume/127.0);
	}
}
コード例 #9
0
ファイル: Sampler_plugin.c プロジェクト: renno23/radium
static bool load_sample_with_libsndfile(Data *data, const wchar_t *filename){
  SF_INFO sf_info; memset(&sf_info,0,sizeof(sf_info));

  data->num_different_samples = 1;

  float *samples = load_interleaved_samples(filename, &sf_info);

  if(samples==NULL){
    fprintf(stderr,"could not open file\n");
    return false;
  }

  {
    int num_channels = sf_info.channels;

    printf("Num channels: %d\n",num_channels);

    if(num_channels > 2) // TODO
      num_channels = 2;

    int ch;
    for(ch=0;ch<num_channels;ch++){
      Sample *sample     = (Sample*)&data->samples[ch];
      sample->num_frames = sf_info.frames;
      sample->sound       = malloc(sizeof(float)*sample->num_frames);
    }

    int interleaved_pos=0;
    int i;
    for(i=0;i<sf_info.frames;i++){
      for(ch=0;ch<sf_info.channels;ch++){
        if(ch<2){
          Sample *sample=(Sample*)&data->samples[ch];
          sample->sound[i] = samples[interleaved_pos];
        }
        interleaved_pos++;
      }
    }

    for(ch=0;ch<num_channels;ch++){     
      Sample *sample=(Sample*)&data->samples[ch];

      set_legal_loop_points(sample,-1,-1); // By default, don't loop, but if set, loop all.
              
      if((sf_info.format&0xffff0000) == SF_FORMAT_WAV){
        printf("format: 0x%x. sections: %d, num_frames: %d. SF_FORMAT_WAV: 0x%x. og: 0x%x\n",sf_info.format,sf_info.sections,(int)sf_info.frames,SF_FORMAT_WAV,sf_info.format&SF_FORMAT_WAV);
        set_wav_loop_points(sample,filename);
      }

      if(num_channels==1)
        sample->ch = -1; // i.e play the sample in both channels.
      else
        sample->ch = ch;

      int i;
      for(i=1;i<128;i++){
        Note *note=(Note*)&data->notes[i];
        
        note->num_samples = num_channels;
        note->samples[ch] = sample;
          
        sample->frequency_table[i] = sf_info.samplerate * midi_to_hz(i)/midi_to_hz(48);
        
        //printf("%d: %f, data: %f, sample: %f, midifreq: %f\n",i,sample->samplerate,(float)data->samplerate,(float)sf_info.samplerate,midi_to_hz(i));
      }
    }
  }

  return true;
}
コード例 #10
0
ファイル: Sampler_plugin.c プロジェクト: renno23/radium
static double get_ratio(int sample_note_num, int play_note_num){
  return midi_to_hz(sample_note_num) / midi_to_hz(play_note_num);
}
コード例 #11
0
ファイル: jeg.c プロジェクト: Claudiu/jeg
static int audio_callback(	const void *inputBuffer, void *outputBuffer,
                            unsigned long framesPerBuffer,
                            const PaStreamCallbackTimeInfo *timeInfo,
                            PaStreamCallbackFlags statusFlags,
                            void *userData )
{
    int i;
    float *out = (float*)outputBuffer;
    float b, d, f, mod;
    int beat;

    float v;

    for( i = 0; i < framesPerBuffer; i++ )
    {
        d = 0;

        beat = global_frame % ( SAMPLE_RATE / ( DEFAULT_BPM / 60 ) / 4 );

        if( beat == 0 )
        {
            if( beat_count % 4 == 0 )
                bass_lfofreq = ((float)DEFAULT_BPM/60.0f) * flt_freq[ rand()%4 ];

            if( rand()%RANDOM_NOTE_CHANGE_CHANCE == 0 )
            {
                bass_freq = midi_to_hz( BASE_NOTE + minor_scale[ rand()%7 ] + ((rand()%RANDOM_OCTAVE_JUMP_CHANCE==0)?12:0) );
            }

            if( ( beat_count % 4 == 0 ) && ( rand()%RANDOM_GLITCH_CHANCE == 0 ) )
            {
                bass_fmindex = (float)( rand()%999 + 1 );
            }

            if( ( beat_count % 4 == 0 ) && ( rand()%RANDOM_GLITCH_RETURN_CHANCE == 0 ) )
            {
                bass_fmindex = 0.0f;
            }

            if( rand()%RANDOM_MODULATION == 0 )
            {
                bass_fmmod = (float)( rand()%3 + 1 );
            }

            if( beat_count % 16 == 0 )
                bd_time = 0;

            if( beat_count % 16 == 8 )
            {
                if( rand()%RANDOM_SNARE_SILENCE_CHANCE == 0 )
                    bass_vol = 0.0f;
                sd_time = 0;
            }

            if( ( beat_count % 16 == 10 ) && ( rand()%RANDOM_SNARE_CHANCE == 0 ) )
                sd_time = 0;

            if( beat_count % 16 == 12 )
                bass_vol = 1.0f;

            if( beat_count % 16 == 6 )
                bd_time = 0;

            if( beat_count % 2 == 0 )
                hh_time = 0;

            beat_count++;
        }

        if( bd_time >= 0 )
        {
            d = bd[bd_time++];
            if( bd_time > SAMPLE_RATE )
                bd_time = -1;
        }

        if( sd_time >= 0 )
        {
            d = d * 0.8f + sd[sd_time++];
            if( sd_time > SAMPLE_RATE )
                sd_time = -1;
        }

        if( hh_time >= 0 )
        {
            d = d * 0.8f + hh[hh_time++] * 0.05f;
            if( hh_time > SAMPLE_RATE )
                hh_time = -1;
        }

        bass_lfoval = sin( 2.0 * M_PI * bass_lfofreq * (float)global_frame / (float)SAMPLE_RATE );
        bass_lfoval = bass_lfoval/100.0f + 0.99f;

        mod = sin( 2.0 * M_PI * bass_fmmod * bass_freq * (float)global_frame / (float)SAMPLE_RATE );
        b = sgn( sin( 2.0 * M_PI * ( bass_freq * (float)global_frame / (float)SAMPLE_RATE ) + mod * bass_fmindex ) );

        bass_z = bass_lfoval * bass_z + ( 1.0f - bass_lfoval ) * b;

        v = 0.3f;

        out[i] = bass_vol * bass_z * v + d * ( 1.0f-v );

        if( out[i] > 1.0f ) out[i] = 1.0f;
        if( out[i] < -1.0f ) out[i] = -1.0f;

        global_frame++;
    }

    sf_write_float( wave_output, out, framesPerBuffer );
    if (to_stdout)
    {
        for (i = 0; i < framesPerBuffer; i++)
        {
            double f = (double)out[i];
            convert_buf[i] = (int32_t)(f * 0x7fffffffL);
        }
        write(STDOUT_FILENO, convert_buf, framesPerBuffer * 4);
    }

    if (mute)
        memset(out, 0, sizeof(float) * framesPerBuffer);

    return paContinue;
}
コード例 #12
0
ファイル: jeg.c プロジェクト: deveah/jeg
/*	main function that makes the dubstep sound */
static int audio_callback(	const void *inputBuffer, void *outputBuffer,
							unsigned long framesPerBuffer,
							const PaStreamCallbackTimeInfo *timeInfo,
							PaStreamCallbackFlags statusFlags,
							void *userData )
{
	int i;
	float *out = (float*)outputBuffer;
	float b, d, f, mod;
	int beat;

	float v;

	for( i = 0; i < framesPerBuffer; i++ )
	{
		d = 0;

		beat = global_frame % ( SAMPLE_RATE / ( DEFAULT_BPM / 60 ) / 4 );

		/*	if the stream has hit a beat */
		if( beat == 0 )
		{
			/*	4 beats is half a measure; alter the filter's LFO */
			if( beat_count % 4 == 0 )
				bass_lfofreq = ((float)DEFAULT_BPM/60.0f) *
					flt_freq[ rand()%4 ];

			/*	change the note by choosing another from the provided scale */
			if( rand()%RANDOM_NOTE_CHANGE_CHANCE == 0 )
			{
				bass_freq = midi_to_hz( BASE_NOTE + minor_scale[ rand()%7 ] +
					((rand()%RANDOM_OCTAVE_JUMP_CHANCE==0)?12:0) );
			}

			/*	alter the FM index (modulator amplitude), to add overtones to
				the bassline, thus creating the 'glitched' sound */
			if( ( beat_count % 4 == 0 ) && ( rand()%RANDOM_GLITCH_CHANCE == 0 ) )
			{
				bass_fmindex = (float)( rand()%999 + 1 );
			}

			/*	reset the FM index to return to the normal square bass sound */
			if( ( beat_count % 4 == 0 ) && ( rand()%RANDOM_GLITCH_RETURN_CHANCE == 0 ) )
			{
				bass_fmindex = 0.0f;
			}
		
			/*	alter the FM mod (modulator frequency multiplier) */
			if( rand()%RANDOM_MODULATION == 0 )
			{
				bass_fmmod = (float)( rand()%3 + 1 );
			}

			/*	a bassdrum hits every two measures */
			if( beat_count % 16 == 0 )
				bd_time = 0;

			/*	sometimes, the snare won't trigger */
			if( beat_count % 16 == 8 )
			{
				if( rand()%RANDOM_SNARE_SILENCE_CHANCE == 0 )
					bass_vol = 0.0f;
				sd_time = 0;
			}

			/*	trigger a snare drum on the 10th beat of two measures combined */
			if( ( beat_count % 16 == 10 ) && ( rand()%RANDOM_SNARE_CHANCE == 0 ) )
				sd_time = 0;

			/*	reset the volume of the bassline, if it has been previously
				diminished, to create the impression of a compressor */
			if( beat_count % 16 == 12 )
				bass_vol = 1.0f;

			/*	trigger a bass drum */
			if( beat_count % 16 == 6 )
				bd_time = 0;

			/*	trigger a hihat */
			if( beat_count % 2 == 0 )
				hh_time = 0;

			beat_count++;
		}

		/*	advance sample counters and mix the drum channel */
		if( bd_time >= 0 )
		{
			d = bd[bd_time++];
			if( bd_time > SAMPLE_RATE )
				bd_time = -1;
		}

		if( sd_time >= 0 )
		{
			d = d * 0.8f + sd[sd_time++];
			if( sd_time > SAMPLE_RATE )
				sd_time = -1;
		}

		if( hh_time >= 0 )
		{
			d = d * 0.8f + hh[hh_time++] * 0.05f;
			if( hh_time > SAMPLE_RATE )
				hh_time = -1;
		}

		/*	compute the LFO value */
		bass_lfoval = sin( 2.0 * M_PI * bass_lfofreq * (float)global_frame /
			(float)SAMPLE_RATE );
		/*	the LFO value is in range 0.00 .. 0.01 */
		bass_lfoval = bass_lfoval/100.0f + 0.99f;

		/*	compute the modulator */
		mod = sin( 2.0 * M_PI * bass_fmmod * bass_freq * (float)global_frame /
			(float)SAMPLE_RATE );
		/*	compute the bassline */
		b = sgn( sin( 2.0 * M_PI * ( bass_freq * (float)global_frame /
			(float)SAMPLE_RATE ) + mod * bass_fmindex ) );

		/*	process the bassline through a lowpass filter */
		bass_z = bass_lfoval * bass_z + ( 1.0f - bass_lfoval ) * b;

		v = 0.3f;

		/*	final mix of the two tracks */
		out[i] = bass_vol * bass_z * v + d * ( 1.0f-v );


		if( out[i] > 1.0f ) out[i] = 1.0f;
		if( out[i] < -1.0f ) out[i] = -1.0f;

		global_frame++;
	}

	sf_write_float( wave_output, out, framesPerBuffer );

	return paContinue;
}
コード例 #13
0
static bool load_sf2_instrument(Data *data, const wchar_t *filename, int preset_bag_number, bool set_loop_on_off){
  EVENTLOG_add_event(talloc_format("load_sf2_instrument -%S-", filename));
    
  hash_t *info = SF2_get_info(filename);
  if(info==NULL){
    GFX_Message(NULL, "Unable to open soundfont file \"%S\"\n", filename);
    return false;
  }

  //HASH_save(info,stdout);
  hash_t *sample_infos = HASH_get_hash(info,"samples");

  hash_t *presets = HASH_get_hash(info,"presets");
  hash_t *preset = HASH_get_hash_at(presets, "", preset_bag_number);
  if(preset==NULL){
    GFX_Message(NULL, "No such preset number %d in instrument \"%S\"\n", preset_bag_number, filename);
    return false;
  }

  int bank_num = HASH_get_int32(preset,"bank");

  hash_t *instrument = NULL;

  // Try to find an instrument from the region. A preset may use several instruments, but that's not supported yet. We just use the first and best/worst.
  {
    hash_t *instruments = HASH_get_hash(info,"instruments");
    hash_t *regions = HASH_get_hash(preset,"regions");

    int i;
    for(i=0;i<HASH_get_array_size(regions, "");i++){
      hash_t *region = HASH_get_hash_at(regions,"",i);

      if(HASH_has_key(region,"instrument")==true){
        instrument = HASH_get_hash(instruments,HASH_get_chars(region,"instrument"));
        break;
      }
    }
  }

  if(instrument==NULL){
    GFX_Message(NULL, "load_sf2_instrument: Preset \"%S\" (bank %d / preset %d) in \"%S\" doesn't point to an instrument\n",
                HASH_get_string(preset,"name"), bank_num, HASH_get_int32(preset,"num"), filename
                );
    return false;
  }

  hash_t *regions = HASH_get_hash(instrument, "regions");

  for(int i=0;i<128;i++){
    Note *note = new Note;
    data->notes[i] = note;
    data->note_storage.push_back(note);
  }
  
  int num_samples=0;

  int i;
  for(i=0;i<HASH_get_array_size(regions, "");i++){
    hash_t *region = HASH_get_hash_at(regions,"",i);
    
    const char *sample_name = HASH_get_chars(region, "sample_name");
    if(strcmp(sample_name,"<no sample!>")){
      hash_t *sample_info = HASH_get_hash(sample_infos, sample_name);
      int sample_num = HASH_get_int32(sample_info,"num");

      Sample &sample = data->samples[num_samples++];
      new (&sample) Sample();
        
      sample.data = data;

      sample.volume = 1.0f;
      sample.num_frames = HASH_get_int(sample_info,"num_frames");

      set_legal_loop_points(sample,-1,-1, set_loop_on_off); // By default, loop all.
      set_legal_loop_points(sample,
                            HASH_get_int(sample_info,"loop start"),
                            HASH_get_int(sample_info,"loop end"),
                            set_loop_on_off
                            );

      printf("Loop start / end: %d %d\n",(int)sample.loop_start,(int)sample.loop_end);
      
      {
        sample.ch = -1;
        const char *type = HASH_get_chars(sample_info,"type");
        if(!strcmp(type,"Left Sample") || !strcmp(type,"ROM Left Sample"))
          sample.ch = 0;
        if(!strcmp(type,"Right Sample") || !strcmp(type,"ROM Right Sample"))
          sample.ch = 1;
      }

      sample.sound = SF2_load_sample(filename, sample_num);

      int root_key = HASH_get_int32(region, "root key");
      int coarsetune = HASH_get_int32(region, "coarse tune");
      int finetune = HASH_get_int32(region, "fine tune");

      printf("root: %d, coarse: %d, fine: %d, sample pitch: %d\n",root_key,coarsetune,finetune,(int)HASH_get_int(sample_info,"pitch"));

      int note;
      for(note=0;note<128;note++)
        if(HASH_get_int(sample_info,"pitch")==255)
          sample.frequency_table[note] = HASH_get_int(sample_info, "samplerate");
        else
          sample.frequency_table[note] = HASH_get_int(sample_info, "samplerate") * midi_to_hz(note+coarsetune+(float)finetune/100.0) / midi_to_hz(root_key);

      int note_num;
      for(note_num=HASH_get_int32(region,"key start");note_num<=HASH_get_int32(region,"key end");note_num++){
        Note *note = const_cast<Note*>(data->notes[note_num]);
        note->samples.push_back(&sample);
        
        //printf("%d: %f. middle_note: %d, finetune: %f. Sample: %p. Frequency: %f\n",i,dest->ratio,dest->middle_note,dest->finetune,dest->interleaved_samples,get_frequency(i,dest->finetune));
      }
    }
  }

  // Optimize data->notes so that as few Note objects as possible are used (better for cache)
  for(int i=0;i<128;i++){

    Note *old_note = const_cast<Note*>(data->notes[i]);
    old_note->sort_samples();
    
    for(int i2=0;i2<i;i2++){
      if(data->notes[i]->is_equal(data->notes[i2])){
        
        data->notes[i] = data->notes[i2];

        data->note_storage.remove(old_note);
        delete old_note;

        printf("   Load SF2: Move notes %d to %d. Size of note_storage: %d\n", i, i2, data->note_storage.size());

        break;
      }
    }
    
  }

    

  return true;
}