From d792394cf00e4b4742c73c05360e9c5889619986 Mon Sep 17 00:00:00 2001 From: joysuff <338421459@qq.com> Date: Mon, 24 Jun 2024 16:58:23 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E7=AC=AC=E4=B8=80=E6=AC=A1=E4=BD=9C?= =?UTF-8?q?=E4=B8=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 4/main.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 4/main.c diff --git a/4/main.c b/4/main.c new file mode 100644 index 0000000..13cbf77 --- /dev/null +++ b/4/main.c @@ -0,0 +1,54 @@ +#include +#include +/* 1990年1月1日 是星期一 */ +bool is_valid(int year,int month,int day){ + if(year<1990){ + return false; + } + if(month < 1 || month > 12){ + return false; + } + return true; +} +bool is_leap(int year) +{ + return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0); +} +// 获取月份天数 +int getmonthdays(int month,bool leap){ + int days = 0; + int a[]={0,31,28+!!leap,31,30,31,30,31,31,30,31,30,31}; + for(int i=0;i Date: Sat, 29 Jun 2024 20:39:36 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E5=AE=9E=E7=8E=B0key1=E5=BD=95=E9=9F=B3?= =?UTF-8?q?=EF=BC=8Ckey2=E8=B0=83=E5=A4=A7=E9=9F=B3=E9=87=8F=EF=BC=8Ckey3?= =?UTF-8?q?=E8=B0=83=E5=B0=8F=E9=9F=B3=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 4/CMakeLists.txt | 14 ++ 4/control.c | 360 +++++++++++++++++++++++++++++++++++++++++++++++ 4/control.h | 44 ++++++ 4/key.c | 116 +++++++++++++++ 4/record.c | 116 +++++++++++++++ 4/record.h | 20 +++ 6 files changed, 670 insertions(+) create mode 100644 4/CMakeLists.txt create mode 100644 4/control.c create mode 100644 4/control.h create mode 100644 4/key.c create mode 100644 4/record.c create mode 100644 4/record.h diff --git a/4/CMakeLists.txt b/4/CMakeLists.txt new file mode 100644 index 0000000..01d4d4f --- /dev/null +++ b/4/CMakeLists.txt @@ -0,0 +1,14 @@ +cmake_minimum_required(VERSION 3.0.0) +project(voice_assistant VERSION 0.1.0 LANGUAGES C) + +add_library(record STATIC record.c) +add_library(control STATIC control.c) + +add_executable(voice_assistant main.c) + + +add_executable(play play.c) +target_link_libraries(play asound) + +add_executable(key key.c) +target_link_libraries(key gpiod record asound control) \ No newline at end of file diff --git a/4/control.c b/4/control.c new file mode 100644 index 0000000..528f7fb --- /dev/null +++ b/4/control.c @@ -0,0 +1,360 @@ +#include +#include +#include +#include "control.h" + +int set_capture_switch(const char* card, const char* selem, bool enable) { + int err; + snd_mixer_t *handle; + snd_mixer_selem_id_t *sid; + + // 打开混音器 + if ((err = snd_mixer_open(&handle, 0)) < 0) { + fprintf(stderr, "Mixer %s open error: %s\n", card, snd_strerror(err)); + return err; + } + + // 附加控制接口到混音器 + if ((err = snd_mixer_attach(handle, card)) < 0) { + fprintf(stderr, "Mixer attach %s error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 注册混音器 + if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { + fprintf(stderr, "Mixer register error: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 加载混音器元素 + if ((err = snd_mixer_load(handle)) < 0) { + fprintf(stderr, "Mixer %s load error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 分配简单元素ID + snd_mixer_selem_id_alloca(&sid); + + // 设置简单元素的名称 + snd_mixer_selem_id_set_name(sid, selem); + + // 查找简单元素 + snd_mixer_elem_t *elem = snd_mixer_find_selem(handle, sid); + if (!elem) { + fprintf(stderr, "Unable to find simple control '%s',%i\n", selem, 0); + snd_mixer_close(handle); + return -ENOENT; + } + + // 设置采集开关(启用或禁用) + if ((err = snd_mixer_selem_set_capture_switch_all(elem, enable ? 1 : 0)) < 0) { + fprintf(stderr, "Unable to set capture switch: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 关闭混音器 + snd_mixer_close(handle); + + return 0; // 成功 +} + +int set_playback_switch(const char* card, const char* selem, bool enable) { + int err; + snd_mixer_t *handle; + snd_mixer_selem_id_t *sid; + + // 打开混音器 + if ((err = snd_mixer_open(&handle, 0)) < 0) { + fprintf(stderr, "Mixer %s open error: %s\n", card, snd_strerror(err)); + return err; + } + + // 附加控制接口到混音器 + if ((err = snd_mixer_attach(handle, card)) < 0) { + fprintf(stderr, "Mixer attach %s error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 注册混音器 + if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { + fprintf(stderr, "Mixer register error: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 加载混音器元素 + if ((err = snd_mixer_load(handle)) < 0) { + fprintf(stderr, "Mixer %s load error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 分配简单元素ID + snd_mixer_selem_id_alloca(&sid); + + // 设置简单元素的名称 + snd_mixer_selem_id_set_name(sid, selem); + + // 查找简单元素 + snd_mixer_elem_t *elem = snd_mixer_find_selem(handle, sid); + if (!elem) { + fprintf(stderr, "Unable to find simple control '%s',%i\n", selem, 0); + snd_mixer_close(handle); + return -ENOENT; + } + + // 设置回放开关(启用或禁用) + if ((err = snd_mixer_selem_set_playback_switch_all(elem, enable ? 1 : 0)) < 0) { + fprintf(stderr, "Unable to set playback switch: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 关闭混音器 + snd_mixer_close(handle); + + return 0; // 成功 +} + +int get_capture_volume(const char* card, const char* selem) { + int err; + snd_mixer_t *handle; + snd_mixer_selem_id_t *sid; + + // 打开混音器 + if ((err = snd_mixer_open(&handle, 0)) < 0) { + fprintf(stderr, "Mixer %s open error: %s\n", card, snd_strerror(err)); + return err; + } + + // 附加控制接口到混音器 + if ((err = snd_mixer_attach(handle, card)) < 0) { + fprintf(stderr, "Mixer attach %s error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 注册混音器 + if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { + fprintf(stderr, "Mixer register error: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 加载混音器元素 + if ((err = snd_mixer_load(handle)) < 0) { + fprintf(stderr, "Mixer %s load error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 分配简单元素ID + snd_mixer_selem_id_alloca(&sid); + + // 设置简单元素的名称 + snd_mixer_selem_id_set_name(sid, selem); + + // 查找简单元素 + snd_mixer_elem_t *elem = snd_mixer_find_selem(handle, sid); + if (!elem) { + fprintf(stderr, "Unable to find simple control '%s',%i\n", selem, 0); + snd_mixer_close(handle); + return -ENOENT; + } + + // 获取采集通道音量 + long volume = 0; + if ((err = snd_mixer_selem_get_capture_volume(elem, 0, &volume)) < 0) { + fprintf(stderr, "Unable to get capture volume: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 关闭混音器 + snd_mixer_close(handle); + + return volume; // 成功返回音量 +} + +int get_playback_volume(const char* card, const char* selem) { + int err; + snd_mixer_t *handle; + snd_mixer_selem_id_t *sid; + + // 打开混音器 + if ((err = snd_mixer_open(&handle, 0)) < 0) { + fprintf(stderr, "Mixer %s open error: %s\n", card, snd_strerror(err)); + return err; + } + + // 附加控制接口到混音器 + if ((err = snd_mixer_attach(handle, card)) < 0) { + fprintf(stderr, "Mixer attach %s error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 注册混音器 + if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { + fprintf(stderr, "Mixer register error: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 加载混音器元素 + if ((err = snd_mixer_load(handle)) < 0) { + fprintf(stderr, "Mixer %s load error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 分配简单元素ID + snd_mixer_selem_id_alloca(&sid); + + // 设置简单元素的名称 + snd_mixer_selem_id_set_name(sid, selem); + + // 查找简单元素 + snd_mixer_elem_t *elem = snd_mixer_find_selem(handle, sid); + if (!elem) { + fprintf(stderr, "Unable to find simple control '%s',%i\n", selem, 0); + snd_mixer_close(handle); + return -ENOENT; + } + + // 获取回放通道音量 + long volume = 0; + if ((err = snd_mixer_selem_get_playback_volume(elem, 0, &volume)) < 0) { + fprintf(stderr, "Unable to get playback volume: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 关闭混音器 + snd_mixer_close(handle); + + return volume; // 成功返回音量 +} + +int set_capture_volume(const char* card, const char* selem, long volume) { + int err; + snd_mixer_t *handle; + snd_mixer_selem_id_t *sid; + + // 打开混音器 + if ((err = snd_mixer_open(&handle, 0)) < 0) { + fprintf(stderr, "Mixer %s open error: %s\n", card, snd_strerror(err)); + return err; + } + + // 附加控制接口到混音器 + if ((err = snd_mixer_attach(handle, card)) < 0) { + fprintf(stderr, "Mixer attach %s error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 注册混音器 + if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { + fprintf(stderr, "Mixer register error: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 加载混音器元素 + if ((err = snd_mixer_load(handle)) < 0) { + fprintf(stderr, "Mixer %s load error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 分配简单元素ID + snd_mixer_selem_id_alloca(&sid); + + // 设置简单元素的名称 + snd_mixer_selem_id_set_name(sid, selem); + + // 查找简单元素 + snd_mixer_elem_t *elem = snd_mixer_find_selem(handle, sid); + if (!elem) { + fprintf(stderr, "Unable to find simple control '%s',%i\n", selem, 0); + snd_mixer_close(handle); + return -ENOENT; + } + + // 设置采集通道音量 + if ((err = snd_mixer_selem_set_capture_volume_all(elem, volume)) < 0) { + fprintf(stderr, "Unable to set capture volume: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 关闭混音器 + snd_mixer_close(handle); + + return volume; // 成功返回设置的音量 +} + +int set_playback_volume(const char* card, const char* selem, long volume) { + int err; + snd_mixer_t *handle; + snd_mixer_selem_id_t *sid; + + // 打开混音器 + if ((err = snd_mixer_open(&handle, 0)) < 0) { + fprintf(stderr, "Mixer %s open error: %s\n", card, snd_strerror(err)); + return err; + } + + // 附加控制接口到混音器 + if ((err = snd_mixer_attach(handle, card)) < 0) { + fprintf(stderr, "Mixer attach %s error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 注册混音器 + if ((err = snd_mixer_selem_register(handle, NULL, NULL)) < 0) { + fprintf(stderr, "Mixer register error: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 加载混音器元素 + if ((err = snd_mixer_load(handle)) < 0) { + fprintf(stderr, "Mixer %s load error: %s\n", card, snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 分配简单元素ID + snd_mixer_selem_id_alloca(&sid); + + // 设置简单元素的名称 + snd_mixer_selem_id_set_name(sid, selem); + + // 查找简单元素 + snd_mixer_elem_t *elem = snd_mixer_find_selem(handle, sid); + if (!elem) { + fprintf(stderr, "Unable to find simple control '%s',%i\n", selem, 0); + snd_mixer_close(handle); + return -ENOENT; + } + + // 设置回放通道音量 + if ((err = snd_mixer_selem_set_playback_volume_all(elem, volume)) < 0) { + fprintf(stderr, "Unable to set playback volume: %s\n", snd_strerror(err)); + snd_mixer_close(handle); + return err; + } + + // 关闭混音器 + snd_mixer_close(handle); + + return volume; // 成功返回设置的音量 +} diff --git a/4/control.h b/4/control.h new file mode 100644 index 0000000..768e9d0 --- /dev/null +++ b/4/control.h @@ -0,0 +1,44 @@ +#ifndef CONTROL_H +#define CONTROL_H + +#include + +// 设置音频采集开关的函数 +// card: 声卡名称 +// selem: 控制项名称 +// enable: 开关状态 +int set_capture_switch(const char* card, const char* selem, bool enable); + +// 设置音频回放开关的函数 +// card: 声卡名称 +// selem: 控制项名称 +// enable: 开关状态 +int set_playback_switch(const char* card, const char* selem, bool enable); + +// 获取音频采集音量 +// card: 声卡名称 +// selem: 控制项名称 +// 返回值: 当前音量 +int get_capture_volume(const char* card, const char* selem); + +// 获取音频回放通道音量 +// card: 声卡名称 +// selem: 控制项名称 +// 返回值: 当前音量 +int get_playback_volume(const char* card, const char* selem); + +// 设置音频采集音量 +// card: 声卡名称 +// selem: 控制项名称 +// volume: 设置音量 +// 返回值: 成功返回设置后的音量,失败返回错误码 +int set_capture_volume(const char* card, const char* selem, long volume); + +// 设置音频回放通道音量 +// card: 声卡名称 +// selem: 控制项名称 +// volume: 设置音量 +// 返回值: 成功返回设置后的音量,失败返回错误码 +int set_playback_volume(const char* card, const char* selem, long volume); + +#endif // CONTROL_H diff --git a/4/key.c b/4/key.c new file mode 100644 index 0000000..c6903d2 --- /dev/null +++ b/4/key.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include +#include "record.h" +#include "control.h" + +#define GPIO_LINE_KEY1 9 +#define GPIO_LINE_KEY2 7 +#define GPIO_LINE_KEY3 8 + +int main(void) { + struct gpiod_chip *chip; + struct gpiod_line *line_key1, *line_key2, *line_key3; + int value_key1, last_value_key1; + int value_key2, last_value_key2; + int value_key3, last_value_key3; + pid_t record_pid = -1; + + // 打开GPIO芯片 + chip = gpiod_chip_open_by_label("GPIOF"); + if (!chip) { + perror("打开GPIO芯片失败"); + return 1; + } + + // 获取GPIO线 + line_key1 = gpiod_chip_get_line(chip, GPIO_LINE_KEY1); + line_key2 = gpiod_chip_get_line(chip, GPIO_LINE_KEY2); + line_key3 = gpiod_chip_get_line(chip, GPIO_LINE_KEY3); + if (!line_key1 || !line_key2 || !line_key3) { + perror("获取GPIO线失败"); + gpiod_chip_close(chip); + return 1; + } + + // 将GPIO线设置为输入模式 + if (gpiod_line_request_input(line_key1, "key1") || + gpiod_line_request_input(line_key2, "key2") || + gpiod_line_request_input(line_key3, "key3")) { + perror("请求将GPIO线设置为输入模式失败"); + gpiod_chip_close(chip); + return 1; + } + + // 获取初始的GPIO线值 + last_value_key1 = gpiod_line_get_value(line_key1); + last_value_key2 = gpiod_line_get_value(line_key2); + last_value_key3 = gpiod_line_get_value(line_key3); + + // 无限循环检测GPIO线值的变化 + while (1) { + // 获取当前的GPIO线值 + value_key1 = gpiod_line_get_value(line_key1); + value_key2 = gpiod_line_get_value(line_key2); + value_key3 = gpiod_line_get_value(line_key3); + + // 检测key1的变化 + if (value_key1 != last_value_key1) { + if (value_key1 == 0) { + printf("key1 pressed\n"); + // 启动record进程 + record_pid = fork(); + if (record_pid == 0) { + signal(SIGTERM, handle_sigterm); + start_recording("hw:0,1", "output.pcm", SND_PCM_FORMAT_S16_LE, 2, 44100); + exit(0); + } + } else { + if (record_pid > 0) { + stop_recording(); + kill(record_pid, SIGTERM); + waitpid(record_pid, NULL, 0); + record_pid = -1; + } + } + last_value_key1 = value_key1; + } + + // 检测key2的变化 + if (value_key2 != last_value_key2) { + if (value_key2 == 0) { + printf("key2 pressed\n"); + } else { + long volume = get_playback_volume("hw:0", "Analog"); + volume += 5; + set_playback_volume("hw:0", "Analog", volume); + printf("Volume increased to %ld\n", volume); + } + last_value_key2 = value_key2; + } + + // 检测key3的变化 + if (value_key3 != last_value_key3) { + if (value_key3 == 0) { + printf("key3 pressed\n"); + } else { + long volume = get_playback_volume("hw:0", "Analog"); + volume -= 5; + set_playback_volume("hw:0", "Analog", volume); + printf("Volume decreased to %ld\n", volume); + } + last_value_key3 = value_key3; + } + + // 延时100毫秒,防止检测过于频繁 + usleep(100000); + } + + // 关闭GPIO芯片 + gpiod_chip_close(chip); + return 0; +} diff --git a/4/record.c b/4/record.c new file mode 100644 index 0000000..398e1b5 --- /dev/null +++ b/4/record.c @@ -0,0 +1,116 @@ +#include "record.h" + +snd_pcm_t *capture = NULL; +char *buffer = NULL; +FILE *pcm_file = NULL; +volatile sig_atomic_t keep_recording = 1; + +void handle_sigterm(int sig) { + keep_recording = 0; +} + +// 开始录音 +snd_pcm_t* record_start(const char* name, snd_pcm_format_t format, unsigned int channel, unsigned int rate, snd_pcm_uframes_t* period) { + snd_pcm_t *capture; + snd_pcm_hw_params_t *params; + int err; + int dir; + + if ((err = snd_pcm_open(&capture, name, SND_PCM_STREAM_CAPTURE, 0)) < 0) { + fprintf(stderr, "Error opening PCM device %s: %s\n", name, snd_strerror(err)); + return NULL; + } + + snd_pcm_hw_params_alloca(¶ms); + snd_pcm_hw_params_any(capture, params); + + if ((err = snd_pcm_hw_params_set_access(capture, params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) { + fprintf(stderr, "Error setting access: %s\n", snd_strerror(err)); + snd_pcm_close(capture); + return NULL; + } + if ((err = snd_pcm_hw_params_set_format(capture, params, format)) < 0) { + fprintf(stderr, "Error setting format: %s\n", snd_strerror(err)); + snd_pcm_close(capture); + return NULL; + } + if ((err = snd_pcm_hw_params_set_channels(capture, params, channel)) < 0) { + fprintf(stderr, "Error setting channels: %s\n", snd_strerror(err)); + snd_pcm_close(capture); + return NULL; + } + if ((err = snd_pcm_hw_params_set_rate_near(capture, params, &rate, &dir)) < 0) { + fprintf(stderr, "Error setting rate: %s\n", snd_strerror(err)); + snd_pcm_close(capture); + return NULL; + } + printf("sample rate: %d Hz\n", rate); + + if ((err = snd_pcm_hw_params(capture, params)) < 0) { + fprintf(stderr, "Error setting HW params: %s\n", snd_strerror(err)); + snd_pcm_close(capture); + return NULL; + } + + snd_pcm_hw_params_get_period_size(params, period, &dir); + + return capture; +} + +void start_recording(const char *pcm_device, const char *output_file, snd_pcm_format_t format, unsigned int channels, unsigned int rate) { + snd_pcm_uframes_t period; + int err; + + capture = record_start(pcm_device, format, channels, rate, &period); + if (!capture) { + exit(1); + } + + printf("period: %lu frames\n", period); + + buffer = (char *) malloc(snd_pcm_frames_to_bytes(capture, period)); + if (!buffer) { + perror("malloc"); + snd_pcm_close(capture); + exit(1); + } + + pcm_file = fopen(output_file, "wb"); + if (!pcm_file) { + perror("Error opening output file"); + free(buffer); + snd_pcm_close(capture); + exit(1); + } + + printf("Recording... Release the button to stop.\n"); + while (keep_recording) { + snd_pcm_sframes_t frames = snd_pcm_readi(capture, buffer, period); + if (frames < 0) { + fprintf(stderr, "Error from read: %s\n", snd_strerror(frames)); + if (frames == -EPIPE) { + snd_pcm_prepare(capture); + } + } + + fwrite(buffer, snd_pcm_frames_to_bytes(capture, frames), 1, pcm_file); + } +} + +void stop_recording() { + // 清理资源 + if (buffer) { + free(buffer); + buffer = NULL; + } + if (pcm_file) { + fclose(pcm_file); + pcm_file = NULL; + } + if (capture) { + snd_pcm_drain(capture); + snd_pcm_close(capture); + capture = NULL; + } + printf("Recording stopped.\n"); +} diff --git a/4/record.h b/4/record.h new file mode 100644 index 0000000..7d732c8 --- /dev/null +++ b/4/record.h @@ -0,0 +1,20 @@ +#ifndef RECORD_H +#define RECORD_H + +#include +#include +#include +#include +#include + +extern snd_pcm_t *capture; +extern char *buffer; +extern FILE *pcm_file; +extern volatile sig_atomic_t keep_recording; + +void handle_sigterm(int sig); +snd_pcm_t* record_start(const char* name, snd_pcm_format_t format, unsigned int channel, unsigned int rate, snd_pcm_uframes_t* period); +void start_recording(const char *pcm_device, const char *output_file, snd_pcm_format_t format, unsigned int channels, unsigned int rate); +void stop_recording(); + +#endif // RECORD_H -- Gitee