NDK JNI 变声器实现
Android NDK 导入 C库的开发流程学习;通过使用fmod的C库,实现变声器功能。

导入库文件
1)复制fmod的C库到cpp目录下
2)复制fmod的so库到jniLibs目录下
3)复制fmod的jar库到libs目录下
4)将声音文件复制到assets目录下
fmod库文件资源:https://wwgl.lanzout.com/ilXHP0pn7f4f

打开CMakeLists.txt导入fmod库文件
cmake_minimum_required(VERSION 3.10.2) # 最低支持的CMake版本project("whine")# TODO 第一步 导入头文件(fmod库)
include_directories("inc")# 批量导入所有文件
file(GLOB allCPP *.c *.h *.cpp)add_library(native-lib # 打包出来库的名称 libnative-lib.soSHARED # 动态库${allCPP} # 添加所有库文件
)# TODO 第二步 导入库文件(fmod库)
# ${CMAKE_CXX_FLAGS} 原先的CMake环境 +
# -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI} 加上新的fmod库的路径
# CMAKE_SOURCE_DIR == CMakeLists.txt所在的路径
# /../ 回退到cpp目录
# jniLibs/ 进入jniLibs目录
# ${CMAKE_ANDROID_ARCH_ABI} 使用当前手机CPU系统结构对应的库 如:arm64-v8a
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -L${CMAKE_SOURCE_DIR}/../jniLibs/${CMAKE_ANDROID_ARCH_ABI}")find_library(log-liblog # 自动寻找log库
)# TODO 第三步 链接具体的库,到 libnative-lib.so总库
target_link_libraries(native-lib${log-lib}fmod # 具体的库 链接到 libnative-lib.so里面去fmodL # 具体的库 链接到 libnative-lib.so里面去
)打开build.gradle,指定CPU架构和依赖fmod的jar包
defaultConfig {// TODO 第四步externalNativeBuild {cmake {// cppFlags "" // 默认五大平台// 指定CPU架构,Cmake的本地库, 例如:native-lib ---> arm64-v8aabiFilters "arm64-v8a"}}// TODO 第五步// 指定CPU架构,打入APK lib/CPU平台ndk {abiFilters "arm64-v8a"}
}dependencies {// TODO 第六步:依赖fmod的jar包implementation files("libs\\fmod.jar");
}准备工作完成,开始编写Activity代码
1)定义变声模式
/*** 定义变声模式* 0 正常; 1 萝莉; 2 大叔; 3 惊悚; 4 搞怪; 5 回声;*/
private static final int MODE_NORMAL = 0;
private static final int MODE_LUOLI = 1;
private static final int MODE_DASHU = 2;
private static final int MODE_JINGSONG = 3;
private static final int MODE_GAOGUAI = 4;
private static final int MODE_KONGLING = 5;2)加载编译后的lib库
static {System.loadLibrary("native-lib");
}3)初始化fmod.jar库,并在页面关闭的时候释放
@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);FMOD.init(this);
}@Override
protected void onDestroy() {super.onDestroy();FMOD.close();
}4)编写变声native层方法和变声结束后提供native调用的方法
public native void voiceChangeNative(int modeNormal, String path);private void playerEnd(String msg) {isPlaying = false;runOnUiThread(() -> Toast.makeText(this, msg, Toast.LENGTH_SHORT).show());
}5)Activity完整代码
package com.whine;import androidx.appcompat.app.AppCompatActivity;import android.os.Bundle;
import android.view.View;
import android.widget.Toast;import org.fmod.FMOD;/*** TODO Android NDK 导入 C库,开发流程 之 变声器*/
public class MainActivity extends AppCompatActivity {/*** 定义变声模式* 0 正常; 1 萝莉; 2 大叔; 3 惊悚; 4 搞怪; 5 回声;*/private static final int MODE_NORMAL = 0;private static final int MODE_LUOLI = 1;private static final int MODE_DASHU = 2;private static final int MODE_JINGSONG = 3;private static final int MODE_GAOGUAI = 4;private static final int MODE_KONGLING = 5;/*** 声音路径*/private String soundPath;private boolean isPlaying = false;static {System.loadLibrary("native-lib");}@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// TODO 第七步 初始化FMOD库FMOD.init(this);initData();}private void initData() {soundPath = "file:///android_asset/sound.mp3";}// 点击事件public void onFix(View view) {switch (view.getId()) {case R.id.btn_normal:voiceChange(MODE_NORMAL, soundPath); // 真实开发中,必须子线程 JNI线程(很多坑)break;case R.id.btn_luoli:voiceChange(MODE_LUOLI, soundPath);break;case R.id.btn_dashu:voiceChange(MODE_DASHU, soundPath);break;case R.id.btn_jingsong:voiceChange(MODE_JINGSONG, soundPath);break;case R.id.btn_gaoguai:voiceChange(MODE_GAOGUAI, soundPath);break;case R.id.btn_kongling:voiceChange(MODE_KONGLING, soundPath);break;}}@Overrideprotected void onDestroy() {super.onDestroy();FMOD.close();}private void voiceChange(int modeNormal, String path) {if (isPlaying) {Toast.makeText(this, "正在播放,请稍后!", Toast.LENGTH_SHORT).show();return;}isPlaying = true;new Thread(() -> voiceChangeNative(modeNormal, path)).start();}/*** 给C++(native)层调用的函数* JNI 调用 Java函数的时候,忽略掉 私有、公开 等** @param msg*/private void playerEnd(String msg) {isPlaying = false;runOnUiThread(() -> Toast.makeText(this, msg, Toast.LENGTH_SHORT).show());}/*** 变声native层方法** @param modeNormal* @param path*/public native void voiceChangeNative(int modeNormal, String path);
}编写native层头文件(声明文件)
1)导入需要使用到的头文件
#include <jni.h>
#include <fmod.hpp>
#include <string>
#include <android/log.h>2)定义log宏
#define TAG "NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)3)定义变声模式宏
#undef com_whine_MainActivity_MODE_NORMAL
#define com_whine_MainActivity_MODE_NORMAL 0L
#undef com_whine_MainActivity_MODE_LUOLI
#define com_whine_MainActivity_MODE_LUOLI 1L
#undef com_whine_MainActivity_MODE_DASHU
#define com_whine_MainActivity_MODE_DASHU 2L
#undef com_whine_MainActivity_MODE_JINGSONG
#define com_whine_MainActivity_MODE_JINGSONG 3L
#undef com_whine_MainActivity_MODE_GAOGUAI
#define com_whine_MainActivity_MODE_GAOGUAI 4L
#undef com_whine_MainActivity_MODE_KONGLING
#define com_whine_MainActivity_MODE_KONGLING 5L4)头文件完整代码
// TODO 第八步 编写头文件(声明文件)
#include <jni.h>
// 导入FMOD的头文件
#include <fmod.hpp>
#include <string>
// 导入log库
#include <android/log.h>extern "C" {// log宏
#define TAG "NDK"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)// 创建变声模式宏
#undef com_whine_MainActivity_MODE_NORMAL
#define com_whine_MainActivity_MODE_NORMAL 0L
#undef com_whine_MainActivity_MODE_LUOLI
#define com_whine_MainActivity_MODE_LUOLI 1L
#undef com_whine_MainActivity_MODE_DASHU
#define com_whine_MainActivity_MODE_DASHU 2L
#undef com_whine_MainActivity_MODE_JINGSONG
#define com_whine_MainActivity_MODE_JINGSONG 3L
#undef com_whine_MainActivity_MODE_GAOGUAI
#define com_whine_MainActivity_MODE_GAOGUAI 4L
#undef com_whine_MainActivity_MODE_KONGLING
#define com_whine_MainActivity_MODE_KONGLING 5L
JNIEXPORT void JNICALL Java_com_whine_MainActivity_voiceChangeNative(JNIEnv *, jobject, jint, jstring);
}编写native层实现文件
1)转换Java层传递的声音路径jstring -> char *
const char *pathChar = env->GetStringUTFChars(path, NULL);2)定义和初始化音效引擎系统
// 定义音效引擎系统 指针
System *system = 0;
// 声音
Sound *sound = 0;
// 音轨
Channel *channel = 0;
// 数字信号处理 指针
DSP *dsp = 0;
// 创建系统
System_Create(&system);
// 初始化系统 参数1:最大音轨数,参数2:系统初始化标记,参数3:额外数据
system->init(32, FMOD_INIT_NORMAL, 0);
// 创建声音 参数1:路径, 参数2:声音初始化标记, 参数3:额外数据, 参数4:声音指针
system->createSound(pathChar, FMOD_DEFAULT, 0, &sound);
// 播放声音,并赋值通道 参数1:声音,参数2:分组音轨,参数3:控制,参数4:通道
system->playSound(sound, 0, false, &channel);3)判断变声模式,调节音效
switch (mode_normal) {case com_whine_MainActivity_MODE_NORMAL:resultChar = "原生,播放完毕!";break;case com_whine_MainActivity_MODE_LUOLI:resultChar = "萝莉,播放完毕!";// 音调高 -- 萝莉 2.0// 1.创建DSP类型的Pitch 音调条件system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节2.0dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 3.0f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;case com_whine_MainActivity_MODE_DASHU:resultChar = "大叔,播放完毕!";// 音调低 -- 大叔 0.7// 1.创建DSP类型的Pitch 音调条件system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节0.7dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.7f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;case com_whine_MainActivity_MODE_GAOGUAI:resultChar = "搞怪小黄人,播放完毕!";// 小黄人声音 频率快// 1.从音轨拿 当前 频率float frequency;channel->getFrequency(&frequency);// 2.加快频率加快 小黄人的声音channel->setFrequency(frequency * 1.5f);break;case com_whine_MainActivity_MODE_JINGSONG:resultChar = "惊悚,播放完毕!";// 惊悚音效:特点:很多声音的拼接// TODO 1.音调低// 音调低 -- 大叔 0.7// 1.创建DSP类型的Pitchsystem->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节0.7dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.7f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);// TODO 2.回声// 回音 ECHO// 1.创建DSP类型的ECHOsystem->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);// 2.设置回音 延时 to 5000. Default = 500.dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 200);// 3.设置回音 衰减度 Default = 50 0 完全衰减了dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 4.添加音效进去 第二个音轨channel->addDSP(1, dsp);// TODO 3.颤抖// Tremolo 颤抖音// 1.创建DSP类型的Tremolosystem->createDSPByType(FMOD_DSP_TYPE_TREMOLO, &dsp);// 2.设置颤抖 正常 5,非常颤抖 20dsp->setParameterFloat(FMOD_DSP_TREMOLO_FREQUENCY, 20);// 3.dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW, 0.8f);// 4.第三个音轨channel->addDSP(2, dsp);break;case com_whine_MainActivity_MODE_KONGLING:resultChar = "空灵,播放完毕!";// 回音 ECHO// 1.创建DSP类型的ECHO 音调条件system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);// 2.设置回音 延时 to 5000. Default = 500.dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 200);// 3.设置回音 衰减度 Default = 50 0 完全衰减了dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 4.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;
}4)检测声音是否播放完毕
bool isPlay = true;
while (isPlay) {// 如果真的播放完成了,音轨是知道的,内部会修改isPlayer=falsechannel->isPlaying(&isPlay);// 休眠100mSusleep(100 * 1000);
}5)回收C层资源
sound->release();
system->close();
system->release();
env->ReleaseStringUTFChars(path, pathChar);6)播放完毕,通知java层(调用Java层的播放完成方法)
jclass jClazz = env->GetObjectClass(thiz);
jmethodID methodId = env->GetMethodID(jClazz, "playerEnd", "(Ljava/lang/String;)V");
jstring value = env->NewStringUTF(resultChar);
env->CallVoidMethod(thiz, methodId, value);7)实现文件完整代码
#include <unistd.h>
#include "whine.h"using namespace FMOD; // fmod的命名空间extern "C"
JNIEXPORT void JNICALL
Java_com_whine_MainActivity_voiceChangeNative(JNIEnv *env, jobject thiz, jint mode_normal,jstring path) {// 定义一个结果字符串返回char *resultChar = "播放完毕!";// 转换路径jstring -> char *const char *pathChar = env->GetStringUTFChars(path, NULL);// 定义音效引擎系统 指针System *system = 0;// 声音Sound *sound = 0;// 音轨Channel *channel = 0;// 数字信号处理 指针DSP *dsp = 0;// 创建系统System_Create(&system);// 初始化系统 参数1:最大音轨数,参数2:系统初始化标记,参数3:额外数据system->init(32, FMOD_INIT_NORMAL, 0);// 创建声音 参数1:路径, 参数2:声音初始化标记, 参数3:额外数据, 参数4:声音指针system->createSound(pathChar, FMOD_DEFAULT, 0, &sound);// 播放声音,并赋值通道 参数1:声音,参数2:分组音轨,参数3:控制,参数4:通道system->playSound(sound, 0, false, &channel);LOGI("init done");// 判断模式,增加特效switch (mode_normal) {case com_whine_MainActivity_MODE_NORMAL:resultChar = "原生,播放完毕!";break;case com_whine_MainActivity_MODE_LUOLI:resultChar = "萝莉,播放完毕!";// 音调高 -- 萝莉 2.0// 1.创建DSP类型的Pitch 音调条件system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节2.0dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 3.0f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;case com_whine_MainActivity_MODE_DASHU:resultChar = "大叔,播放完毕!";// 音调低 -- 大叔 0.7// 1.创建DSP类型的Pitch 音调条件system->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节0.7dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.7f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;case com_whine_MainActivity_MODE_GAOGUAI:resultChar = "搞怪小黄人,播放完毕!";// 小黄人声音 频率快// 1.从音轨拿 当前 频率float frequency;channel->getFrequency(&frequency);// 2.加快频率加快 小黄人的声音channel->setFrequency(frequency * 1.5f);break;case com_whine_MainActivity_MODE_JINGSONG:resultChar = "惊悚,播放完毕!";// 惊悚音效:特点:很多声音的拼接// TODO 1.音调低// 音调低 -- 大叔 0.7// 1.创建DSP类型的Pitchsystem->createDSPByType(FMOD_DSP_TYPE_PITCHSHIFT, &dsp);// 2.设置Pitch音调调节0.7dsp->setParameterFloat(FMOD_DSP_PITCHSHIFT_PITCH, 0.7f);// 3.添加音效进去 第一个音轨channel->addDSP(0, dsp);// TODO 2.回声// 回音 ECHO// 1.创建DSP类型的ECHOsystem->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);// 2.设置回音 延时 to 5000. Default = 500.dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 200);// 3.设置回音 衰减度 Default = 50 0 完全衰减了dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 4.添加音效进去 第二个音轨channel->addDSP(1, dsp);// TODO 3.颤抖// Tremolo 颤抖音// 1.创建DSP类型的Tremolosystem->createDSPByType(FMOD_DSP_TYPE_TREMOLO, &dsp);// 2.设置颤抖 正常 5,非常颤抖 20dsp->setParameterFloat(FMOD_DSP_TREMOLO_FREQUENCY, 20);// 3.dsp->setParameterFloat(FMOD_DSP_TREMOLO_SKEW, 0.8f);// 4.第三个音轨channel->addDSP(2, dsp);break;case com_whine_MainActivity_MODE_KONGLING:resultChar = "空灵,播放完毕!";// 回音 ECHO// 1.创建DSP类型的ECHO 音调条件system->createDSPByType(FMOD_DSP_TYPE_ECHO, &dsp);// 2.设置回音 延时 to 5000. Default = 500.dsp->setParameterFloat(FMOD_DSP_ECHO_DELAY, 200);// 3.设置回音 衰减度 Default = 50 0 完全衰减了dsp->setParameterFloat(FMOD_DSP_ECHO_FEEDBACK, 10);// 4.添加音效进去 第一个音轨channel->addDSP(0, dsp);break;}// 等待播放完毕 再回收bool isPlay = true;while (isPlay) {// 如果真的播放完成了,音轨是知道的,内部会修改isPlayer=falsechannel->isPlaying(&isPlay);// 休眠100mSusleep(100 * 1000);}LOGI("play done");// 回收资源sound->release();system->close();system->release();env->ReleaseStringUTFChars(path, pathChar);// 通知java层jclass jClazz = env->GetObjectClass(thiz);jmethodID methodId = env->GetMethodID(jClazz, "playerEnd", "(Ljava/lang/String;)V");jstring value = env->NewStringUTF(resultChar);env->CallVoidMethod(thiz, methodId, value);
}
相关文章:
NDK JNI 变声器实现
Android NDK 导入 C库的开发流程学习;通过使用fmod的C库,实现变声器功能。导入库文件1)复制fmod的C库到cpp目录下2)复制fmod的so库到jniLibs目录下3)复制fmod的jar库到libs目录下4)将声音文件复制到assets目…...
VMLogin防关联指纹浏览器的主帐号和子账号区别介绍
VMLogin主账户管理子账户,主要用于团队协作,分账户登录使用,主账户相当于老板,子账户相当于员工。 主账户创建并管理子账户; 主账户可以修改子账户的密码; 主账户可以设置子账户是否有创建配置文件权限&a…...
Apache DolphinScheduler GitHub Star 突破 10000!
点击蓝字 关注我们今天,Apache DolphinScheduler GitHub Star 突破 10000,项目迎来一个重要里程碑。这表明 Apache DolphinScheduler 已经在全球的开发者和用户中获得了广泛的认可和使用。DolphinScheduler 旨在解决公司日常运营中的大数据处理工作流调度…...
程序员中的女性力量——做不被定义的自己
她是office lady,亦是程序媛,程序员界的靓丽色彩,不可或缺。 “只有那些疯狂到以为自己能够改变世界的人——才能真正改变世界。” 女性该如何定义自己?程序媛怎么发挥自己最大的价值。 争取自己做选择,经济和思想都独…...
pb中Datawindow中每页打印固定行
Datawindow中每页打印固定行 第一步: 增加一个计算列,此计算列必须放在Detail段,Expression中输入:ceiling(getrow()/20),这里20还可以用全局函数取代,这样可以允许用户任意设置每页打印多少行。 第二步: 定义分组,选择菜单Rows->Create Group...按计算列字段…...
华为OD机试 - 内存池(C 语言解题)【独家】
最近更新的博客 华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧文章目录 使用说明本期题目:内存池题…...
SaaS简介
SaaS 简介 SaaS被认为是云计算的一部分,其他包括基础设施即服务(IaaS)、平台即服务(PaaS)、桌面即服务(DaaS)、托管软件即服务(MSaaS)、移动后端即服务(MBaaS)、数据中心即服务(DCaaS)、集成平台即服务(iPaaS)和信息技术管理即服务(ITMaaS) SaaS应用程序通常由web浏…...
unity 实现使用三张图片来表达车速,通过传值达到车速
//速度 public Image SpeedNums_Unit; public Image SpeedNums_Ten; //public Image SpeedNums_Hundred; //kw public Image MileageNums_Unit; public Image MileageNums_Ten; /// /// 仪表速度UI /// private void SpeedUI(string speedStr) {if (SpeedNums_Unit == null) …...
程序员看过都说好的资源网站,你值得拥有。
程序员必备的相关资源网站一.技术社区1.GitHub2.Gitee(码云)3.稀土掘金4.OSCHINA开源中国5.CSDN6.博客园7.SegmentFault(思否)8.Stack Overflow9.Golang中文社区10.ChinaUnix11.51CTO12.Ruby China二.技术教程1.Devdocs2.码农教程…...
【MySQL高级篇】第03章 用户与权限管理
第03章 用户与权限管理 1. 用户管理 1.1 登录MySQL服务器 启动MySQL服务后,可以通过mysql命令来登录MySQL服务器,命令如下: mysql –h hostname|hostIP –P port –u username –p DatabaseName –e "SQL语句"-h参数后面接主机…...
MySQL的分库分表?通俗易懂
1- 为什么要分库分表 如果一个网站业务快速发展,那这个网站流量也会增加,数据的压力也会随之而来,比如电商系统来说双十一大促对订单数据压力很大,Tps十几万并发量,如果传统的架构(一主多从)&a…...
elasticsearch 查询语法
match_all 查询所有 GET test/_search {"query": {"match_all": {}} }match 单字段匹配查询 GET test/_search {"query":{"match":{"name":"zhangsan"}} }multi_match 多字段匹配查询 GET test/_search {"…...
深入剖析MVC模型与三层架构
MVC(Model-View-Controller)模型和三层架构都是常见的软件架构模式,用于实现大型应用程序和软件系统。下面是对它们的深入剖析: MVC模型 MVC模型是一种将应用程序分成三个主要组件的软件架构模式,分别是模型…...
使用 Wall 搭建个人照片墙和视频墙
下载 Github:https://github.com/super-tongyao/wall 国内仓库(不推荐,只做加速访问,无编译包和发行版,以github仓库为准):https://gitee.com/Super_TongYao/wall 推荐github仓库,下载最新版…...
03_Linux压缩解压,用户用户组,文件权限
目录 Linux下常用的压缩格式 gzip 压缩工具 gzip 对文件夹进行压缩 bzip2 压缩工具 tar打包工具 对.tar.bz2 进行压缩和解压缩 对.tar.gz 进行压缩和解压缩 rar格式 zip格式 Linux用户 Linux用户组 创建用户和用户组 Linux文件权限 Linux文件权限修改 Linux下常用…...
硬盘分区数据恢复?这些方法助您解忧
案例:分区把电脑文件丢了,数据还能恢复吗? “急急急!!!本人电脑小白,在使用磁盘管理合并E、F分区的时候,不小心把D分区给删除了,D分区里面存放了很多重要的数据与文件&a…...
高校竞赛信息管理系统
摘要随着当今社会的发展,时代的进步,各行各业也在发生着变化,比如高校竞赛信息管理这一方面,利用网络已经逐步进入人们的生活。传统的高校竞赛信息管理,都是学生去学校查看竞赛信息然后再进行报名,这种传统…...
还是要学好数学啊
有一个无穷大的二维网格图,一开始所有格子都未染色。给你一个正整数 n ,表示你需要执行以下步骤 n 分钟:第一分钟,将任一格子染成蓝色。之后的每一分钟,将与蓝色格子相邻的 所有 未染色格子染成蓝色。下图分别是 1、2、…...
ActiveMQ反序列化漏洞原理+复现
ActiveMQ反序列化漏洞 ActiveMQ ActiveMQ是开源消息总线,消息中间件 工作原理 通过使用消息队列,实现服务的异步处理,主要目的是减少请求响应时间和解耦合。 消息队列,服务器A将客户发起的请求放入服务器B的消息队列中&#…...
layui框架实战案例(19):layui-table模块表格综合应用(筛选查询、导入导出、群发短信、一键审核、照片展示、隐私加密)
系列文章目录 layui动态表格翻页和搜索的代码分析layui框架实战案例(3):layui上传错误请求上传接口出现异常解决方案layui框架实战案例(9):layPage 静态数据分页组件layui框架实战案例(10):短信验证码60秒倒计时layui框架实战案例(11)&#…...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路
进入2025年以来,尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断,但全球市场热度依然高涨,入局者持续增加。 以国内市场为例,天眼查专业版数据显示,截至5月底,我国现存在业、存续状态的机器人相关企…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
【分享】推荐一些办公小工具
1、PDF 在线转换 https://smallpdf.com/cn/pdf-tools 推荐理由:大部分的转换软件需要收费,要么功能不齐全,而开会员又用不了几次浪费钱,借用别人的又不安全。 这个网站它不需要登录或下载安装。而且提供的免费功能就能满足日常…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
[论文阅读]TrustRAG: Enhancing Robustness and Trustworthiness in RAG
TrustRAG: Enhancing Robustness and Trustworthiness in RAG [2501.00879] TrustRAG: Enhancing Robustness and Trustworthiness in Retrieval-Augmented Generation 代码:HuichiZhou/TrustRAG: Code for "TrustRAG: Enhancing Robustness and Trustworthin…...
