Решение, которое я нашел, это указать громкость для каждого трека в порядке «потомка» и затем не использовать фильтр нормализации.
Я использую этот пример, где я объединяю один и тот же аудиофайл в разных положениях:
ffmpeg -vn -i test.mp3 -i test.mp3 -i test.mp3 -filter_complex "[0]adelay=0|0,volume=3[a];[1]adelay=2000|2000,volume=2[b];[2]adelay=4000|4000,volume=1[c];[a][b][c]amix=inputs=3:dropout_transition=0" -q:a 1 -acodec libmp3lame -y amix-volume.mp3
Подробнее см. это изображение. Первый трек - обычное микширование, второе - с указанными томами; третий - оригинальный трек. Как мы видим, 2-й трек выглядит нормально.
ffmpeg -vn -i test.mp3 -i test.mp3 -i test.mp3 -filter_complex "[0]adelay=0|0[a];[1]adelay=2000|2000[b];[2]adelay=4000|4000[c];[a][b][c]amix=inputs=3:dropout_transition=0" -q:a 1 -acodec libmp3lame -y amix-no-volume.mp3
ffmpeg -vn -i test.mp3 -i test.mp3 -i test.mp3 -filter_complex "[0]adelay=0|0,volume=3[a];[1]adelay=2000|2000,volume=2[b];[2]adelay=4000|4000,volume=1[c];[a][b][c]amix=inputs=3:dropout_transition=0" -q:a 1 -acodec libmp3lame -y amix-volume.mp3
Я не могу понять, почему amix изменяет громкость; так или иначе; Я долгое время рылся за хорошим решением.
Я мог бы полагать, что реализация уровня MVCC просто в DB, с помощью сохранила procs и представления для обработки моих операций данных. Затем Вы могли представить разумный API любому ORM, который был способен к отображению на и от сохраненного procs, и Вы могли позволить DB иметь дело с проблемами целостности данных (так как это - в значительной степени сборка для этого). Если бы Вы пошли этим путем, то Вы могли бы хотеть посмотреть на более чистое решение для Отображения как IBatis или IBatis.net.
Я всегда полагал, что Вы будете использовать дб, включают обновление и удаляют для выставления тех строк в таблицу TableName_Audit.
Это работало бы с ORMs, дало бы Вам Вашу историю и не десятикратно уменьшит избранную производительность на той таблице. Это - хорошая идея, или я пропускаю что-то?
Насколько я знаю платформы ORM собираются хотеть сгенерировать код CRUD для Вас, таким образом, они должны были бы быть явно разработаны для реализации опции MVCC; я не знаю ни о ком, которые делают так из поля.
С точки зрения платформы Объекта CSLA не реализует персистентность для Вас вообще - это просто определяет интерфейс "Data Adapter", который Вы используете для реализации безотносительно персистентности, в которой Вы нуждаетесь. Таким образом, Вы могли настроить генерацию кода (CodeSmith, и т.д.) шаблоны, чтобы автоматически сгенерировать логику CRUD для Ваших объектов CSLA, которые соглашаются с архитектурой базы данных MVCC.
Этот подход работал бы с любой платформой объекта, скорее всего, не только CSLA, но и это будет очень "чистая" реализация в CSLA.
Я разработал базу данных так же (только ВСТАВЛЯЕТ — никакие ОБНОВЛЕНИЯ, нет УДАЛЯЕТ).
Почти все мои Запросы Select были против представлений только текущих строк для каждой таблицы (самое большое количество пересмотра).
Представления были похожи на этот …
SELECT
dbo.tblBook.BookId,
dbo.tblBook.RevisionId,
dbo.tblBook.Title,
dbo.tblBook.AuthorId,
dbo.tblBook.Price,
dbo.tblBook.Deleted
FROM
dbo.tblBook INNER JOIN
(
SELECT
BookId,
MAX(RevisionId) AS RevisionId
FROM
dbo.tblBook
GROUP BY
BookId
) AS CurrentBookRevision ON
dbo.tblBook.BookId = CurrentBookRevision.BookId AND
dbo.tblBook.RevisionId = CurrentBookRevision.RevisionId
WHERE
dbo.tblBook.Deleted = 0
И мои вставки (и обновления и удаляет) были все обработаны хранимыми процедурами (один на таблицу).
Хранимые процедуры были похожи на этот …
ALTER procedure [dbo].[sp_Book_CreateUpdateDelete]
@BookId uniqueidentifier,
@RevisionId bigint,
@Title varchar(256),
@AuthorId uniqueidentifier,
@Price smallmoney,
@Deleted bit
as
insert into tblBook
(
BookId,
RevisionId,
Title,
AuthorId,
Price,
Deleted
)
values
(
@BookId,
@RevisionId,
@Title,
@AuthorId,
@Price,
@Deleted
)
Числа пересмотра были обработаны на транзакцию в … кода Visual Basic
Shared Sub Save(ByVal UserId As Guid, ByVal Explanation As String, ByVal Commands As Collections.Generic.Queue(Of SqlCommand))
Dim Connection As SqlConnection = New SqlConnection(System.Configuration.ConfigurationManager.ConnectionStrings("Connection").ConnectionString)
Connection.Open()
Dim Transaction As SqlTransaction = Connection.BeginTransaction
Try
Dim RevisionId As Integer = Nothing
Dim RevisionCommand As SqlCommand = New SqlCommand("sp_Revision_Create", Connection)
RevisionCommand.CommandType = CommandType.StoredProcedure
RevisionCommand.Parameters.AddWithValue("@RevisionId", 0)
RevisionCommand.Parameters(0).SqlDbType = SqlDbType.BigInt
RevisionCommand.Parameters(0).Direction = ParameterDirection.Output
RevisionCommand.Parameters.AddWithValue("@UserId", UserId)
RevisionCommand.Parameters.AddWithValue("@Explanation", Explanation)
RevisionCommand.Transaction = Transaction
LogDatabaseActivity(RevisionCommand)
If RevisionCommand.ExecuteNonQuery() = 1 Then 'rows inserted
RevisionId = CInt(RevisionCommand.Parameters(0).Value) 'generated key
Else
Throw New Exception("Zero rows affected.")
End If
For Each Command As SqlCommand In Commands
Command.Connection = Connection
Command.Transaction = Transaction
Command.CommandType = CommandType.StoredProcedure
Command.Parameters.AddWithValue("@RevisionId", RevisionId)
LogDatabaseActivity(Command)
If Command.ExecuteNonQuery() < 1 Then 'rows inserted
Throw New Exception("Zero rows affected.")
End If
Next
Transaction.Commit()
Catch ex As Exception
Transaction.Rollback()
Throw New Exception("Rolled back transaction", ex)
Finally
Connection.Close()
End Try
End Sub
Я создал объект для каждой таблицы, каждого с конструкторами, свойствами экземпляра и методами, create-update-delete команды, набор функций средства поиска и IComparable сортирующие функции. Это был огромный объем кода.
Непосредственная Таблица базы данных к объекту VB...
Public Class Book
Implements iComparable
#Region " Constructors "
Private _BookId As Guid
Private _RevisionId As Integer
Private _Title As String
Private _AuthorId As Guid
Private _Price As Decimal
Private _Deleted As Boolean
...
Sub New(ByVal BookRow As DataRow)
Try
_BookId = New Guid(BookRow("BookId").ToString)
_RevisionId = CInt(BookRow("RevisionId"))
_Title = CStr(BookRow("Title"))
_AuthorId = New Guid(BookRow("AuthorId").ToString)
_Price = CDec(BookRow("Price"))
Catch ex As Exception
'TO DO: log exception
Throw New Exception("DataRow does not contain valid Book data.", ex)
End Try
End Sub
#End Region
...
#Region " Create, Update & Delete "
Function Save() As SqlCommand
If _BookId = Guid.Empty Then
_BookId = Guid.NewGuid()
End If
Dim Command As SqlCommand = New SqlCommand("sp_Book_CreateUpdateDelete")
Command.Parameters.AddWithValue("@BookId", _BookId)
Command.Parameters.AddWithValue("@Title", _Title)
Command.Parameters.AddWithValue("@AuthorId", _AuthorId)
Command.Parameters.AddWithValue("@Price", _Price)
Command.Parameters.AddWithValue("@Deleted", _Deleted)
Return Command
End Function
Shared Function Delete(ByVal BookId As Guid) As SqlCommand
Dim Doomed As Book = FindByBookId(BookId)
Doomed.Deleted = True
Return Doomed.Save()
End Function
...
#End Region
...
#Region " Finders "
Shared Function FindByBookId(ByVal BookId As Guid, Optional ByVal TryDeleted As Boolean = False) As Book
Dim Command As SqlCommand
If TryDeleted Then
Command = New SqlCommand("sp_Book_FindByBookIdTryDeleted")
Else
Command = New SqlCommand("sp_Book_FindByBookId")
End If
Command.Parameters.AddWithValue("@BookId", BookId)
If Database.Find(Command).Rows.Count > 0 Then
Return New Book(Database.Find(Command).Rows(0))
Else
Return Nothing
End If
End Function
Такая система сохраняет все прошлые версии каждой строки, но может быть реальной болью для управления.
ПРОФЕССИОНАЛЫ:
НЕДОСТАТКИ:
ЗАКЛЮЧЕНИЕ:
Мне любопытно, если Microsoft Entity Framework может обработать такие проектирования баз данных хорошо.
Jeff и остальная часть, которая команда Переполнения стека должна была заниматься подобными проблемами при разработке Переполнения стека: Прошлые изменения отредактированных вопросов и ответов сохраняются и восстановимы.
Я полагаю, что Jeff заявил, что его команда привыкла Linq для SQL Server MS и SQL.
Интересно, как они обработали эти проблемы.
То, что мы делаем, является просто использованием, нормальный ORM (в спящем режиме) и обрабатывает MVCC с представлениями + вместо триггеров.
Так, существует представление v_emp, которое просто похоже на нормальную таблицу, можно вставить и обновить в него прекрасный, когда Вы делаете это, хотя, триггеры обрабатывают на самом деле вставку корректных данных в базовую таблицу.
Нет.. Я ненавижу этот метод :) Я пошел бы с хранимой процедурой API, как предложил Tim.
Проверьте проект Envers - работы, любезные с приложениями JPA/Hibernate, и в основном делает это для Вас - отслеживает различные версии каждого Объекта в другой таблице и дает Вам подобные SVN возможности ("Дай мне версию Человека, используемого 05.11.2008...")
/Jens