From adc0eda2c8942a22c6dae77531140e825bc9b85d Mon Sep 17 00:00:00 2001 From: kazu Date: Sat, 27 Apr 2024 01:51:31 +0000 Subject: [PATCH] Update (thanks to bree!) git-svn-id: file:///raid/svn-main/kazu-ksynth/trunk@31 7b47e76f-e598-2f43-bc14-414d160cc389 --- src/ksynth.c | 444 +++++++++++++++++++++++++++------------------------ src/ksynth.h | 62 +++---- src/sample.h | 2 +- 3 files changed, 269 insertions(+), 239 deletions(-) diff --git a/src/ksynth.c b/src/ksynth.c index b33fbf5..5e53ff3 100644 --- a/src/ksynth.c +++ b/src/ksynth.c @@ -1,7 +1,8 @@ #include "ksynth.h" +#define MAX_KEYS 128 #define MAX_POLYPHONY 1000000 -#define MIN_BUF 16 +#define MIN_BUF 8 #define MAX_BUF 65536 #define RELEASE_TIME 300 @@ -17,130 +18,152 @@ float compute_velocity_sse2(float logVel, float pow, float coeff) { } #endif -struct KSynth* ksynth_new(const char* sample_file_path, unsigned int sample_rate, unsigned char num_channel, unsigned long max_polyphony) { - struct KSynth* ksynth_instance = malloc(sizeof(struct KSynth)); - if(ksynth_instance != NULL) { - memset(ksynth_instance, 0, sizeof(struct KSynth)); +void int_free_voices(struct Voice** voices, unsigned long count) { + if(voices) { + if(count > 0) { + for(unsigned long i = 0; i < count; i++) { + if(voices[i]) { + free(voices[i]); + } + } + } + + free(voices); + } +} + +struct Voice** int_allocate_voices(struct KSynth* ksynth_instance) { + if(ksynth_instance->max_polyphony < 1) ksynth_instance->max_polyphony = 1; + else if(ksynth_instance->max_polyphony >= MAX_POLYPHONY) + ksynth_instance->max_polyphony = MAX_POLYPHONY; + + struct Voice** voices = calloc(ksynth_instance->max_polyphony, sizeof(struct Voice*)); + + if(voices) { + for(unsigned long i = 0; i < ksynth_instance->max_polyphony; i++) { + struct Voice* newVoice = calloc(1, sizeof(struct Voice)); + + if(newVoice) { + newVoice->killed = 1; + voices[i] = newVoice; + + continue; + } + + if(i > 0) { + for(unsigned long j = 0; j < i; j++) { + free(voices[i]); + } + } - // Load samples from file - FILE* f = fopen(sample_file_path, "rb"); - if(f == NULL) { - fprintf(stderr, "[KSynth] Error: Failed to open sample file.\n"); - free(ksynth_instance); return NULL; } - // HARDCODED? - int sfrate = 48000; - ksynth_instance->samples = malloc(sizeof(struct Sample*) * 128); - if(ksynth_instance->samples != NULL) { - for(int i = 0; i < 128; i++) { - ksynth_instance->samples[i] = malloc(sizeof(struct Sample)); - memset(ksynth_instance->samples[i], 0, sizeof(struct Sample)); + return voices; + } - ksynth_instance->samples[i]->sample = malloc(sfrate * 10 * sizeof(float)); - memset(ksynth_instance->samples[i]->sample, 0, sfrate * 10 * sizeof(float)); + return NULL; +} - ksynth_instance->samples[i]->length = sfrate * 10; - fread(ksynth_instance->samples[i]->sample, sfrate * 10 * sizeof(float), 1, f); +void int_free_samples(struct Sample** samples, unsigned long count) { + if(samples) { + if(count > 0) { + for(unsigned long i = 0; i < count; i++) { + if(samples[i]) { + if(samples[i]->audio_data) free(samples[i]->audio_data); - ksynth_instance->samples[i]->sample_rate = sfrate; + free(samples[i]); + } } } - fclose(f); - // Load samples from file end + free(samples); + } +} - ksynth_instance->sample_rate = sample_rate; - if(num_channel >= 2) { - ksynth_instance->num_channel = 2; - } else { - ksynth_instance->num_channel = num_channel; - } - ksynth_instance->polyphony = 0; +struct Sample** int_allocate_samples(const char* path, unsigned char keys, struct KSynth* ksynth_instance) { + int sfrate = ksynth_instance->sample_rate; + keys = keys > MAX_KEYS ? MAX_KEYS : keys; - if(max_polyphony < 1) { - ksynth_instance->max_polyphony = 1; - } else if(max_polyphony >= MAX_POLYPHONY) { - ksynth_instance->max_polyphony = MAX_POLYPHONY; - } else { - ksynth_instance->max_polyphony = max_polyphony; + struct Sample** samples = calloc(ksynth_instance->sample_rate, sizeof(struct Sample*)); + if(samples != NULL) { + // Load samples from file + FILE* f = fopen(path, "rb"); + if(f == NULL) { + fprintf(stderr, "[KSynth] Error: Failed to open sample file.\n"); + free(samples); + return NULL; } - for(int i = 0; i < 16; i++) { - ksynth_instance->channels[i].pan = 0.0f; - ksynth_instance->channels[i].sustain = 0; - ksynth_instance->polyphony_per_channel[i] = 0; - } + for(int i = 0; i < keys; i++) { + samples[i] = calloc(1, sizeof(struct Sample)); - ksynth_instance->rendering_time = 0; + if(!samples[i]) { + int_free_samples(samples, i); - ksynth_instance->voices = malloc(sizeof(struct Voice*) * max_polyphony); - memset(ksynth_instance->voices, 0, sizeof(struct Voice*) * max_polyphony); + fprintf(stderr, "[KSynth] Error: Failed to allocate memory for sample struct.\n"); + return NULL; + } - if(ksynth_instance->voices) { - for(unsigned long i = 0; i < max_polyphony; i++) { - struct Voice* newVoice = malloc(sizeof(struct Voice)); - memset(newVoice, 0, sizeof(struct Voice)); + struct Sample* sample = samples[i]; - if(newVoice) { - newVoice->killed = 1; + sample->sample_rate = sfrate; + sample->length = sfrate * 10; + sample->audio_data = calloc(sfrate * 10, sizeof(float)); - ksynth_instance->voices[i] = newVoice; - continue; - } + if(!sample->audio_data) { + int_free_samples(samples, i); + fprintf(stderr, "[KSynth] Error: Failed to allocate memory for samples data.\n"); return NULL; } + + // Load samples from file end + fread(samples[i]->audio_data, sfrate * 10 * sizeof(float), 1, f); } - } else { - fprintf(stderr, "[KSynth] Error: Failed to allocate memory for KSynth instance.\n"); - } - return ksynth_instance; -} + fclose(f); -void ksynth_cc(struct KSynth* ksynth_instance, unsigned char channel, unsigned char param1, unsigned char param2) { - if(!ksynth_instance || channel > 15) { - fprintf(stderr, "[KSynth] Error: Invalid parameters for CC.\n"); - return; + return samples; } - if(channel == 9) return; - - switch(param1) { - case 10: - ksynth_instance->channels[channel].pan = ((param2 - 64) / 64.0f); - break; - case 64: - // Damper pedal, MUST respond to this at least - ksynth_instance->channels[channel].sustain = param2 > 63 ? 1 : 0; - break; - default: - break; - } + fprintf(stderr, "[KSynth] Error: Failed to open samples file.\n"); + return NULL; } -void ksynth_note_off(struct KSynth* ksynth_instance, unsigned char channel, unsigned char note) { - if(!ksynth_instance || channel > 15 || note > 127) { - fprintf(stderr, "[KSynth] Error: Invalid parameters for note off.\n"); - return; - } +struct KSynth* ksynth_new(const char* sample_file_path, unsigned int sample_rate, unsigned char num_channel, unsigned long max_polyphony) { + struct KSynth* ksynth_instance = calloc(1, sizeof(struct KSynth)); + if(ksynth_instance != NULL) { + // HARDCODED? + ksynth_instance->rendering_time = 0.0f; + ksynth_instance->polyphony = 0; + ksynth_instance->max_polyphony = max_polyphony; + ksynth_instance->sample_rate = sample_rate; + ksynth_instance->num_channel = num_channel >= 2 ? 2 : num_channel; - if(channel == 9) return; + ksynth_instance->voices = int_allocate_voices(ksynth_instance); + if(ksynth_instance->voices) { + ksynth_instance->samples = int_allocate_samples(sample_file_path, MAX_KEYS, ksynth_instance); - struct Voice* voice = 0; - for(unsigned long i = ksynth_instance->polyphony - 1; i < ksynth_instance->polyphony; --i) { - voice = ksynth_instance->voices[i]; + if(ksynth_instance->samples) { + memset(ksynth_instance->channels, 0, 16 * sizeof(struct Chan)); + memset(ksynth_instance->polyphony_per_channel, 0, 16 * sizeof(unsigned char)); - if((voice->channel == channel && note == voice->noteNumber) && (!voice->killed && !voice->tokill)) { - voice->tokill = 1; - break; + return ksynth_instance; + } else { + fprintf(stderr, "[KSynth] Error: Failed to allocate memory for samples.\n"); + return NULL; + } + } else { + fprintf(stderr, "[KSynth] Error: Failed to allocate memory for voices.\n"); + return NULL; } } -} + fprintf(stderr, "[KSynth] Error: Failed to allocate memory for KSynth instance.\n"); + return NULL; +} void ksynth_note_on(struct KSynth* ksynth_instance, unsigned char channel, unsigned char note, unsigned char velocity) { - if(!ksynth_instance || !ksynth_instance->voices || channel > 15 || note > 127 || velocity > 127) { + if(!ksynth_instance || !ksynth_instance->voices || channel > 15 || note > (MAX_KEYS - 1) || velocity > 127) { fprintf(stderr, "[KSynth] Error: Invalid parameters for note on.\n"); return; } @@ -150,6 +173,7 @@ void ksynth_note_on(struct KSynth* ksynth_instance, unsigned char channel, unsig if(channel == 9) return; struct Voice* voice = 0; + if(ksynth_instance->polyphony >= ksynth_instance->max_polyphony) { unsigned char min = ksynth_instance->voices[0]->velocity; unsigned long index = 0; @@ -194,6 +218,26 @@ void ksynth_note_on(struct KSynth* ksynth_instance, unsigned char channel, unsig } } +void ksynth_note_off(struct KSynth* ksynth_instance, unsigned char channel, unsigned char note) { + if(!ksynth_instance || channel > 15 || note > (MAX_KEYS - 1)) { + fprintf(stderr, "[KSynth] Error: Invalid parameters for note off.\n"); + return; + } + + if(channel == 9) return; + + struct Voice* voice = 0; + for(unsigned long i = ksynth_instance->polyphony - 1; i < ksynth_instance->polyphony; --i) { + voice = ksynth_instance->voices[i]; + + if((voice->channel == channel && note == voice->noteNumber) && (!voice->killed && !voice->tokill)) { + voice->tokill = 1; + break; + } + } +} + + void ksynth_note_off_all(struct KSynth* ksynth_instance) { if(ksynth_instance != NULL) { for(unsigned long i = 0; i < ksynth_instance->max_polyphony; ++i) { @@ -211,6 +255,27 @@ void ksynth_note_off_all(struct KSynth* ksynth_instance) { } } +void ksynth_cc(struct KSynth* ksynth_instance, unsigned char channel, unsigned char param1, unsigned char param2) { + if(!ksynth_instance || channel > 15) { + fprintf(stderr, "[KSynth] Error: Invalid parameters for CC.\n"); + return; + } + + if(channel == 9) return; + + switch(param1) { + case 10: + ksynth_instance->channels[channel].pan = ((param2 - 64) / 64.0f); + break; + case 64: + // Damper pedal, MUST respond to this at least + ksynth_instance->channels[channel].sustain = param2 > 63 ? 1 : 0; + break; + default: + break; + } +} + int ksynth_get_polyphony(struct KSynth* ksynth_instance) { if(!ksynth_instance) { fprintf(stderr, "[KSynth] Error: Invalid KSynth instance.\n"); @@ -232,39 +297,24 @@ int ksynth_get_max_polyphony(struct KSynth* ksynth_instance) { bool ksynth_set_max_polyphony(struct KSynth* ksynth_instance, unsigned long max_polyphony) { if(!ksynth_instance) return false; - if(max_polyphony < 1) { - max_polyphony = 1; - } else if(max_polyphony >= MAX_POLYPHONY) { - max_polyphony = MAX_POLYPHONY; - } - - ksynth_note_off_all(ksynth_instance); - - for(unsigned long i = 0; i < ksynth_instance->max_polyphony; i++) free(ksynth_instance->voices[i]); + struct Voice** old_ptr = ksynth_instance->voices; + unsigned long old_count = ksynth_instance->max_polyphony; - free(ksynth_instance->voices); + ksynth_instance->max_polyphony = max_polyphony; + struct Voice** new_ptr = int_allocate_voices(ksynth_instance); + if(new_ptr != NULL) { + ksynth_note_off_all(ksynth_instance); - struct Voice** new_voices = malloc(sizeof(struct Voice*) * max_polyphony); - if(!new_voices) { - fprintf(stderr, "[KSynth] Error: Failed to allocate memory for new voices.\n"); - return false; - } + ksynth_instance->voices = new_ptr; + ksynth_instance->max_polyphony = max_polyphony; - for(unsigned long i = 0; i < max_polyphony; i++) { - struct Voice* newVoice = malloc(sizeof(struct Voice)); - if(!newVoice) { - fprintf(stderr, "[KSynth] Error: Failed to allocate memory for new voice.\n"); - return true; - } + int_free_voices(old_ptr, old_count); - newVoice->killed = 1; - newVoice->channel = 0; + return true; } - ksynth_instance->voices = new_voices; - ksynth_instance->max_polyphony = max_polyphony; - - return true; + fprintf(stderr, "[KSynth] Error: Failed to allocate memory for voices.\n"); + return false; } void ksynth_fill_buffer(struct KSynth* ksynth_instance, float* buffer, unsigned int buffer_size) { @@ -280,14 +330,6 @@ void ksynth_fill_buffer(struct KSynth* ksynth_instance, float* buffer, unsigned return; } - // Initialize buffer with zeros - memset(buffer, 0, sizeof(float) * buffer_size); - - if(!ksynth_instance->polyphony) { - ksynth_instance->rendering_time = 0; - return; - } - // post_decay is RELEASE_TIME of the MIDI stream, which you can take by doing (sample_rate / 1000) * RELEASE_TIME unsigned int post_decay = (ksynth_instance->sample_rate / 1000) * RELEASE_TIME; int num_channels = ksynth_instance->num_channel; @@ -297,80 +339,87 @@ void ksynth_fill_buffer(struct KSynth* ksynth_instance, float* buffer, unsigned static struct timespec rendering_time_start, rendering_time_end; clock_gettime(CLOCK_MONOTONIC, &rendering_time_start); - for(unsigned long i = 0; i < ksynth_instance->max_polyphony; i++) { - struct Voice* voice = ksynth_instance->voices[i]; + if(ksynth_instance->polyphony) { + // Initialize buffer with zeros + memset(buffer, 0, sizeof(float) * buffer_size); + + for(unsigned long i = 0; i < ksynth_instance->max_polyphony; i++) { + struct Voice* voice = ksynth_instance->voices[i]; - if(!voice->killed) { - // Voice is alive, let's store the current position and the length of the sample - // for future reference - unsigned int sample_position = voice->sample_position; - unsigned int sample_length = ksynth_instance->samples[voice->noteNumber]->length; + if(!voice->killed) { + // Voice is alive, let's store the current position and the length of the sample + // for future reference + unsigned int sample_length = ksynth_instance->samples[voice->noteNumber]->length; - // CC 10 support - float pan = ((ksynth_instance->channels[voice->channel].pan + 1.0f) / 2.0f) * (M_PI / 2.0f); - float lpan = sinf(pan); - float rpan = cosf(pan); + // CC 10 support + float pan = ((ksynth_instance->channels[voice->channel].pan + 1.0f) / 2.0f) * (M_PI / 2.0f); + float lpan = sinf(pan); + float rpan = cosf(pan); - float decay_time = post_decay * (voice->noteNumber > 64 ? ((64 - (voice->noteNumber - 64)) / 128.0f) : 1.0f); - float nVel = 1.0f; - float logVel = (float)voice->velocity / 127.0f; + float decay_time = post_decay * (voice->noteNumber > 64 ? ((64 - (voice->noteNumber - 64)) / 128.0f) : 1.0f); + float nVel = 1.0f; + float logVel = (float)voice->velocity / 127.0f; #if defined(_MSC_VER) && !defined(__clang__) - velocity = compute_velocity_sse2(logVel, 2.5f, 0.03f); + velocity = compute_velocity_sse2(logVel, 2.5f, 0.03f); #else - velocity = fminf(powf(logVel, 2.5) + 0.03, 1.0); + velocity = fminf(powf(logVel, 2.5) + 0.03, 1.0); #endif - for(unsigned int j = 0; j < buffer_size / num_channels; ++j) { - // This is used to calculate the natural decay of the note, - // which happens n samples before sample_length!! VERY IMPORTANT! - bool natural_decay = sample_length - sample_position < decay_time; - bool sample_done = sample_position >= sample_length; - bool fadeout_done = voice->curfalloff >= decay_time; - - // If we ran out of samples to play, or the fade out limit from voice->tokill - // has been reached, the voice is done and doesn't need to be played anymore. - if(sample_done || fadeout_done) { - voice->killed = 1; - break; + for(unsigned int j = 0; j < buffer_size / num_channels; ++j) { + // This is used to calculate the natural decay of the note, + // which happens n samples before sample_length!! VERY IMPORTANT! + bool natural_decay = sample_length - voice->sample_position < decay_time; + bool sample_done = voice->sample_position >= sample_length; + bool fadeout_done = voice->curfalloff >= decay_time; + + // If we ran out of samples to play, or the fade out limit from voice->tokill + // has been reached, the voice is done and doesn't need to be played anymore. + if(sample_done || fadeout_done) { + voice->killed = 1; + break; + } + + // Get the sample byte you want to play + float sample = ksynth_instance->samples[voice->noteNumber]->audio_data[voice->sample_position]; + + // Check if the voice hasn't been killed yet, if it has + // been marked as tokill, or if it is about to reach the end of the sample (natural_decay) + if(!voice->killed && (voice->tokill || natural_decay)) { + // If the voice isn't sustained using CC 64 and it's time to kill it, or if we reached the natural_decay limit, + // start the curve falloff + if((!ksynth_instance->channels[voice->channel].sustain && voice->tokill) || natural_decay) voice->curfalloff++; + + // As long as curfalloff is minor than decay_time (the amount of samples it takes for the + // sample to reach natural decay, which is "sample_length - (sample_rate / 4)"), keep + // calculating the velocity curve, else set velocity to 0.0f. + nVel = voice->curfalloff < decay_time ? (((float)decay_time - voice->curfalloff) / decay_time) : 0.0f; + } + + for(int c = 0; c < num_channels; ++c) { + // Fill up the buffer. + buffer[j * num_channels + c] += sample * (velocity * nVel) * (num_channels < 2 ? 1.0f : c ? lpan : rpan); + } + + // Move forward in sample by one. + voice->sample_position++; } - // Get the sample byte you want to play - float sample = ksynth_instance->samples[voice->noteNumber]->sample[sample_position]; - - // Check if the voice hasn't been killed yet, if it has - // been marked as tokill, or if it is about to reach the end of the sample (natural_decay) - if(!voice->killed && (voice->tokill || natural_decay)) { - // If the voice isn't sustained using CC 64 and it's time to kill it, or if we reached the natural_decay limit, - // start the curve falloff - if((!ksynth_instance->channels[voice->channel].sustain && voice->tokill) || natural_decay) voice->curfalloff++; - - // As long as curfalloff is minor than decay_time (the amount of samples it takes for the - // sample to reach natural decay, which is "sample_length - (sample_rate / 4)"), keep - // calculating the velocity curve, else set velocity to 0.0f. - nVel = voice->curfalloff < decay_time ? (((float)decay_time - voice->curfalloff) / decay_time) : 0.0f; - } + // If voice is finally done being played, and hasn't been killed, store its position + if(voice->killed) { + // Otherwise, commit homicide and reset it + ksynth_instance->polyphony--; + ksynth_instance->polyphony_per_channel[voice->channel]--; - for(int c = 0; c < num_channels; ++c) { - // Fill up the buffer. - buffer[j * num_channels + c] += sample * (velocity * nVel) * (num_channels < 2 ? 1.0f : c ? lpan : rpan); + voice_reset(voice); + continue; } - - // Move forward in sample by one. - sample_position++; - } - - // If voice is finally done being played, and hasn't been killed, store its position - if(!voice->killed) voice->sample_position = sample_position; - else { - // Otherwise, commit homicide and reset it - ksynth_instance->polyphony--; - ksynth_instance->polyphony_per_channel[voice->channel]--; - - voice_reset(voice); - continue; } } + } else { + for(int i = 0; i < buffer_size; i++) { + buffer[i] = 0.0f; + } } clock_gettime(CLOCK_MONOTONIC, &rendering_time_end); @@ -438,27 +487,8 @@ void ksynth_buffer_free(float* buffer) { void ksynth_free(struct KSynth* ksynth_instance) { if(ksynth_instance != NULL) { - if(ksynth_instance->samples != NULL) { - for(int i = 0; i < 128; i++) { - if(ksynth_instance->samples[i] != NULL) { - free(ksynth_instance->samples[i]->sample); - free(ksynth_instance->samples[i]); - } - } - free(ksynth_instance->samples); - ksynth_instance->samples = NULL; - } - - if(ksynth_instance->voices != NULL) { - for(unsigned long i = 0; i < ksynth_instance->max_polyphony; i++) { - if(ksynth_instance->voices[i] != NULL) { - free(ksynth_instance->voices[i]); - } - } - free(ksynth_instance->voices); - ksynth_instance->voices = NULL; - } - + int_free_samples(ksynth_instance->samples, MAX_KEYS); + int_free_voices(ksynth_instance->voices, ksynth_instance->max_polyphony); free(ksynth_instance); } -} +} \ No newline at end of file diff --git a/src/ksynth.h b/src/ksynth.h index 57f6407..dd796fd 100644 --- a/src/ksynth.h +++ b/src/ksynth.h @@ -4,6 +4,8 @@ extern "C" { #endif +#define _USE_MATH_DEFINES + #include "chan.h" #include "sample.h" #include "voice.h" @@ -16,6 +18,7 @@ extern "C" { #ifdef KSYNTH_MSVC_TESTING // HEEDOOPY BY BREE #include "breewashere.h" +#include #include #else #include @@ -33,9 +36,6 @@ struct KSynth { unsigned char polyphony_per_channel[16]; unsigned long max_polyphony; float rendering_time; -#ifdef ATOMIC_TEST - _Atomic(bool) lock; -#endif struct Chan channels[16]; struct Voice** voices; }; @@ -94,29 +94,6 @@ struct KSynth* ksynth_new(const char* sample_file_path, unsigned int sample_rate */ void ksynth_note_on(struct KSynth* ksynth_instance, unsigned char channel, unsigned char note, unsigned char velocity); -/** - * @~english - * @brief Handles MIDI Control Change messages for a synthesizer. (supporting only pan and sustain for now) - * - * Updates pan and sustain pedal information based on the given MIDI channel and data. - * - * @param ksynth_instance Pointer to the KSynth instance. - * @param channel MIDI channel (0 to 15). - * @param param1 is Continuos Controller ID - * @param param2 is Continuos Controller value - * - * @~japanese - * @brief シンセサイザーの MIDI コントロールチェンジメッセージを処理します。(現在はパンとサスティンのみをサポートしています。) - * - * 与えられた MIDI チャンネルとデータに基づいて、パンとサスティンペダルの情報を更新します。 - * - * @param ksynth_instance KSynth インスタンスへのポインタ - * @param channel MIDI チャンネル(0 から 15) - * @param param1 コントロールチェンジの ID - * @param param2 コントロールチェンジの値 - */ -void ksynth_cc(struct KSynth* ksynth_instance, unsigned char channel, unsigned char param1, unsigned char param2); - /** * @~english * @brief Turns a note off for the specified MIDI channel and note. @@ -147,6 +124,29 @@ void ksynth_note_off(struct KSynth* ksynth_instance, unsigned char channel, unsi */ void ksynth_note_off_all(struct KSynth* ksynth_instance); +/** + * @~english + * @brief Handles MIDI Control Change messages for a synthesizer. (supporting only pan and sustain for now) + * + * Updates pan and sustain pedal information based on the given MIDI channel and data. + * + * @param ksynth_instance Pointer to the KSynth instance. + * @param channel MIDI channel (0 to 15). + * @param param1 is CC ID + * @param param2 is CC value + * + * @~japanese + * @brief シンセサイザーの MIDI コントロールチェンジメッセージを処理します。(現在はパンとサスティンのみをサポートしています。) + * + * 与えられた MIDI チャンネルとデータに基づいて、パンとサスティンペダルの情報を更新します。 + * + * @param ksynth_instance KSynth インスタンスへのポインタ + * @param channel MIDI チャンネル(0 から 15) + * @param param1 コントロールチェンジの ID + * @param param2 コントロールチェンジの値 + */ +void ksynth_cc(struct KSynth* ksynth_instance, unsigned char channel, unsigned char param1, unsigned char param2); + /** * @~english * @brief Gets the current polyphony. @@ -221,7 +221,7 @@ bool ksynth_set_max_polyphony(struct KSynth* ksynth_instance, unsigned long max_ * ただし、バッファ サイズが非常に大きいと、メモリ使用量と遅延が増加し、結果として音声が途切れ途切れになる可能性があります。 * * @param ksynth_instance KSynthインスタンスへのポインタ - * @param buffer バッファへのポインタ + * @param buffer データで埋めたいバッファへのポインタ * @param buffer_size バッファのサイズ */ void ksynth_fill_buffer(struct KSynth* ksynth_instance, float* buffer, unsigned int buffer_size); @@ -235,7 +235,7 @@ void ksynth_fill_buffer(struct KSynth* ksynth_instance, float* buffer, unsigned * this function prepares it for them and gives them a pointer as a return value. * * @param ksynth_instance Pointer to the KSynth instance - * @param buffer_size Size of the buffer (Note: Values are typically between 16 and 65536) + * @param buffer_size Size of the buffer (Note: Values are typically between 32 and 16384) * @return A pointer to the generated buffer on success, NULL on failure. * * @~japanese @@ -245,7 +245,7 @@ void ksynth_fill_buffer(struct KSynth* ksynth_instance, float* buffer, unsigned * この関数は内部的に ksynth_fill_buffer を指しますが、ユーザーにバッファーを管理させる代わりに、この関数はユーザーのためにバッファーを準備し、戻り値としてポインターを与えます。 * * @param ksynth_instance KSynthインスタンスへのポインタ - * @param buffer_size バッファのサイズ(注:通常は16から65536の値です) + * @param buffer_size バッファのサイズ(注:通常は32から16384の値です) * @return 成功した場合は生成されたバッファへのポインタ、失敗した場合はNULL */ float* ksynth_generate_buffer(struct KSynth* ksynth_instance, unsigned int buffer_size); @@ -259,7 +259,7 @@ float* ksynth_generate_buffer(struct KSynth* ksynth_instance, unsigned int buffe * and any longer processing time may result in buffer underrun, leading to audio glitches or gaps. * * @param ksynth_instance Pointer to the KSynth instance - * @return Rendering time as a percentage of the buffer duration (0 to 1.0) Multiply by 100 to treat as a percentage + * @return Rendering time as a percentage of the buffer duration * * @~japanese * @brief レンダリング時間を取得します。 @@ -269,7 +269,7 @@ float* ksynth_generate_buffer(struct KSynth* ksynth_instance, unsigned int buffe * より長い処理時間はバッファのアンダーランを引き起こし、オーディオのグリッチやギャップを引き起こす可能性があります。 * * @param ksynth_instance KSynthインスタンスへのポインタ - * @return バッファの期間の割合としてのレンダリング時間(0から1.0)100を掛けると、パーセンテージとして扱えます + * @return バッファの期間の割合としてのレンダリング時間 */ float ksynth_get_rendering_time(struct KSynth* ksynth_instance); diff --git a/src/sample.h b/src/sample.h index 0154dd2..f5dab8f 100644 --- a/src/sample.h +++ b/src/sample.h @@ -7,7 +7,7 @@ extern "C" { #include struct Sample { - float* sample; + float* audio_data; unsigned int sample_rate; unsigned int length; }; -- 2.43.0